Page MenuHomeFreeBSD

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/lib/libc/aarch64/gen/flt_rounds.c b/lib/libc/aarch64/gen/flt_rounds.c
index 7d5259a1a3bc..b62536aafaf8 100644
--- a/lib/libc/aarch64/gen/flt_rounds.c
+++ b/lib/libc/aarch64/gen/flt_rounds.c
@@ -1,47 +1,46 @@
/*-
* Copyright (c) 2012 Ian Lepore <freebsd@damnhippie.dyndns.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <fenv.h>
#include <float.h>
static int map[] = {
1, /* round to nearest */
2, /* round to positive infinity */
3, /* round to negative infinity */
0 /* round to zero */
};
int
__flt_rounds(void)
{
uint64_t fpcr;
asm volatile("mrs %0, fpcr" : "=r" (fpcr));
return map[(fpcr >> 22) & 3];
}
diff --git a/lib/libc/aarch64/gen/fpgetmask.c b/lib/libc/aarch64/gen/fpgetmask.c
index 7bc56a9d75be..b6f398d202f5 100644
--- a/lib/libc/aarch64/gen/fpgetmask.c
+++ b/lib/libc/aarch64/gen/fpgetmask.c
@@ -1,44 +1,43 @@
/*-
* Copyright (c) 2015 The FreeBSD Foundation
*
* This software was developed by Andrew Turner under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
fp_except_t
fpgetmask(void)
{
uint64_t mask;
/* Read the current mask */
__asm __volatile("mrs %0, fpcr" : "=&r"(mask));
return (mask & FP_X_MASK);
}
diff --git a/lib/libc/aarch64/gen/fpsetmask.c b/lib/libc/aarch64/gen/fpsetmask.c
index 1ad3f49d603d..4bc72913a8b9 100644
--- a/lib/libc/aarch64/gen/fpsetmask.c
+++ b/lib/libc/aarch64/gen/fpsetmask.c
@@ -1,49 +1,48 @@
/*-
* Copyright (c) 2015 The FreeBSD Foundation
*
* This software was developed by Andrew Turner under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
fp_except_t
fpsetmask(fp_except_t mask)
{
uint64_t old, new;
mask &= FP_X_MASK;
/* Read the current mask */
__asm __volatile("mrs %0, fpcr" : "=&r"(old));
new = old & ~FP_X_MASK;
new |= mask;
__asm __volatile("msr fpcr, %0" :: "r"(new));
return ((fp_except_t)old);
}
diff --git a/lib/libc/aarch64/gen/infinity.c b/lib/libc/aarch64/gen/infinity.c
index fca66838fa63..b7688798765f 100644
--- a/lib/libc/aarch64/gen/infinity.c
+++ b/lib/libc/aarch64/gen/infinity.c
@@ -1,12 +1,11 @@
/*
* infinity.c
*/
-#include <sys/cdefs.h>
#include <math.h>
/* bytes for +Infinity on aarch64 */
const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
/* bytes for NaN */
const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/aarch64/gen/makecontext.c b/lib/libc/aarch64/gen/makecontext.c
index d4dcffa6cd6f..8c9b4edd7a15 100644
--- a/lib/libc/aarch64/gen/makecontext.c
+++ b/lib/libc/aarch64/gen/makecontext.c
@@ -1,83 +1,82 @@
/*-
* Copyright (c) 2015 The FreeBSD Foundation
*
* This software was developed by Andrew Turner under
* sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <machine/armreg.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ucontext.h>
void _ctx_start(void);
void
ctx_done(ucontext_t *ucp)
{
if (ucp->uc_link == NULL) {
exit(0);
} else {
setcontext((const ucontext_t *)ucp->uc_link);
abort();
}
}
__weak_reference(__makecontext, makecontext);
void
__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
{
struct gpregs *gp;
va_list ap;
int i;
/* A valid context is required. */
if (ucp == NULL)
return;
if ((argc < 0) || (argc > 8))
return;
gp = &ucp->uc_mcontext.mc_gpregs;
va_start(ap, argc);
/* Pass up to eight arguments in x0-7. */
for (i = 0; i < argc && i < 8; i++)
gp->gp_x[i] = va_arg(ap, uint64_t);
va_end(ap);
/* Set the stack */
gp->gp_sp = STACKALIGN(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
/* Arrange for return via the trampoline code. */
gp->gp_elr = (__register_t)_ctx_start;
gp->gp_x[19] = (__register_t)func;
gp->gp_x[20] = (__register_t)ucp;
}
diff --git a/lib/libc/aarch64/sys/__vdso_gettc.c b/lib/libc/aarch64/sys/__vdso_gettc.c
index 52fba0e08566..5c5963d0e757 100644
--- a/lib/libc/aarch64/sys/__vdso_gettc.c
+++ b/lib/libc/aarch64/sys/__vdso_gettc.c
@@ -1,74 +1,73 @@
/*-
* Copyright (c) 2015 The FreeBSD Foundation
*
* This software was developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/elf.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <machine/cpufunc.h>
#include <errno.h>
#include "libc_private.h"
static inline uint64_t
cp15_cntvct_get(void)
{
uint64_t reg;
__asm __volatile("mrs %0, cntvct_el0" : "=r" (reg));
return (reg);
}
static inline uint64_t
cp15_cntpct_get(void)
{
uint64_t reg;
__asm __volatile("mrs %0, cntpct_el0" : "=r" (reg));
return (reg);
}
#pragma weak __vdso_gettc
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
if (th->th_algo != VDSO_TH_ALGO_ARM_GENTIM)
return (ENOSYS);
__asm __volatile("isb" : : : "memory");
*tc = th->th_physical == 0 ? cp15_cntvct_get() : cp15_cntpct_get();
return (0);
}
#pragma weak __vdso_gettimekeep
int
__vdso_gettimekeep(struct vdso_timekeep **tk)
{
return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
}
diff --git a/lib/libc/amd64/gen/flt_rounds.c b/lib/libc/amd64/gen/flt_rounds.c
index 018ea029ee3f..cd7e501af5af 100644
--- a/lib/libc/amd64/gen/flt_rounds.c
+++ b/lib/libc/amd64/gen/flt_rounds.c
@@ -1,24 +1,23 @@
/*
* Written by J.T. Conklin, Apr 10, 1995
* Public domain.
*/
-#include <sys/cdefs.h>
#include <float.h>
static const int map[] = {
1, /* round to nearest */
3, /* round to zero */
2, /* round to negative infinity */
0 /* round to positive infinity */
};
int
__flt_rounds(void)
{
int x;
/* Assume that the x87 and the SSE unit agree on the rounding mode. */
__asm("fnstcw %0" : "=m" (x));
return (map[(x >> 10) & 0x03]);
}
diff --git a/lib/libc/amd64/gen/infinity.c b/lib/libc/amd64/gen/infinity.c
index b9db2fc84efa..bc05708abd2b 100644
--- a/lib/libc/amd64/gen/infinity.c
+++ b/lib/libc/amd64/gen/infinity.c
@@ -1,12 +1,11 @@
/*
* infinity.c
*/
-#include <sys/cdefs.h>
#include <math.h>
/* bytes for +Infinity on a 387 */
const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
/* bytes for NaN */
const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/amd64/gen/makecontext.c b/lib/libc/amd64/gen/makecontext.c
index dcc3b8ab9b45..c5767c9d5d75 100644
--- a/lib/libc/amd64/gen/makecontext.c
+++ b/lib/libc/amd64/gen/makecontext.c
@@ -1,107 +1,106 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/ucontext.h>
#include <stdarg.h>
#include <stdlib.h>
typedef void (*func_t)(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t);
/* Prototypes */
static void makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args);
__weak_reference(__makecontext, makecontext);
void
__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
{
uint64_t *args;
uint64_t *sp;
va_list ap;
int i;
/* A valid context is required. */
if ((ucp == NULL) || (ucp->uc_mcontext.mc_len != sizeof(mcontext_t)))
return;
else if ((argc < 0) || (argc > 6) || (ucp->uc_stack.ss_sp == NULL) ||
(ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
/*
* This should really return -1 with errno set to ENOMEM
* or something, but the spec says that makecontext is
* a void function. At least make sure that the context
* isn't valid so it can't be used without an error.
*/
ucp->uc_mcontext.mc_len = 0;
return;
}
/* Align the stack to 16 bytes. */
sp = (uint64_t *)(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
sp = (uint64_t *)((uint64_t)sp & ~15UL);
/* Allocate space for a maximum of 6 arguments on the stack. */
args = sp - 6;
/*
* Account for arguments on stack and do the funky C entry alignment.
* This means that we need an 8-byte-odd alignment since the ABI expects
* the return address to be pushed, thus breaking the 16 byte alignment.
*/
sp -= 7;
/* Add the arguments: */
va_start(ap, argc);
for (i = 0; i < argc; i++)
args[i] = va_arg(ap, uint64_t);
va_end(ap);
for (i = argc; i < 6; i++)
args[i] = 0;
ucp->uc_mcontext.mc_rdi = (register_t)ucp;
ucp->uc_mcontext.mc_rsi = (register_t)start;
ucp->uc_mcontext.mc_rdx = (register_t)args;
ucp->uc_mcontext.mc_rbp = 0;
ucp->uc_mcontext.mc_rbx = (register_t)sp;
ucp->uc_mcontext.mc_rsp = (register_t)sp;
ucp->uc_mcontext.mc_rip = (register_t)makectx_wrapper;
}
static void
makectx_wrapper(ucontext_t *ucp, func_t func, uint64_t *args)
{
(*func)(args[0], args[1], args[2], args[3], args[4], args[5]);
if (ucp->uc_link == NULL)
exit(0);
setcontext((const ucontext_t *)ucp->uc_link);
/* should never get here */
abort();
/* NOTREACHED */
}
diff --git a/lib/libc/amd64/gen/signalcontext.c b/lib/libc/amd64/gen/signalcontext.c
index cc1c2523c754..a97dd158542a 100644
--- a/lib/libc/amd64/gen/signalcontext.c
+++ b/lib/libc/amd64/gen/signalcontext.c
@@ -1,106 +1,105 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/ucontext.h>
#include <signal.h>
#include <stdlib.h>
#include <strings.h>
typedef void (*handler_t)(uint64_t, uint64_t, uint64_t);
/* Prototypes */
static void sigctx_wrapper(ucontext_t *ucp, handler_t func, uint64_t *args);
__weak_reference(__signalcontext, signalcontext);
int
__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
{
uint64_t *args;
siginfo_t *sig_si;
ucontext_t *sig_uc;
uint64_t sp;
/* Bail out if we don't have a valid ucontext pointer. */
if (ucp == NULL)
abort();
/*
* Build a signal frame and copy the arguments of signal handler
* 'func' onto the stack and do the funky stack alignment.
* This means that we need an 8-byte-odd alignment since the ABI expects
* the return address to be pushed, thus breaking the 16 byte alignment.
*/
sp = (ucp->uc_mcontext.mc_rsp - 128 - sizeof(ucontext_t)) & ~15UL;
sig_uc = (ucontext_t *)sp;
bcopy(ucp, sig_uc, sizeof(*sig_uc));
sp = (sp - sizeof(siginfo_t)) & ~15UL;
sig_si = (siginfo_t *)sp;
bzero(sig_si, sizeof(*sig_si));
sig_si->si_signo = sig;
sp -= 3 * sizeof(uint64_t);
args = (uint64_t *)sp;
args[0] = sig;
args[1] = (intptr_t)sig_si;
args[2] = (intptr_t)sig_uc;
sp -= 16;
/*
* Setup the ucontext of the signal handler.
*/
bzero(&ucp->uc_mcontext, sizeof(ucp->uc_mcontext));
ucp->uc_mcontext.mc_fpformat = _MC_FPFMT_NODEV;
ucp->uc_mcontext.mc_ownedfp = _MC_FPOWNED_NONE;
ucp->uc_link = sig_uc;
sigdelset(&ucp->uc_sigmask, sig);
ucp->uc_mcontext.mc_len = sizeof(mcontext_t);
ucp->uc_mcontext.mc_rdi = (register_t)ucp;
ucp->uc_mcontext.mc_rsi = (register_t)func;
ucp->uc_mcontext.mc_rdx = (register_t)args;
ucp->uc_mcontext.mc_rbp = (register_t)sp;
ucp->uc_mcontext.mc_rbx = (register_t)sp;
ucp->uc_mcontext.mc_rsp = (register_t)sp;
ucp->uc_mcontext.mc_rip = (register_t)sigctx_wrapper;
return (0);
}
static void
sigctx_wrapper(ucontext_t *ucp, handler_t func, uint64_t *args)
{
(*func)(args[0], args[1], args[2]);
if (ucp->uc_link == NULL)
exit(0);
setcontext((const ucontext_t *)ucp->uc_link);
/* should never get here */
abort();
/* NOTREACHED */
}
diff --git a/lib/libc/amd64/string/bcopy.c b/lib/libc/amd64/string/bcopy.c
index 406b28f0b97a..868567711e8b 100644
--- a/lib/libc/amd64/string/bcopy.c
+++ b/lib/libc/amd64/string/bcopy.c
@@ -1,13 +1,12 @@
/*-
* Public domain.
*/
-#include <sys/cdefs.h>
#include <string.h>
void
bcopy(const void *src, void *dst, size_t len)
{
memmove(dst, src, len);
}
diff --git a/lib/libc/amd64/string/bzero.c b/lib/libc/amd64/string/bzero.c
index a4fdb74d6bb4..92adb2bb4f0e 100644
--- a/lib/libc/amd64/string/bzero.c
+++ b/lib/libc/amd64/string/bzero.c
@@ -1,13 +1,12 @@
/*-
* Public domain.
*/
-#include <sys/cdefs.h>
#include <string.h>
void
bzero(void *b, size_t len)
{
memset(b, 0, len);
}
diff --git a/lib/libc/amd64/string/strcpy.c b/lib/libc/amd64/string/strcpy.c
index fbc661462ff2..eb93b0defbaa 100644
--- a/lib/libc/amd64/string/strcpy.c
+++ b/lib/libc/amd64/string/strcpy.c
@@ -1,38 +1,37 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2011 George V. Neville-Neil. All rights reserved.
*
* The compilation of software known as FreeBSD is distributed under the
* following terms:
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
char *__stpcpy(char * __restrict, const char * __restrict);
char *
strcpy(char * __restrict to, const char * __restrict from)
{
__stpcpy(to, from);
return(to);
}
diff --git a/lib/libc/amd64/string/strnlen.c b/lib/libc/amd64/string/strnlen.c
index 9db4ce30dfd4..74020f1b1c65 100644
--- a/lib/libc/amd64/string/strnlen.c
+++ b/lib/libc/amd64/string/strnlen.c
@@ -1,42 +1,41 @@
/*-
* Copyright (c) 2023 The FreeBSD Foundation
*
* This software was developed by Robert Clausecker <fuz@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE
*/
-#include <sys/cdefs.h>
#include <string.h>
char *__memchr(const void *, int, size_t);
size_t
strnlen(const char *s, size_t maxlen)
{
const char *loc;
loc = __memchr(s, '\0', maxlen);
return (loc == NULL ? maxlen : (size_t)(loc - s));
}
diff --git a/lib/libc/amd64/sys/amd64_get_fsbase.c b/lib/libc/amd64/sys/amd64_get_fsbase.c
index 4784bb0baf42..00f16a5e404f 100644
--- a/lib/libc/amd64/sys/amd64_get_fsbase.c
+++ b/lib/libc/amd64/sys/amd64_get_fsbase.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Peter Wemm
* Copyright (c) 2017, 2018 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define _WANT_P_OSREL
#include <sys/param.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <x86/ifunc.h>
#include "libc_private.h"
static int
amd64_get_fsbase_cpu(void **addr)
{
*addr = (void *)rdfsbase();
return (0);
}
static int
amd64_get_fsbase_syscall(void **addr)
{
return (sysarch(AMD64_GET_FSBASE, addr));
}
DEFINE_UIFUNC(, int, amd64_get_fsbase, (void **))
{
if (__getosreldate() >= P_OSREL_WRFSBASE &&
(cpu_stdext_feature & CPUID_STDEXT_FSGSBASE) != 0)
return (amd64_get_fsbase_cpu);
return (amd64_get_fsbase_syscall);
}
diff --git a/lib/libc/amd64/sys/amd64_get_gsbase.c b/lib/libc/amd64/sys/amd64_get_gsbase.c
index c81773c4b78c..ef135b1eed7f 100644
--- a/lib/libc/amd64/sys/amd64_get_gsbase.c
+++ b/lib/libc/amd64/sys/amd64_get_gsbase.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Peter Wemm
* Copyright (c) 2017, 2018 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define _WANT_P_OSREL
#include <sys/param.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <x86/ifunc.h>
#include "libc_private.h"
static int
amd64_get_gsbase_cpu(void **addr)
{
*addr = (void *)rdgsbase();
return (0);
}
static int
amd64_get_gsbase_syscall(void **addr)
{
return (sysarch(AMD64_GET_GSBASE, addr));
}
DEFINE_UIFUNC(, int, amd64_get_gsbase, (void **))
{
if (__getosreldate() >= P_OSREL_WRFSBASE &&
(cpu_stdext_feature & CPUID_STDEXT_FSGSBASE) != 0)
return (amd64_get_gsbase_cpu);
return (amd64_get_gsbase_syscall);
}
diff --git a/lib/libc/amd64/sys/amd64_set_fsbase.c b/lib/libc/amd64/sys/amd64_set_fsbase.c
index 24dddcad48f8..f1690fde6e17 100644
--- a/lib/libc/amd64/sys/amd64_set_fsbase.c
+++ b/lib/libc/amd64/sys/amd64_set_fsbase.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Peter Wemm
* Copyright (c) 2017, 2018 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define _WANT_P_OSREL
#include <sys/param.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <x86/ifunc.h>
#include "libc_private.h"
static int
amd64_set_fsbase_cpu(void *addr)
{
wrfsbase((uintptr_t)addr);
return (0);
}
static int
amd64_set_fsbase_syscall(void *addr)
{
return (sysarch(AMD64_SET_FSBASE, &addr));
}
DEFINE_UIFUNC(, int, amd64_set_fsbase, (void *))
{
if (__getosreldate() >= P_OSREL_WRFSBASE &&
(cpu_stdext_feature & CPUID_STDEXT_FSGSBASE) != 0)
return (amd64_set_fsbase_cpu);
return (amd64_set_fsbase_syscall);
}
diff --git a/lib/libc/amd64/sys/amd64_set_gsbase.c b/lib/libc/amd64/sys/amd64_set_gsbase.c
index 10004afe8234..756bbae18844 100644
--- a/lib/libc/amd64/sys/amd64_set_gsbase.c
+++ b/lib/libc/amd64/sys/amd64_set_gsbase.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Peter Wemm
* Copyright (c) 2017, 2018 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define _WANT_P_OSREL
#include <sys/param.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <x86/ifunc.h>
#include "libc_private.h"
static int
amd64_set_gsbase_cpu(void *addr)
{
wrgsbase((uintptr_t)addr);
return (0);
}
static int
amd64_set_gsbase_syscall(void *addr)
{
return (sysarch(AMD64_SET_GSBASE, &addr));
}
DEFINE_UIFUNC(, int, amd64_set_gsbase, (void *))
{
if (__getosreldate() >= P_OSREL_WRFSBASE &&
(cpu_stdext_feature & CPUID_STDEXT_FSGSBASE) != 0)
return (amd64_set_gsbase_cpu);
return (amd64_set_gsbase_syscall);
}
diff --git a/lib/libc/arm/aeabi/aeabi_atexit.c b/lib/libc/arm/aeabi/aeabi_atexit.c
index 267ddfb223de..d688edf9c4e9 100644
--- a/lib/libc/arm/aeabi/aeabi_atexit.c
+++ b/lib/libc/arm/aeabi/aeabi_atexit.c
@@ -1,38 +1,37 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2012 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
int __cxa_atexit(void (*)(void *), void *, void *);
int
__aeabi_atexit(void *object, void (*func)(void*), void *dso)
{
return __cxa_atexit(func, object, dso);
}
diff --git a/lib/libc/arm/aeabi/aeabi_double.c b/lib/libc/arm/aeabi/aeabi_double.c
index 9fb0c61a3467..190354e5c6eb 100644
--- a/lib/libc/arm/aeabi/aeabi_double.c
+++ b/lib/libc/arm/aeabi/aeabi_double.c
@@ -1,101 +1,100 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2012 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
#include "aeabi_vfp.h"
extern int _libc_arm_fpu_present;
flag __unorddf2(float64, float64);
/* These are written in asm and are only called from this file */
int __aeabi_dcmpeq_vfp(float64, float64);
int __aeabi_dcmplt_vfp(float64, float64);
int __aeabi_dcmple_vfp(float64, float64);
int __aeabi_dcmpgt_vfp(float64, float64);
int __aeabi_dcmpge_vfp(float64, float64);
int __aeabi_dcmpun_vfp(float64, float64);
int __aeabi_d2iz_vfp(float64);
float32 __aeabi_d2f_vfp(float64);
float64 __aeabi_i2d_vfp(int);
float64 __aeabi_dadd_vfp(float64, float64);
float64 __aeabi_ddiv_vfp(float64, float64);
float64 __aeabi_dmul_vfp(float64, float64);
float64 __aeabi_dsub_vfp(float64, float64);
/*
* Depending on the target these will:
* On armv6 with a vfp call the above function, or
* Call the softfloat function in the 3rd argument.
*/
int AEABI_FUNC2(dcmpeq, float64, float64_eq)
int AEABI_FUNC2(dcmplt, float64, float64_lt)
int AEABI_FUNC2(dcmple, float64, float64_le)
int AEABI_FUNC2_REV(dcmpge, float64, float64_le)
int AEABI_FUNC2_REV(dcmpgt, float64, float64_lt)
int AEABI_FUNC2(dcmpun, float64, __unorddf2)
int AEABI_FUNC(d2iz, float64, float64_to_int32_round_to_zero)
float32 AEABI_FUNC(d2f, float64, float64_to_float32)
float64 AEABI_FUNC(i2d, int, int32_to_float64)
float64 AEABI_FUNC2(dadd, float64, float64_add)
float64 AEABI_FUNC2(ddiv, float64, float64_div)
float64 AEABI_FUNC2(dmul, float64, float64_mul)
float64 AEABI_FUNC2(dsub, float64, float64_sub)
int
__aeabi_cdcmpeq_helper(float64 a, float64 b)
{
int quiet = 0;
/* Check if a is a NaN */
if ((a << 1) > 0xffe0000000000000ull) {
/* If it's a signalling NaN we will always signal */
if ((a & 0x0008000000000000ull) == 0)
return (0);
quiet = 1;
}
/* Check if b is a NaN */
if ((b << 1) > 0xffe0000000000000ull) {
/* If it's a signalling NaN we will always signal */
if ((b & 0x0008000000000000ull) == 0)
return (0);
quiet = 1;
}
return (quiet);
}
diff --git a/lib/libc/arm/aeabi/aeabi_float.c b/lib/libc/arm/aeabi/aeabi_float.c
index 71b46af836ed..ac6b11ae9dfe 100644
--- a/lib/libc/arm/aeabi/aeabi_float.c
+++ b/lib/libc/arm/aeabi/aeabi_float.c
@@ -1,101 +1,100 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2012 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
#include "aeabi_vfp.h"
extern int _libc_arm_fpu_present;
flag __unordsf2(float32, float32);
/* These are written in asm and are only called from this file */
int __aeabi_fcmpeq_vfp(float32, float32);
int __aeabi_fcmplt_vfp(float32, float32);
int __aeabi_fcmple_vfp(float32, float32);
int __aeabi_fcmpgt_vfp(float32, float32);
int __aeabi_fcmpge_vfp(float32, float32);
int __aeabi_fcmpun_vfp(float32, float32);
int __aeabi_f2iz_vfp(float32);
float64 __aeabi_f2d_vfp(float32);
float32 __aeabi_i2f_vfp(int);
float32 __aeabi_fadd_vfp(float32, float32);
float32 __aeabi_fdiv_vfp(float32, float32);
float32 __aeabi_fmul_vfp(float32, float32);
float32 __aeabi_fsub_vfp(float32, float32);
/*
* Depending on the target these will:
* On armv6 with a vfp call the above function, or
* Call the softfloat function in the 3rd argument.
*/
int AEABI_FUNC2(fcmpeq, float32, float32_eq)
int AEABI_FUNC2(fcmplt, float32, float32_lt)
int AEABI_FUNC2(fcmple, float32, float32_le)
int AEABI_FUNC2_REV(fcmpge, float32, float32_le)
int AEABI_FUNC2_REV(fcmpgt, float32, float32_lt)
int AEABI_FUNC2(fcmpun, float32, __unordsf2)
int AEABI_FUNC(f2iz, float32, float32_to_int32_round_to_zero)
float64 AEABI_FUNC(f2d, float32, float32_to_float64)
float32 AEABI_FUNC(i2f, int, int32_to_float32)
float32 AEABI_FUNC2(fadd, float32, float32_add)
float32 AEABI_FUNC2(fdiv, float32, float32_div)
float32 AEABI_FUNC2(fmul, float32, float32_mul)
float32 AEABI_FUNC2(fsub, float32, float32_sub)
int
__aeabi_cfcmpeq_helper(float32 a, float32 b)
{
int quiet = 0;
/* Check if a is a NaN */
if ((a << 1) > 0xff000000u) {
/* If it's a signalling NaN we will always signal */
if ((a & 0x00400000u) == 0)
return (0);
quiet = 1;
}
/* Check if b is a NaN */
if ((b << 1) > 0xff000000u) {
/* If it's a signalling NaN we will always signal */
if ((b & 0x00400000u) == 0)
return (0);
quiet = 1;
}
return (quiet);
}
diff --git a/lib/libc/arm/aeabi/aeabi_unwind_cpp.c b/lib/libc/arm/aeabi/aeabi_unwind_cpp.c
index f3bee222d529..efcace2c0675 100644
--- a/lib/libc/arm/aeabi/aeabi_unwind_cpp.c
+++ b/lib/libc/arm/aeabi/aeabi_unwind_cpp.c
@@ -1,61 +1,60 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2011 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
/*
* Provide an implementation of __aeabi_unwind_cpp_pr{0,1,2}. These are
* required by libc but are implemented in libgcc_eh.a which we don't link
* against. The libgcc_eh.a version will be called so we call abort to
* check this.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
void __aeabi_unwind_cpp_pr0(void) __hidden;
void __aeabi_unwind_cpp_pr1(void) __hidden;
void __aeabi_unwind_cpp_pr2(void) __hidden;
void
__aeabi_unwind_cpp_pr0(void)
{
abort();
}
void
__aeabi_unwind_cpp_pr1(void)
{
abort();
}
void
__aeabi_unwind_cpp_pr2(void)
{
abort();
}
diff --git a/lib/libc/arm/aeabi/aeabi_unwind_exidx.c b/lib/libc/arm/aeabi/aeabi_unwind_exidx.c
index e7bff3816ff5..cf61922d4304 100644
--- a/lib/libc/arm/aeabi/aeabi_unwind_exidx.c
+++ b/lib/libc/arm/aeabi/aeabi_unwind_exidx.c
@@ -1,102 +1,101 @@
/*-
* Copyright (c) 2014 Ian Lepore <ian@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/elf.h>
#include <link.h>
#include <stddef.h>
/*
* ARM EABI unwind helper.
*
* This finds the exidx section address and size associated with a given code
* address. There are separate implementations for static and dynamic code.
*
* GCC expects this function to exist as __gnu_Unwind_Find_exidx(), clang and
* BSD tools expect it to be dl_unwind_find_exidx(). Both have the same API, so
* we set up an alias for GCC.
*/
__strong_reference(dl_unwind_find_exidx, __gnu_Unwind_Find_exidx);
/*
* Each entry in the exidx section is a pair of 32-bit words. We don't
* interpret the contents of the entries here; this typedef is just a local
* convenience for using sizeof() and doing pointer math.
*/
typedef struct exidx_entry {
uint32_t data[2];
} exidx_entry;
#ifdef __PIC__
/*
* Unwind helper for dynamically linked code.
*
* This finds the shared object that contains the given address, and returns the
* address of the exidx section in that shared object along with the number of
* entries in that section, or NULL if it wasn't found.
*/
void *
dl_unwind_find_exidx(const void *pc, int *pcount)
{
const Elf_Phdr *hdr;
struct dl_phdr_info info;
int i;
if (_rtld_addr_phdr(pc, &info)) {
hdr = info.dlpi_phdr;
for (i = 0; i < info.dlpi_phnum; i++, hdr++) {
if (hdr->p_type == PT_ARM_EXIDX) {
*pcount = hdr->p_memsz / sizeof(exidx_entry);
return ((void *)(info.dlpi_addr + hdr->p_vaddr));
}
}
}
return (NULL);
}
#else /* !__PIC__ */
/*
* Unwind helper for statically linked code.
*
* In a statically linked program, the linker populates a pair of symbols with
* the addresses of the start and end of the exidx table, so returning the
* address and count of elements is pretty straighforward.
*/
void *
dl_unwind_find_exidx(const void *pc, int *pcount)
{
extern struct exidx_entry __exidx_start;
extern struct exidx_entry __exidx_end;
*pcount = (int)(&__exidx_end - &__exidx_start);
return (&__exidx_start);
}
#endif /* __PIC__ */
diff --git a/lib/libc/arm/gen/arm_drain_writebuf.c b/lib/libc/arm/gen/arm_drain_writebuf.c
index d8e4063f27cb..30c93718bfe6 100644
--- a/lib/libc/arm/gen/arm_drain_writebuf.c
+++ b/lib/libc/arm/gen/arm_drain_writebuf.c
@@ -1,37 +1,36 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Ian Lepore <ian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
#include <stddef.h>
int
arm_drain_writebuf(void)
{
sysarch(ARM_DRAIN_WRITEBUF, NULL);
return (0);
}
diff --git a/lib/libc/arm/gen/arm_initfini.c b/lib/libc/arm/gen/arm_initfini.c
index 00ca41165c29..31756aa852a4 100644
--- a/lib/libc/arm/gen/arm_initfini.c
+++ b/lib/libc/arm/gen/arm_initfini.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 The NetBSD Foundation, Inc.
* Copyright (c) 2013 Andrew Turner
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Matt Thomas of 3am Software Foundry.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Bases on NetBSD lib/libc/arch/arm/misc/arm_initfini.c
* $NetBSD: arm_initfini.c,v 1.2 2013/01/31 06:47:55 matt Exp $
*/
-#include <sys/cdefs.h>
/*
* To properly implement setjmp/longjmp for the ARM AAPCS ABI, it has to be
* aware of whether there is a FPU is present or not. Regardless of whether
* the hard-float ABI is being used, setjmp needs to save D8-D15. But it can
* only do this if those instructions won't cause an exception.
*/
#include <sys/param.h>
#include <sys/sysctl.h>
#include <stdbool.h>
#include <stddef.h>
extern int __sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp,
void *newp, size_t newlen);
int _libc_arm_fpu_present;
static bool _libc_aapcs_initialized;
void _libc_aapcs_init(void) __attribute__((__constructor__, __used__));
void
_libc_aapcs_init(void)
{
int mib[2];
size_t len;
if (_libc_aapcs_initialized)
return;
mib[0] = CTL_HW;
mib[1] = HW_FLOATINGPT;
len = sizeof(_libc_arm_fpu_present);
if (__sysctl(mib, 2, &_libc_arm_fpu_present, &len, NULL, 0) == -1 ||
len != sizeof(_libc_arm_fpu_present)) {
/* sysctl failed, assume no vfp */
_libc_arm_fpu_present = 0;
}
_libc_aapcs_initialized = true;
}
diff --git a/lib/libc/arm/gen/arm_sync_icache.c b/lib/libc/arm/gen/arm_sync_icache.c
index d89f57cbae18..b5872fb8ef00 100644
--- a/lib/libc/arm/gen/arm_sync_icache.c
+++ b/lib/libc/arm/gen/arm_sync_icache.c
@@ -1,42 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Ian Lepore <ian@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/sysarch.h>
#include <stddef.h>
int
arm_sync_icache(u_int addr, int len)
{
struct arm_sync_icache_args args;
args.addr = addr;
args.len = len;
sysarch(ARM_SYNC_ICACHE, &args);
return (0);
}
diff --git a/lib/libc/arm/gen/fabs.c b/lib/libc/arm/gen/fabs.c
index b3020b88062d..2e0abbb8a42a 100644
--- a/lib/libc/arm/gen/fabs.c
+++ b/lib/libc/arm/gen/fabs.c
@@ -1,46 +1,45 @@
/* $NetBSD: fabs.c,v 1.2 2002/05/26 11:48:01 wiz Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1996 Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* fabs(x) returns the absolute value of x.
*/
-#include <sys/cdefs.h>
double
fabs(double x)
{
if (x < 0)
x = -x;
return(x);
}
diff --git a/lib/libc/arm/gen/flt_rounds.c b/lib/libc/arm/gen/flt_rounds.c
index a592dbff38c0..7621262419a4 100644
--- a/lib/libc/arm/gen/flt_rounds.c
+++ b/lib/libc/arm/gen/flt_rounds.c
@@ -1,69 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Ian Lepore <freebsd@damnhippie.dyndns.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <fenv.h>
#include <float.h>
#ifndef __ARM_PCS_VFP
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
#endif
int
__flt_rounds(void)
{
int mode;
#ifndef __ARM_PCS_VFP
/*
* Translate our rounding modes to the unnamed
* manifest constants required by C99 et. al.
*/
mode = __softfloat_float_rounding_mode;
#else /* __ARM_PCS_VFP */
/*
* Read the floating-point status and control register
*/
__asm __volatile("vmrs %0, fpscr" : "=&r"(mode));
mode &= _ROUND_MASK;
#endif /* __ARM_PCS_VFP */
switch (mode) {
case FE_TOWARDZERO:
return (0);
case FE_TONEAREST:
return (1);
case FE_UPWARD:
return (2);
case FE_DOWNWARD:
return (3);
}
return (-1);
}
diff --git a/lib/libc/arm/gen/fpgetmask_vfp.c b/lib/libc/arm/gen/fpgetmask_vfp.c
index d70f5caf845b..a4ed8d1afbec 100644
--- a/lib/libc/arm/gen/fpgetmask_vfp.c
+++ b/lib/libc/arm/gen/fpgetmask_vfp.c
@@ -1,47 +1,46 @@
/*
* Copyright (C) 2014 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifdef __weak_alias
__weak_alias(fpgetmask,_fpgetmask)
#endif
#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
fp_except_t
fpgetmask(void)
{
fp_except mask;
__asm __volatile("vmrs %0, fpscr" : "=&r"(mask));
return ((mask >> 8) & FP_X_MASK);
}
diff --git a/lib/libc/arm/gen/fpgetround_vfp.c b/lib/libc/arm/gen/fpgetround_vfp.c
index 830193b65e65..21debc0b028d 100644
--- a/lib/libc/arm/gen/fpgetround_vfp.c
+++ b/lib/libc/arm/gen/fpgetround_vfp.c
@@ -1,45 +1,44 @@
/*
* Copyright (C) 2014 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifdef __weak_alias
__weak_alias(fpgetround,_fpgetround)
#endif
fp_rnd_t
fpgetround(void)
{
uint32_t fpscr;
__asm __volatile("vmrs %0, fpscr" : "=&r"(fpscr));
return ((fpscr >> 22) & 3);
}
diff --git a/lib/libc/arm/gen/fpgetsticky_vfp.c b/lib/libc/arm/gen/fpgetsticky_vfp.c
index 34ed2f0dd5e0..7d278c3ad849 100644
--- a/lib/libc/arm/gen/fpgetsticky_vfp.c
+++ b/lib/libc/arm/gen/fpgetsticky_vfp.c
@@ -1,47 +1,46 @@
/*
* Copyright (C) 2014 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifdef __weak_alias
__weak_alias(fpgetsticky,_fpgetsticky)
#endif
#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
fp_except
fpgetsticky(void)
{
fp_except old;
__asm __volatile("vmrs %0, fpscr" : "=&r"(old));
return (old & FP_X_MASK);
}
diff --git a/lib/libc/arm/gen/fpsetmask_vfp.c b/lib/libc/arm/gen/fpsetmask_vfp.c
index bf9c1c622094..92ad97e6dfa2 100644
--- a/lib/libc/arm/gen/fpsetmask_vfp.c
+++ b/lib/libc/arm/gen/fpsetmask_vfp.c
@@ -1,50 +1,49 @@
/*
* Copyright (C) 2014 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifdef __weak_alias
__weak_alias(fpsetmask,_fpsetmask)
#endif
#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
fp_except_t
fpsetmask(fp_except_t mask)
{
fp_except old, new;
__asm __volatile("vmrs %0, fpscr" : "=&r"(old));
mask = (mask & FP_X_MASK) << 8;
new = (old & ~(FP_X_MASK << 8)) | mask;
__asm __volatile("vmsr fpscr, %0" : : "r"(new));
return ((old >> 8) & FP_X_MASK);
}
diff --git a/lib/libc/arm/gen/fpsetround_vfp.c b/lib/libc/arm/gen/fpsetround_vfp.c
index 76b8a9e92269..4e55335f6a3b 100644
--- a/lib/libc/arm/gen/fpsetround_vfp.c
+++ b/lib/libc/arm/gen/fpsetround_vfp.c
@@ -1,48 +1,47 @@
/*
* Copyright (C) 2014 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifdef __weak_alias
__weak_alias(fpsetround,_fpsetround)
#endif
fp_rnd_t
fpsetround(fp_rnd_t rnd_dir)
{
uint32_t old, new;
__asm __volatile("vmrs %0, fpscr" : "=&r"(old));
new = old & ~(3 << 22);
new |= rnd_dir << 22;
__asm __volatile("vmsr fpscr, %0" : : "r"(new));
return ((old >> 22) & 3);
}
diff --git a/lib/libc/arm/gen/fpsetsticky_vfp.c b/lib/libc/arm/gen/fpsetsticky_vfp.c
index e98681e2372c..fb3a59b25178 100644
--- a/lib/libc/arm/gen/fpsetsticky_vfp.c
+++ b/lib/libc/arm/gen/fpsetsticky_vfp.c
@@ -1,50 +1,49 @@
/*
* Copyright (C) 2014 Andrew Turner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifdef __weak_alias
__weak_alias(fpsetsticky,_fpsetsticky)
#endif
#define FP_X_MASK (FP_X_INV | FP_X_DZ | FP_X_OFL | FP_X_UFL | FP_X_IMP)
fp_except
fpsetsticky(fp_except except)
{
fp_except old, new;
__asm __volatile("vmrs %0, fpscr" : "=&r"(old));
new = old & ~(FP_X_MASK);
new &= ~except;
__asm __volatile("vmsr fpscr, %0" : : "r"(new));
return (old & except);
}
diff --git a/lib/libc/arm/gen/getcontextx.c b/lib/libc/arm/gen/getcontextx.c
index 78db8c077152..357d3a2a0416 100644
--- a/lib/libc/arm/gen/getcontextx.c
+++ b/lib/libc/arm/gen/getcontextx.c
@@ -1,99 +1,98 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2017 Michal Meloun <mmel@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/ucontext.h>
#include <errno.h>
#include <stdlib.h>
#include <machine/sysarch.h>
struct ucontextx {
ucontext_t ucontext;
mcontext_vfp_t mcontext_vfp;
};
int
__getcontextx_size(void)
{
return (sizeof(struct ucontextx));
}
int
__fillcontextx2(char *ctx)
{
struct ucontextx *ucxp;
ucontext_t *ucp;
mcontext_vfp_t *mvp;
struct arm_get_vfpstate_args vfp_arg;
ucxp = (struct ucontextx *)ctx;
ucp = &ucxp->ucontext;
mvp = &ucxp->mcontext_vfp;
vfp_arg.mc_vfp_size = sizeof(mcontext_vfp_t);
vfp_arg.mc_vfp = mvp;
if (sysarch(ARM_GET_VFPSTATE, &vfp_arg) == -1)
return (-1);
ucp->uc_mcontext.mc_vfp_size = sizeof(mcontext_vfp_t);
ucp->uc_mcontext.mc_vfp_ptr = mvp;
return (0);
}
int
__fillcontextx(char *ctx)
{
struct ucontextx *ucxp;
ucxp = (struct ucontextx *)ctx;
if (getcontext(&ucxp->ucontext) == -1)
return (-1);
__fillcontextx2(ctx);
return (0);
}
__weak_reference(__getcontextx, getcontextx);
ucontext_t *
__getcontextx(void)
{
char *ctx;
int error;
ctx = malloc(__getcontextx_size());
if (ctx == NULL)
return (NULL);
if (__fillcontextx(ctx) == -1) {
error = errno;
free(ctx);
errno = error;
return (NULL);
}
return ((ucontext_t *)ctx);
}
diff --git a/lib/libc/arm/gen/infinity.c b/lib/libc/arm/gen/infinity.c
index fe6c147980ec..1a78a03be2e3 100644
--- a/lib/libc/arm/gen/infinity.c
+++ b/lib/libc/arm/gen/infinity.c
@@ -1,24 +1,23 @@
/*
* infinity.c
*/
-#include <sys/cdefs.h>
#include <math.h>
/* bytes for +Infinity on a 387 */
const union __infinity_un __infinity = {
#if BYTE_ORDER == BIG_ENDIAN
{ 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
#else
{ 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
#endif
};
/* bytes for NaN */
const union __nan_un __nan = {
#if BYTE_ORDER == BIG_ENDIAN
{0xff, 0xc0, 0, 0}
#else
{ 0, 0, 0xc0, 0xff }
#endif
};
diff --git a/lib/libc/arm/gen/makecontext.c b/lib/libc/arm/gen/makecontext.c
index 1051d4e4de15..ac338085f2ed 100644
--- a/lib/libc/arm/gen/makecontext.c
+++ b/lib/libc/arm/gen/makecontext.c
@@ -1,89 +1,88 @@
/* $NetBSD: makecontext.c,v 1.2 2003/01/18 11:06:24 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Klaus Klein.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <stddef.h>
#include <inttypes.h>
#include <ucontext.h>
#include <stdarg.h>
extern void _ctx_start(void);
void
ctx_done(ucontext_t *ucp)
{
if (ucp->uc_link == NULL)
exit(0);
else {
setcontext((const ucontext_t *)ucp->uc_link);
abort();
}
}
__weak_reference(__makecontext, makecontext);
void
__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
{
__greg_t *gr = ucp->uc_mcontext.__gregs;
int i;
unsigned int *sp;
va_list ap;
/* Compute and align stack pointer. */
sp = (unsigned int *)
(((uintptr_t)ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size -
sizeof(double)) & ~7);
/* Allocate necessary stack space for arguments exceeding r0-3. */
if (argc > 4)
sp -= argc - 4;
gr[_REG_SP] = (__greg_t)sp;
/* Wipe out frame pointer. */
gr[_REG_FP] = 0;
/* Arrange for return via the trampoline code. */
gr[_REG_PC] = (__greg_t)_ctx_start;
gr[_REG_R4] = (__greg_t)func;
gr[_REG_R5] = (__greg_t)ucp;
va_start(ap, argc);
/* Pass up to four arguments in r0-3. */
for (i = 0; i < argc && i < 4; i++)
gr[_REG_R0 + i] = va_arg(ap, int);
/* Pass any additional arguments on the stack. */
for (argc -= i; argc > 0; argc--)
*sp++ = va_arg(ap, int);
va_end(ap);
}
diff --git a/lib/libc/arm/gen/signalcontext.c b/lib/libc/arm/gen/signalcontext.c
index 95fdc1579f84..e66a08928355 100644
--- a/lib/libc/arm/gen/signalcontext.c
+++ b/lib/libc/arm/gen/signalcontext.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Olivier Houchard
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <machine/frame.h>
#include <machine/sigframe.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <strings.h>
#include <signal.h>
__weak_reference(__signalcontext, signalcontext);
extern void _ctx_start(void);
int
__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
{
struct sigframe *sfp;
__greg_t *gr = ucp->uc_mcontext.__gregs;
unsigned int *sp;
sp = (unsigned int *)gr[_REG_SP];
sfp = (struct sigframe *)sp - 1;
bzero(sfp, sizeof(*sfp));
bcopy(ucp, &sfp->sf_uc, sizeof(*ucp));
sfp->sf_si.si_signo = sig;
gr[_REG_SP] = (__greg_t)sfp;
/* Wipe out frame pointer. */
gr[_REG_FP] = 0;
/* Arrange for return via the trampoline code. */
gr[_REG_PC] = (__greg_t)_ctx_start;
gr[_REG_R4] = (__greg_t)func;
gr[_REG_R5] = (__greg_t)ucp;
gr[_REG_R0] = (__greg_t)sig;
gr[_REG_R1] = (__greg_t)&sfp->sf_si;
gr[_REG_R2] = (__greg_t)&sfp->sf_uc;
ucp->uc_link = &sfp->sf_uc;
sigdelset(&ucp->uc_sigmask, sig);
return (0);
}
diff --git a/lib/libc/arm/sys/__vdso_gettc.c b/lib/libc/arm/sys/__vdso_gettc.c
index e5987eea2fe4..ea70dec35cd8 100644
--- a/lib/libc/arm/sys/__vdso_gettc.c
+++ b/lib/libc/arm/sys/__vdso_gettc.c
@@ -1,89 +1,88 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2015 The FreeBSD Foundation
*
* This software was developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/elf.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <machine/cpufunc.h>
#include <machine/acle-compat.h>
#include <errno.h>
#include "libc_private.h"
#if __ARM_ARCH >= 6
static inline uint64_t
cp15_cntvct_get(void)
{
uint64_t reg;
__asm __volatile("mrrc\tp15, 1, %Q0, %R0, c14" : "=r" (reg));
return (reg);
}
static inline uint64_t
cp15_cntpct_get(void)
{
uint64_t reg;
__asm __volatile("mrrc\tp15, 0, %Q0, %R0, c14" : "=r" (reg));
return (reg);
}
#endif
#pragma weak __vdso_gettc
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
if (th->th_algo != VDSO_TH_ALGO_ARM_GENTIM)
return (ENOSYS);
#if __ARM_ARCH >= 6
/*
* Userspace gettimeofday() is only enabled on ARMv7 CPUs, but
* libc is compiled for ARMv6. Due to clang issues, .arch
* armv7-a directive does not work.
*/
__asm __volatile(".word\t0xf57ff06f" : : : "memory"); /* isb */
*tc = th->th_physical == 0 ? cp15_cntvct_get() : cp15_cntpct_get();
return (0);
#else
*tc = 0;
return (ENOSYS);
#endif
}
#pragma weak __vdso_gettimekeep
int
__vdso_gettimekeep(struct vdso_timekeep **tk)
{
return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
}
diff --git a/lib/libc/compat-43/creat.c b/lib/libc/compat-43/creat.c
index f38c673967bd..16fceca556e7 100644
--- a/lib/libc/compat-43/creat.c
+++ b/lib/libc/compat-43/creat.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)creat.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <fcntl.h>
#include "un-namespace.h"
#include "libc_private.h"
__weak_reference(__creat, creat);
__weak_reference(__creat, _creat);
int __creat(const char *path, mode_t mode);
#pragma weak creat
int
__creat(const char *path, mode_t mode)
{
return (((int (*)(int, const char *, int, ...))
__libc_interposing[INTERPOS_openat])(AT_FDCWD, path, O_WRONLY |
O_CREAT | O_TRUNC, mode));
}
diff --git a/lib/libc/compat-43/gethostid.c b/lib/libc/compat-43/gethostid.c
index 2314b9f6df64..2e7bc9a7f247 100644
--- a/lib/libc/compat-43/gethostid.c
+++ b/lib/libc/compat-43/gethostid.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gethostid.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <unistd.h>
long
gethostid(void)
{
int mib[2];
size_t size;
long value;
mib[0] = CTL_KERN;
mib[1] = KERN_HOSTID;
size = sizeof value;
if (sysctl(mib, 2, &value, &size, NULL, 0) == -1)
return (-1);
return (value);
}
diff --git a/lib/libc/compat-43/getwd.c b/lib/libc/compat-43/getwd.c
index c5f10440516d..f0c78788bf65 100644
--- a/lib/libc/compat-43/getwd.c
+++ b/lib/libc/compat-43/getwd.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getwd.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
char *
getwd(char *buf)
{
char *p;
if ( (p = getcwd(buf, MAXPATHLEN)) )
return(p);
(void)strerror_r(errno, buf, MAXPATHLEN);
return((char *)NULL);
}
diff --git a/lib/libc/compat-43/killpg.c b/lib/libc/compat-43/killpg.c
index 69340598262b..e7e8b9084ec1 100644
--- a/lib/libc/compat-43/killpg.c
+++ b/lib/libc/compat-43/killpg.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)killpg.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <signal.h>
#include <errno.h>
/*
* Backwards-compatible killpg().
*/
int
killpg(pid_t pgid, int sig)
{
if (pgid == 1) {
errno = ESRCH;
return (-1);
}
return (kill(-pgid, sig));
}
diff --git a/lib/libc/compat-43/sethostid.c b/lib/libc/compat-43/sethostid.c
index cc53400a598b..3f9dbd1af76b 100644
--- a/lib/libc/compat-43/sethostid.c
+++ b/lib/libc/compat-43/sethostid.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)sethostid.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <unistd.h>
void
sethostid(long hostid)
{
int mib[2];
mib[0] = CTL_KERN;
mib[1] = KERN_HOSTID;
sysctl(mib, 2, NULL, NULL, &hostid, sizeof hostid);
}
diff --git a/lib/libc/compat-43/setpgrp.c b/lib/libc/compat-43/setpgrp.c
index 4bf0d23ba73d..3166f0f096a3 100644
--- a/lib/libc/compat-43/setpgrp.c
+++ b/lib/libc/compat-43/setpgrp.c
@@ -1,43 +1,42 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setpgrp.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <unistd.h>
int
setpgrp(pid_t pid, pid_t pgid)
{
return(setpgid(pid, pgid));
}
diff --git a/lib/libc/compat-43/setrgid.c b/lib/libc/compat-43/setrgid.c
index 30a7c24cea4d..8cb55b02f35b 100644
--- a/lib/libc/compat-43/setrgid.c
+++ b/lib/libc/compat-43/setrgid.c
@@ -1,43 +1,42 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setrgid.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <unistd.h>
int
setrgid(gid_t rgid)
{
return (setregid(rgid, -1));
}
diff --git a/lib/libc/compat-43/setruid.c b/lib/libc/compat-43/setruid.c
index 4dd738a6e68d..0615442e3b9f 100644
--- a/lib/libc/compat-43/setruid.c
+++ b/lib/libc/compat-43/setruid.c
@@ -1,43 +1,42 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setruid.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <unistd.h>
int
setruid(uid_t ruid)
{
return (setreuid(ruid, -1));
}
diff --git a/lib/libc/compat-43/sigcompat.c b/lib/libc/compat-43/sigcompat.c
index 350f8e77971c..f7421f7260eb 100644
--- a/lib/libc/compat-43/sigcompat.c
+++ b/lib/libc/compat-43/sigcompat.c
@@ -1,185 +1,184 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)sigcompat.c 8.1 (Berkeley) 6/2/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <errno.h>
#include <signal.h>
#include <string.h>
#include "un-namespace.h"
#include "libc_private.h"
int
sigvec(int signo, struct sigvec *sv, struct sigvec *osv)
{
struct sigaction sa, osa;
struct sigaction *sap, *osap;
int ret;
if (sv != NULL) {
sa.sa_handler = sv->sv_handler;
sa.sa_flags = sv->sv_flags ^ SV_INTERRUPT;
sigemptyset(&sa.sa_mask);
sa.sa_mask.__bits[0] = sv->sv_mask;
sap = &sa;
} else
sap = NULL;
osap = osv != NULL ? &osa : NULL;
ret = __libc_sigaction(signo, sap, osap);
if (ret == 0 && osv != NULL) {
osv->sv_handler = osa.sa_handler;
osv->sv_flags = osa.sa_flags ^ SV_INTERRUPT;
osv->sv_mask = osa.sa_mask.__bits[0];
}
return (ret);
}
int
sigsetmask(int mask)
{
sigset_t set, oset;
int n;
sigemptyset(&set);
set.__bits[0] = mask;
n = __libc_sigprocmask(SIG_SETMASK, &set, &oset);
if (n)
return (n);
return (oset.__bits[0]);
}
int
sigblock(int mask)
{
sigset_t set, oset;
int n;
sigemptyset(&set);
set.__bits[0] = mask;
n = __libc_sigprocmask(SIG_BLOCK, &set, &oset);
if (n)
return (n);
return (oset.__bits[0]);
}
int
sigpause(int mask)
{
sigset_t set;
sigemptyset(&set);
set.__bits[0] = mask;
return (__libc_sigsuspend(&set));
}
int
xsi_sigpause(int sig)
{
sigset_t set;
if (__libc_sigprocmask(SIG_BLOCK, NULL, &set) == -1)
return (-1);
if (sigdelset(&set, sig) == -1)
return (-1);
return (__libc_sigsuspend(&set));
}
int
sighold(int sig)
{
sigset_t set;
sigemptyset(&set);
if (sigaddset(&set, sig) == -1)
return (-1);
return (__libc_sigprocmask(SIG_BLOCK, &set, NULL));
}
int
sigignore(int sig)
{
struct sigaction sa;
bzero(&sa, sizeof(sa));
sa.sa_handler = SIG_IGN;
return (__libc_sigaction(sig, &sa, NULL));
}
int
sigrelse(int sig)
{
sigset_t set;
sigemptyset(&set);
if (sigaddset(&set, sig) == -1)
return (-1);
return (__libc_sigprocmask(SIG_UNBLOCK, &set, NULL));
}
void
(*sigset(int sig, void (*disp)(int)))(int)
{
sigset_t set, pset;
struct sigaction sa, psa;
sigemptyset(&set);
if (sigaddset(&set, sig) == -1)
return (SIG_ERR);
if (__libc_sigprocmask(SIG_BLOCK, NULL, &pset) == -1)
return (SIG_ERR);
if ((__sighandler_t *)disp == SIG_HOLD) {
if (__libc_sigprocmask(SIG_BLOCK, &set, &pset) == -1)
return (SIG_ERR);
if (sigismember(&pset, sig))
return (SIG_HOLD);
else {
if (__libc_sigaction(sig, NULL, &psa) == -1)
return (SIG_ERR);
return (psa.sa_handler);
}
} else {
if (__libc_sigprocmask(SIG_UNBLOCK, &set, &pset) == -1)
return (SIG_ERR);
}
bzero(&sa, sizeof(sa));
sa.sa_handler = disp;
if (__libc_sigaction(sig, &sa, &psa) == -1)
return (SIG_ERR);
if (sigismember(&pset, sig))
return (SIG_HOLD);
else
return (psa.sa_handler);
}
diff --git a/lib/libc/csu/aarch64/reloc.c b/lib/libc/csu/aarch64/reloc.c
index 7f5dff497fe2..ead48a8ad4fb 100644
--- a/lib/libc/csu/aarch64/reloc.c
+++ b/lib/libc/csu/aarch64/reloc.c
@@ -1,44 +1,43 @@
/*-
* Copyright (c) 2019 Leandro Lupori
* Copyright (c) 2021 The FreeBSD Foundation
*
* Portions of this software were developed by Andrew Turner
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
static void
crt1_handle_rela(const Elf_Rela *r)
{
typedef Elf_Addr (*ifunc_resolver_t)(
uint64_t, uint64_t, uint64_t, uint64_t,
uint64_t, uint64_t, uint64_t, uint64_t);
Elf_Addr *ptr, *where, target;
switch (ELF_R_TYPE(r->r_info)) {
case R_AARCH64_IRELATIVE:
ptr = (Elf_Addr *)r->r_addend;
where = (Elf_Addr *)r->r_offset;
target = ((ifunc_resolver_t)ptr)(0, 0, 0, 0, 0, 0, 0, 0);
*where = target;
break;
}
}
diff --git a/lib/libc/csu/amd64/reloc.c b/lib/libc/csu/amd64/reloc.c
index 654958819271..6424d69fbd5c 100644
--- a/lib/libc/csu/amd64/reloc.c
+++ b/lib/libc/csu/amd64/reloc.c
@@ -1,67 +1,66 @@
/*-
* Copyright (c) 2018 The FreeBSD Foundation
*
* This software was developed by Konstantin Belousov <kib@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/specialreg.h>
#include <machine/cpufunc.h>
static uint32_t cpu_feature, cpu_feature2;
static uint32_t cpu_stdext_feature, cpu_stdext_feature2;
static void
init_cpu_features(void)
{
u_int p[4];
do_cpuid(1, p);
cpu_feature = p[3];
cpu_feature2 = p[2];
do_cpuid(0, p);
if (p[0] >= 7) {
cpuid_count(7, 0, p);
cpu_stdext_feature = p[1];
cpu_stdext_feature2 = p[2];
} else {
cpu_stdext_feature = 0;
cpu_stdext_feature2 = 0;
}
}
static void
crt1_handle_rela(const Elf_Rela *r)
{
Elf_Addr *ptr, *where, target;
switch (ELF_R_TYPE(r->r_info)) {
case R_X86_64_IRELATIVE:
ptr = (Elf_Addr *)r->r_addend;
where = (Elf_Addr *)r->r_offset;
target = ((Elf_Addr (*)(uint32_t, uint32_t, uint32_t,
uint32_t))ptr)(cpu_feature, cpu_feature2,
cpu_stdext_feature, cpu_stdext_feature2);
*where = target;
break;
}
}
diff --git a/lib/libc/csu/i386/reloc.c b/lib/libc/csu/i386/reloc.c
index d617f35dc665..1c9ec173facc 100644
--- a/lib/libc/csu/i386/reloc.c
+++ b/lib/libc/csu/i386/reloc.c
@@ -1,89 +1,88 @@
/*-
* Copyright (c) 2018 The FreeBSD Foundation
*
* This software was developed by Konstantin Belousov <kib@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/specialreg.h>
#include <machine/cpufunc.h>
static uint32_t cpu_feature, cpu_feature2;
static uint32_t cpu_stdext_feature, cpu_stdext_feature2;
static void
init_cpu_features(void)
{
u_int cpuid_supported, p[4];
__asm __volatile(
" pushfl\n"
" popl %%eax\n"
" movl %%eax,%%ecx\n"
" xorl $0x200000,%%eax\n"
" pushl %%eax\n"
" popfl\n"
" pushfl\n"
" popl %%eax\n"
" xorl %%eax,%%ecx\n"
" je 1f\n"
" movl $1,%0\n"
" jmp 2f\n"
"1: movl $0,%0\n"
"2:\n"
: "=r" (cpuid_supported) : : "eax", "ecx", "cc");
if (cpuid_supported) {
do_cpuid(1, p);
cpu_feature = p[3];
cpu_feature2 = p[2];
do_cpuid(0, p);
if (p[0] >= 7) {
cpuid_count(7, 0, p);
cpu_stdext_feature = p[1];
cpu_stdext_feature2 = p[2];
} else {
cpu_stdext_feature = 0;
cpu_stdext_feature2 = 0;
}
} else {
cpu_feature = 0;
cpu_feature2 = 0;
cpu_stdext_feature = 0;
cpu_stdext_feature2 = 0;
}
}
static void
crt1_handle_rel(const Elf_Rel *r)
{
Elf_Addr *where, target;
switch (ELF_R_TYPE(r->r_info)) {
case R_386_IRELATIVE:
where = (Elf_Addr *)r->r_offset;
target = ((Elf_Addr (*)(uint32_t, uint32_t, uint32_t,
uint32_t))*where)(cpu_feature, cpu_feature2,
cpu_stdext_feature, cpu_stdext_feature2);
*where = target;
break;
}
}
diff --git a/lib/libc/csu/powerpc64/reloc.c b/lib/libc/csu/powerpc64/reloc.c
index 6201ba0f1fb5..41419bf0e6c2 100644
--- a/lib/libc/csu/powerpc64/reloc.c
+++ b/lib/libc/csu/powerpc64/reloc.c
@@ -1,67 +1,66 @@
/*-
* Copyright (c) 2019 Leandro Lupori
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
static uint32_t cpu_features;
static uint32_t cpu_features2;
static void
init_cpu_features(char **env)
{
const Elf_Auxinfo *aux;
/* Find the auxiliary vector on the stack. */
while (*env++ != 0) /* Skip over environment, and NULL terminator */
;
aux = (const Elf_Auxinfo *)env;
/* Digest the auxiliary vector. */
for (; aux->a_type != AT_NULL; aux++) {
switch (aux->a_type) {
case AT_HWCAP:
cpu_features = (uint32_t)aux->a_un.a_val;
break;
case AT_HWCAP2:
cpu_features2 = (uint32_t)aux->a_un.a_val;
break;
}
}
}
static void
crt1_handle_rela(const Elf_Rela *r)
{
typedef Elf_Addr (*ifunc_resolver_t)(
uint32_t, uint32_t, uint64_t, uint64_t,
uint64_t, uint64_t, uint64_t, uint64_t);
Elf_Addr *ptr, *where, target;
switch (ELF_R_TYPE(r->r_info)) {
case R_PPC_IRELATIVE:
ptr = (Elf_Addr *)r->r_addend;
where = (Elf_Addr *)r->r_offset;
target = ((ifunc_resolver_t)ptr)(cpu_features, cpu_features2,
0, 0, 0, 0, 0, 0);
*where = target;
break;
}
}
diff --git a/lib/libc/db/btree/bt_close.c b/lib/libc/db/btree/bt_close.c
index 1378e45a77e4..8b770639bf6f 100644
--- a/lib/libc/db/btree/bt_close.c
+++ b/lib/libc/db/btree/bt_close.c
@@ -1,179 +1,178 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_close.c 8.7 (Berkeley) 8/17/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include <db.h>
#include "btree.h"
static int bt_meta(BTREE *);
/*
* BT_CLOSE -- Close a btree.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__bt_close(DB *dbp)
{
BTREE *t;
int fd;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Sync the tree. */
if (__bt_sync(dbp, 0) == RET_ERROR)
return (RET_ERROR);
/* Close the memory pool. */
if (mpool_close(t->bt_mp) == RET_ERROR)
return (RET_ERROR);
/* Free random memory. */
if (t->bt_cursor.key.data != NULL) {
free(t->bt_cursor.key.data);
t->bt_cursor.key.size = 0;
t->bt_cursor.key.data = NULL;
}
if (t->bt_rkey.data) {
free(t->bt_rkey.data);
t->bt_rkey.size = 0;
t->bt_rkey.data = NULL;
}
if (t->bt_rdata.data) {
free(t->bt_rdata.data);
t->bt_rdata.size = 0;
t->bt_rdata.data = NULL;
}
fd = t->bt_fd;
free(t);
free(dbp);
return (_close(fd) ? RET_ERROR : RET_SUCCESS);
}
/*
* BT_SYNC -- sync the btree to disk.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__bt_sync(const DB *dbp, u_int flags)
{
BTREE *t;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Sync doesn't currently take any flags. */
if (flags != 0) {
errno = EINVAL;
return (RET_ERROR);
}
if (F_ISSET(t, B_INMEM | B_RDONLY) ||
!F_ISSET(t, B_MODIFIED | B_METADIRTY))
return (RET_SUCCESS);
if (F_ISSET(t, B_METADIRTY) && bt_meta(t) == RET_ERROR)
return (RET_ERROR);
if ((status = mpool_sync(t->bt_mp)) == RET_SUCCESS)
F_CLR(t, B_MODIFIED);
return (status);
}
/*
* BT_META -- write the tree meta data to disk.
*
* Parameters:
* t: tree
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
bt_meta(BTREE *t)
{
BTMETA m;
void *p;
if ((p = mpool_get(t->bt_mp, P_META, 0)) == NULL)
return (RET_ERROR);
/* Fill in metadata. */
m.magic = BTREEMAGIC;
m.version = BTREEVERSION;
m.psize = t->bt_psize;
m.free = t->bt_free;
m.nrecs = t->bt_nrecs;
m.flags = F_ISSET(t, SAVEMETA);
memmove(p, &m, sizeof(BTMETA));
mpool_put(t->bt_mp, p, MPOOL_DIRTY);
return (RET_SUCCESS);
}
diff --git a/lib/libc/db/btree/bt_conv.c b/lib/libc/db/btree/bt_conv.c
index 5b3f166dff9a..280a80b70a8a 100644
--- a/lib/libc/db/btree/bt_conv.c
+++ b/lib/libc/db/btree/bt_conv.c
@@ -1,212 +1,211 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_conv.c 8.5 (Berkeley) 8/17/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdio.h>
#include <db.h>
#include "btree.h"
static void mswap(PAGE *);
/*
* __BT_BPGIN, __BT_BPGOUT --
* Convert host-specific number layout to/from the host-independent
* format stored on disk.
*
* Parameters:
* t: tree
* pg: page number
* h: page to convert
*/
void
__bt_pgin(void *t, pgno_t pg, void *pp)
{
PAGE *h;
indx_t i, top;
u_char flags;
char *p;
if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
return;
if (pg == P_META) {
mswap(pp);
return;
}
h = pp;
M_32_SWAP(h->pgno);
M_32_SWAP(h->prevpg);
M_32_SWAP(h->nextpg);
M_32_SWAP(h->flags);
M_16_SWAP(h->lower);
M_16_SWAP(h->upper);
top = NEXTINDEX(h);
if ((h->flags & P_TYPE) == P_BINTERNAL)
for (i = 0; i < top; i++) {
M_16_SWAP(h->linp[i]);
p = (char *)GETBINTERNAL(h, i);
P_32_SWAP(p);
p += sizeof(u_int32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
if (*(u_char *)p & P_BIGKEY) {
p += sizeof(u_char);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
}
else if ((h->flags & P_TYPE) == P_BLEAF)
for (i = 0; i < top; i++) {
M_16_SWAP(h->linp[i]);
p = (char *)GETBLEAF(h, i);
P_32_SWAP(p);
p += sizeof(u_int32_t);
P_32_SWAP(p);
p += sizeof(u_int32_t);
flags = *(u_char *)p;
if (flags & (P_BIGKEY | P_BIGDATA)) {
p += sizeof(u_char);
if (flags & P_BIGKEY) {
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
if (flags & P_BIGDATA) {
p += sizeof(u_int32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
}
}
}
void
__bt_pgout(void *t, pgno_t pg, void *pp)
{
PAGE *h;
indx_t i, top;
u_char flags;
char *p;
if (!F_ISSET(((BTREE *)t), B_NEEDSWAP))
return;
if (pg == P_META) {
mswap(pp);
return;
}
h = pp;
top = NEXTINDEX(h);
if ((h->flags & P_TYPE) == P_BINTERNAL)
for (i = 0; i < top; i++) {
p = (char *)GETBINTERNAL(h, i);
P_32_SWAP(p);
p += sizeof(u_int32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
if (*(u_char *)p & P_BIGKEY) {
p += sizeof(u_char);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
M_16_SWAP(h->linp[i]);
}
else if ((h->flags & P_TYPE) == P_BLEAF)
for (i = 0; i < top; i++) {
p = (char *)GETBLEAF(h, i);
P_32_SWAP(p);
p += sizeof(u_int32_t);
P_32_SWAP(p);
p += sizeof(u_int32_t);
flags = *(u_char *)p;
if (flags & (P_BIGKEY | P_BIGDATA)) {
p += sizeof(u_char);
if (flags & P_BIGKEY) {
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
if (flags & P_BIGDATA) {
p += sizeof(u_int32_t);
P_32_SWAP(p);
p += sizeof(pgno_t);
P_32_SWAP(p);
}
}
M_16_SWAP(h->linp[i]);
}
M_32_SWAP(h->pgno);
M_32_SWAP(h->prevpg);
M_32_SWAP(h->nextpg);
M_32_SWAP(h->flags);
M_16_SWAP(h->lower);
M_16_SWAP(h->upper);
}
/*
* MSWAP -- Actually swap the bytes on the meta page.
*
* Parameters:
* p: page to convert
*/
static void
mswap(PAGE *pg)
{
char *p;
p = (char *)pg;
P_32_SWAP(p); /* magic */
p += sizeof(u_int32_t);
P_32_SWAP(p); /* version */
p += sizeof(u_int32_t);
P_32_SWAP(p); /* psize */
p += sizeof(u_int32_t);
P_32_SWAP(p); /* free */
p += sizeof(u_int32_t);
P_32_SWAP(p); /* nrecs */
p += sizeof(u_int32_t);
P_32_SWAP(p); /* flags */
p += sizeof(u_int32_t);
}
diff --git a/lib/libc/db/btree/bt_debug.c b/lib/libc/db/btree/bt_debug.c
index 50f1294a9603..6ad20c95b7bd 100644
--- a/lib/libc/db/btree/bt_debug.c
+++ b/lib/libc/db/btree/bt_debug.c
@@ -1,316 +1,315 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_debug.c 8.5 (Berkeley) 8/17/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "btree.h"
#ifdef DEBUG
/*
* BT_DUMP -- Dump the tree
*
* Parameters:
* dbp: pointer to the DB
*/
void
__bt_dump(DB *dbp)
{
BTREE *t;
PAGE *h;
pgno_t i;
char *sep;
t = dbp->internal;
(void)fprintf(stderr, "%s: pgsz %u",
F_ISSET(t, B_INMEM) ? "memory" : "disk", t->bt_psize);
if (F_ISSET(t, R_RECNO))
(void)fprintf(stderr, " keys %u", t->bt_nrecs);
#undef X
#define X(flag, name) \
if (F_ISSET(t, flag)) { \
(void)fprintf(stderr, "%s%s", sep, name); \
sep = ", "; \
}
if (t->flags != 0) {
sep = " flags (";
X(R_FIXLEN, "FIXLEN");
X(B_INMEM, "INMEM");
X(B_NODUPS, "NODUPS");
X(B_RDONLY, "RDONLY");
X(R_RECNO, "RECNO");
X(B_METADIRTY,"METADIRTY");
(void)fprintf(stderr, ")\n");
}
#undef X
for (i = P_ROOT;
(h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
__bt_dpage(h);
}
/*
* BT_DMPAGE -- Dump the meta page
*
* Parameters:
* h: pointer to the PAGE
*/
void
__bt_dmpage(PAGE *h)
{
BTMETA *m;
char *sep;
m = (BTMETA *)h;
(void)fprintf(stderr, "magic %x\n", m->magic);
(void)fprintf(stderr, "version %u\n", m->version);
(void)fprintf(stderr, "psize %u\n", m->psize);
(void)fprintf(stderr, "free %u\n", m->free);
(void)fprintf(stderr, "nrecs %u\n", m->nrecs);
(void)fprintf(stderr, "flags %u", m->flags);
#undef X
#define X(flag, name) \
if (m->flags & flag) { \
(void)fprintf(stderr, "%s%s", sep, name); \
sep = ", "; \
}
if (m->flags) {
sep = " (";
X(B_NODUPS, "NODUPS");
X(R_RECNO, "RECNO");
(void)fprintf(stderr, ")");
}
}
/*
* BT_DNPAGE -- Dump the page
*
* Parameters:
* n: page number to dump.
*/
void
__bt_dnpage(DB *dbp, pgno_t pgno)
{
BTREE *t;
PAGE *h;
t = dbp->internal;
if ((h = mpool_get(t->bt_mp, pgno, MPOOL_IGNOREPIN)) != NULL)
__bt_dpage(h);
}
/*
* BT_DPAGE -- Dump the page
*
* Parameters:
* h: pointer to the PAGE
*/
void
__bt_dpage(PAGE *h)
{
BINTERNAL *bi;
BLEAF *bl;
RINTERNAL *ri;
RLEAF *rl;
indx_t cur, top;
char *sep;
(void)fprintf(stderr, " page %u: (", h->pgno);
#undef X
#define X(flag, name) \
if (h->flags & flag) { \
(void)fprintf(stderr, "%s%s", sep, name); \
sep = ", "; \
}
sep = "";
X(P_BINTERNAL, "BINTERNAL") /* types */
X(P_BLEAF, "BLEAF")
X(P_RINTERNAL, "RINTERNAL") /* types */
X(P_RLEAF, "RLEAF")
X(P_OVERFLOW, "OVERFLOW")
X(P_PRESERVE, "PRESERVE");
(void)fprintf(stderr, ")\n");
#undef X
(void)fprintf(stderr, "\tprev %2u next %2u", h->prevpg, h->nextpg);
if (h->flags & P_OVERFLOW)
return;
top = NEXTINDEX(h);
(void)fprintf(stderr, " lower %3d upper %3d nextind %d\n",
h->lower, h->upper, top);
for (cur = 0; cur < top; cur++) {
(void)fprintf(stderr, "\t[%03d] %4d ", cur, h->linp[cur]);
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
bi = GETBINTERNAL(h, cur);
(void)fprintf(stderr,
"size %03d pgno %03d", bi->ksize, bi->pgno);
if (bi->flags & P_BIGKEY)
(void)fprintf(stderr, " (indirect)");
else if (bi->ksize)
(void)fprintf(stderr,
" {%.*s}", (int)bi->ksize, bi->bytes);
break;
case P_RINTERNAL:
ri = GETRINTERNAL(h, cur);
(void)fprintf(stderr, "entries %03d pgno %03d",
ri->nrecs, ri->pgno);
break;
case P_BLEAF:
bl = GETBLEAF(h, cur);
if (bl->flags & P_BIGKEY)
(void)fprintf(stderr,
"big key page %u size %u/",
*(pgno_t *)bl->bytes,
*(u_int32_t *)(bl->bytes + sizeof(pgno_t)));
else if (bl->ksize)
(void)fprintf(stderr, "%.*s/",
bl->ksize, bl->bytes);
if (bl->flags & P_BIGDATA)
(void)fprintf(stderr,
"big data page %u size %u",
*(pgno_t *)(bl->bytes + bl->ksize),
*(u_int32_t *)(bl->bytes + bl->ksize +
sizeof(pgno_t)));
else if (bl->dsize)
(void)fprintf(stderr, "%.*s",
(int)bl->dsize, bl->bytes + bl->ksize);
break;
case P_RLEAF:
rl = GETRLEAF(h, cur);
if (rl->flags & P_BIGDATA)
(void)fprintf(stderr,
"big data page %u size %u",
*(pgno_t *)rl->bytes,
*(u_int32_t *)(rl->bytes + sizeof(pgno_t)));
else if (rl->dsize)
(void)fprintf(stderr,
"%.*s", (int)rl->dsize, rl->bytes);
break;
}
(void)fprintf(stderr, "\n");
}
}
#endif
#ifdef STATISTICS
/*
* BT_STAT -- Gather/print the tree statistics
*
* Parameters:
* dbp: pointer to the DB
*/
void
__bt_stat(DB *dbp)
{
extern u_long bt_cache_hit, bt_cache_miss, bt_pfxsaved, bt_rootsplit;
extern u_long bt_sortsplit, bt_split;
BTREE *t;
PAGE *h;
pgno_t i, pcont, pinternal, pleaf;
u_long ifree, lfree, nkeys;
int levels;
t = dbp->internal;
pcont = pinternal = pleaf = 0;
nkeys = ifree = lfree = 0;
for (i = P_ROOT;
(h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN)) != NULL; ++i)
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
case P_RINTERNAL:
++pinternal;
ifree += h->upper - h->lower;
break;
case P_BLEAF:
case P_RLEAF:
++pleaf;
lfree += h->upper - h->lower;
nkeys += NEXTINDEX(h);
break;
case P_OVERFLOW:
++pcont;
break;
}
/* Count the levels of the tree. */
for (i = P_ROOT, levels = 0 ;; ++levels) {
h = mpool_get(t->bt_mp, i, MPOOL_IGNOREPIN);
if (h->flags & (P_BLEAF|P_RLEAF)) {
if (levels == 0)
levels = 1;
break;
}
i = F_ISSET(t, R_RECNO) ?
GETRINTERNAL(h, 0)->pgno :
GETBINTERNAL(h, 0)->pgno;
}
(void)fprintf(stderr, "%d level%s with %lu keys",
levels, levels == 1 ? "" : "s", nkeys);
if (F_ISSET(t, R_RECNO))
(void)fprintf(stderr, " (%u header count)", t->bt_nrecs);
(void)fprintf(stderr,
"\n%u pages (leaf %u, internal %u, overflow %u)\n",
pinternal + pleaf + pcont, pleaf, pinternal, pcont);
(void)fprintf(stderr, "%lu cache hits, %lu cache misses\n",
bt_cache_hit, bt_cache_miss);
(void)fprintf(stderr, "%lu splits (%lu root splits, %lu sort splits)\n",
bt_split, bt_rootsplit, bt_sortsplit);
pleaf *= t->bt_psize - BTDATAOFF;
if (pleaf)
(void)fprintf(stderr,
"%.0f%% leaf fill (%lu bytes used, %lu bytes free)\n",
((double)(pleaf - lfree) / pleaf) * 100,
pleaf - lfree, lfree);
pinternal *= t->bt_psize - BTDATAOFF;
if (pinternal)
(void)fprintf(stderr,
"%.0f%% internal fill (%lu bytes used, %lu bytes free\n",
((double)(pinternal - ifree) / pinternal) * 100,
pinternal - ifree, ifree);
if (bt_pfxsaved)
(void)fprintf(stderr, "prefix checking removed %lu bytes.\n",
bt_pfxsaved);
}
#endif
diff --git a/lib/libc/db/btree/bt_delete.c b/lib/libc/db/btree/bt_delete.c
index fc122165a335..e96d933ba961 100644
--- a/lib/libc/db/btree/bt_delete.c
+++ b/lib/libc/db/btree/bt_delete.c
@@ -1,635 +1,634 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_delete.c 8.13 (Berkeley) 7/28/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <db.h>
#include "btree.h"
static int __bt_bdelete(BTREE *, const DBT *);
static int __bt_curdel(BTREE *, const DBT *, PAGE *, u_int);
static int __bt_pdelete(BTREE *, PAGE *);
static int __bt_relink(BTREE *, PAGE *);
static int __bt_stkacq(BTREE *, PAGE **, CURSOR *);
/*
* __bt_delete
* Delete the item(s) referenced by a key.
*
* Return RET_SPECIAL if the key is not found.
*/
int
__bt_delete(const DB *dbp, const DBT *key, u_int flags)
{
BTREE *t;
CURSOR *c;
PAGE *h;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Check for change to a read-only tree. */
if (F_ISSET(t, B_RDONLY)) {
errno = EPERM;
return (RET_ERROR);
}
switch (flags) {
case 0:
status = __bt_bdelete(t, key);
break;
case R_CURSOR:
/*
* If flags is R_CURSOR, delete the cursor. Must already
* have started a scan and not have already deleted it.
*/
c = &t->bt_cursor;
if (F_ISSET(c, CURS_INIT)) {
if (F_ISSET(c, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
return (RET_ERROR);
/*
* If the page is about to be emptied, we'll need to
* delete it, which means we have to acquire a stack.
*/
if (NEXTINDEX(h) == 1)
if (__bt_stkacq(t, &h, &t->bt_cursor))
return (RET_ERROR);
status = __bt_dleaf(t, NULL, h, c->pg.index);
if (NEXTINDEX(h) == 0 && status == RET_SUCCESS) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
} else
mpool_put(t->bt_mp,
h, status == RET_SUCCESS ? MPOOL_DIRTY : 0);
break;
}
/* FALLTHROUGH */
default:
errno = EINVAL;
return (RET_ERROR);
}
if (status == RET_SUCCESS)
F_SET(t, B_MODIFIED);
return (status);
}
/*
* __bt_stkacq --
* Acquire a stack so we can delete a cursor entry.
*
* Parameters:
* t: tree
* hp: pointer to current, pinned PAGE pointer
* c: pointer to the cursor
*
* Returns:
* 0 on success, 1 on failure
*/
static int
__bt_stkacq(BTREE *t, PAGE **hp, CURSOR *c)
{
BINTERNAL *bi;
EPG *e;
EPGNO *parent;
PAGE *h;
indx_t idx;
pgno_t pgno;
recno_t nextpg, prevpg;
int exact, level;
/*
* Find the first occurrence of the key in the tree. Toss the
* currently locked page so we don't hit an already-locked page.
*/
h = *hp;
mpool_put(t->bt_mp, h, 0);
if ((e = __bt_search(t, &c->key, &exact)) == NULL)
return (1);
h = e->page;
/* See if we got it in one shot. */
if (h->pgno == c->pg.pgno)
goto ret;
/*
* Move right, looking for the page. At each move we have to move
* up the stack until we don't have to move to the next page. If
* we have to change pages at an internal level, we have to fix the
* stack back up.
*/
while (h->pgno != c->pg.pgno) {
if ((nextpg = h->nextpg) == P_INVALID)
break;
mpool_put(t->bt_mp, h, 0);
/* Move up the stack. */
for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
/* Get the parent page. */
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (1);
/* Move to the next index. */
if (parent->index != NEXTINDEX(h) - 1) {
idx = parent->index + 1;
BT_PUSH(t, h->pgno, idx);
break;
}
mpool_put(t->bt_mp, h, 0);
}
/* Restore the stack. */
while (level--) {
/* Push the next level down onto the stack. */
bi = GETBINTERNAL(h, idx);
pgno = bi->pgno;
BT_PUSH(t, pgno, 0);
/* Lose the currently pinned page. */
mpool_put(t->bt_mp, h, 0);
/* Get the next level down. */
if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
return (1);
idx = 0;
}
mpool_put(t->bt_mp, h, 0);
if ((h = mpool_get(t->bt_mp, nextpg, 0)) == NULL)
return (1);
}
if (h->pgno == c->pg.pgno)
goto ret;
/* Reacquire the original stack. */
mpool_put(t->bt_mp, h, 0);
if ((e = __bt_search(t, &c->key, &exact)) == NULL)
return (1);
h = e->page;
/*
* Move left, looking for the page. At each move we have to move
* up the stack until we don't have to change pages to move to the
* next page. If we have to change pages at an internal level, we
* have to fix the stack back up.
*/
while (h->pgno != c->pg.pgno) {
if ((prevpg = h->prevpg) == P_INVALID)
break;
mpool_put(t->bt_mp, h, 0);
/* Move up the stack. */
for (level = 0; (parent = BT_POP(t)) != NULL; ++level) {
/* Get the parent page. */
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (1);
/* Move to the next index. */
if (parent->index != 0) {
idx = parent->index - 1;
BT_PUSH(t, h->pgno, idx);
break;
}
mpool_put(t->bt_mp, h, 0);
}
/* Restore the stack. */
while (level--) {
/* Push the next level down onto the stack. */
bi = GETBINTERNAL(h, idx);
pgno = bi->pgno;
/* Lose the currently pinned page. */
mpool_put(t->bt_mp, h, 0);
/* Get the next level down. */
if ((h = mpool_get(t->bt_mp, pgno, 0)) == NULL)
return (1);
idx = NEXTINDEX(h) - 1;
BT_PUSH(t, pgno, idx);
}
mpool_put(t->bt_mp, h, 0);
if ((h = mpool_get(t->bt_mp, prevpg, 0)) == NULL)
return (1);
}
ret: mpool_put(t->bt_mp, h, 0);
return ((*hp = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL);
}
/*
* __bt_bdelete --
* Delete all key/data pairs matching the specified key.
*
* Parameters:
* t: tree
* key: key to delete
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
static int
__bt_bdelete(BTREE *t, const DBT *key)
{
EPG *e;
PAGE *h;
int deleted, exact, redo;
deleted = 0;
/* Find any matching record; __bt_search pins the page. */
loop: if ((e = __bt_search(t, key, &exact)) == NULL)
return (deleted ? RET_SUCCESS : RET_ERROR);
if (!exact) {
mpool_put(t->bt_mp, e->page, 0);
return (deleted ? RET_SUCCESS : RET_SPECIAL);
}
/*
* Delete forward, then delete backward, from the found key. If
* there are duplicates and we reach either side of the page, do
* the key search again, so that we get them all.
*/
redo = 0;
h = e->page;
do {
if (__bt_dleaf(t, key, h, e->index)) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
if (F_ISSET(t, B_NODUPS)) {
if (NEXTINDEX(h) == 0) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
} else
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
deleted = 1;
} while (e->index < NEXTINDEX(h) && __bt_cmp(t, key, e) == 0);
/* Check for right-hand edge of the page. */
if (e->index == NEXTINDEX(h))
redo = 1;
/* Delete from the key to the beginning of the page. */
while (e->index-- > 0) {
if (__bt_cmp(t, key, e) != 0)
break;
if (__bt_dleaf(t, key, h, e->index) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
if (e->index == 0)
redo = 1;
}
/* Check for an empty page. */
if (NEXTINDEX(h) == 0) {
if (__bt_pdelete(t, h))
return (RET_ERROR);
goto loop;
}
/* Put the page. */
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
if (redo)
goto loop;
return (RET_SUCCESS);
}
/*
* __bt_pdelete --
* Delete a single page from the tree.
*
* Parameters:
* t: tree
* h: leaf page
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*
* Side-effects:
* mpool_put's the page
*/
static int
__bt_pdelete(BTREE *t, PAGE *h)
{
BINTERNAL *bi;
PAGE *pg;
EPGNO *parent;
indx_t cnt, idx, *ip, offset;
u_int32_t nksize;
char *from;
/*
* Walk the parent page stack -- a LIFO stack of the pages that were
* traversed when we searched for the page where the delete occurred.
* Each stack entry is a page number and a page index offset. The
* offset is for the page traversed on the search. We've just deleted
* a page, so we have to delete the key from the parent page.
*
* If the delete from the parent page makes it empty, this process may
* continue all the way up the tree. We stop if we reach the root page
* (which is never deleted, it's just not worth the effort) or if the
* delete does not empty the page.
*/
while ((parent = BT_POP(t)) != NULL) {
/* Get the parent page. */
if ((pg = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
return (RET_ERROR);
idx = parent->index;
bi = GETBINTERNAL(pg, idx);
/* Free any overflow pages. */
if (bi->flags & P_BIGKEY &&
__ovfl_delete(t, bi->bytes) == RET_ERROR) {
mpool_put(t->bt_mp, pg, 0);
return (RET_ERROR);
}
/*
* Free the parent if it has only the one key and it's not the
* root page. If it's the rootpage, turn it back into an empty
* leaf page.
*/
if (NEXTINDEX(pg) == 1) {
if (pg->pgno == P_ROOT) {
pg->lower = BTDATAOFF;
pg->upper = t->bt_psize;
pg->flags = P_BLEAF;
} else {
if (__bt_relink(t, pg) || __bt_free(t, pg))
return (RET_ERROR);
continue;
}
} else {
/* Pack remaining key items at the end of the page. */
nksize = NBINTERNAL(bi->ksize);
from = (char *)pg + pg->upper;
memmove(from + nksize, from, (char *)bi - from);
pg->upper += nksize;
/* Adjust indices' offsets, shift the indices down. */
offset = pg->linp[idx];
for (cnt = idx, ip = &pg->linp[0]; cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nksize;
for (cnt = NEXTINDEX(pg) - idx; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nksize : ip[1];
pg->lower -= sizeof(indx_t);
}
mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
break;
}
/* Free the leaf page, as long as it wasn't the root. */
if (h->pgno == P_ROOT) {
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
return (__bt_relink(t, h) || __bt_free(t, h));
}
/*
* __bt_dleaf --
* Delete a single record from a leaf page.
*
* Parameters:
* t: tree
* key: referenced key
* h: page
* idx: index on page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__bt_dleaf(BTREE *t, const DBT *key, PAGE *h, u_int idx)
{
BLEAF *bl;
indx_t cnt, *ip, offset;
u_int32_t nbytes;
void *to;
char *from;
/* If this record is referenced by the cursor, delete the cursor. */
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index == idx &&
__bt_curdel(t, key, h, idx))
return (RET_ERROR);
/* If the entry uses overflow pages, make them available for reuse. */
to = bl = GETBLEAF(h, idx);
if (bl->flags & P_BIGKEY && __ovfl_delete(t, bl->bytes) == RET_ERROR)
return (RET_ERROR);
if (bl->flags & P_BIGDATA &&
__ovfl_delete(t, bl->bytes + bl->ksize) == RET_ERROR)
return (RET_ERROR);
/* Pack the remaining key/data items at the end of the page. */
nbytes = NBLEAF(bl);
from = (char *)h + h->upper;
memmove(from + nbytes, from, (char *)to - from);
h->upper += nbytes;
/* Adjust the indices' offsets, shift the indices down. */
offset = h->linp[idx];
for (cnt = idx, ip = &h->linp[0]; cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nbytes;
for (cnt = NEXTINDEX(h) - idx; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
h->lower -= sizeof(indx_t);
/* If the cursor is on this page, adjust it as necessary. */
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index > idx)
--t->bt_cursor.pg.index;
return (RET_SUCCESS);
}
/*
* __bt_curdel --
* Delete the cursor.
*
* Parameters:
* t: tree
* key: referenced key (or NULL)
* h: page
* idx: index on page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
static int
__bt_curdel(BTREE *t, const DBT *key, PAGE *h, u_int idx)
{
CURSOR *c;
EPG e;
PAGE *pg;
int curcopy, status;
/*
* If there are duplicates, move forward or backward to one.
* Otherwise, copy the key into the cursor area.
*/
c = &t->bt_cursor;
F_CLR(c, CURS_AFTER | CURS_BEFORE | CURS_ACQUIRE);
curcopy = 0;
if (!F_ISSET(t, B_NODUPS)) {
/*
* We're going to have to do comparisons. If we weren't
* provided a copy of the key, i.e. the user is deleting
* the current cursor position, get one.
*/
if (key == NULL) {
e.page = h;
e.index = idx;
if ((status = __bt_ret(t, &e,
&c->key, &c->key, NULL, NULL, 1)) != RET_SUCCESS)
return (status);
curcopy = 1;
key = &c->key;
}
/* Check previous key, if not at the beginning of the page. */
if (idx > 0) {
e.page = h;
e.index = idx - 1;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_BEFORE);
goto dup2;
}
}
/* Check next key, if not at the end of the page. */
if (idx < NEXTINDEX(h) - 1) {
e.page = h;
e.index = idx + 1;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_AFTER);
goto dup2;
}
}
/* Check previous key if at the beginning of the page. */
if (idx == 0 && h->prevpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
return (RET_ERROR);
e.page = pg;
e.index = NEXTINDEX(pg) - 1;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_BEFORE);
goto dup1;
}
mpool_put(t->bt_mp, pg, 0);
}
/* Check next key if at the end of the page. */
if (idx == NEXTINDEX(h) - 1 && h->nextpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
return (RET_ERROR);
e.page = pg;
e.index = 0;
if (__bt_cmp(t, key, &e) == 0) {
F_SET(c, CURS_AFTER);
dup1: mpool_put(t->bt_mp, pg, 0);
dup2: c->pg.pgno = e.page->pgno;
c->pg.index = e.index;
return (RET_SUCCESS);
}
mpool_put(t->bt_mp, pg, 0);
}
}
e.page = h;
e.index = idx;
if (curcopy || (status =
__bt_ret(t, &e, &c->key, &c->key, NULL, NULL, 1)) == RET_SUCCESS) {
F_SET(c, CURS_ACQUIRE);
return (RET_SUCCESS);
}
return (status);
}
/*
* __bt_relink --
* Link around a deleted page.
*
* Parameters:
* t: tree
* h: page to be deleted
*/
static int
__bt_relink(BTREE *t, PAGE *h)
{
PAGE *pg;
if (h->nextpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
return (RET_ERROR);
pg->prevpg = h->prevpg;
mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
}
if (h->prevpg != P_INVALID) {
if ((pg = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
return (RET_ERROR);
pg->nextpg = h->nextpg;
mpool_put(t->bt_mp, pg, MPOOL_DIRTY);
}
return (0);
}
diff --git a/lib/libc/db/btree/bt_get.c b/lib/libc/db/btree/bt_get.c
index 3a0f9f72d92c..d91bba5a9014 100644
--- a/lib/libc/db/btree/bt_get.c
+++ b/lib/libc/db/btree/bt_get.c
@@ -1,99 +1,98 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_get.c 8.6 (Berkeley) 7/20/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <db.h>
#include "btree.h"
/*
* __BT_GET -- Get a record from the btree.
*
* Parameters:
* dbp: pointer to access method
* key: key to find
* data: data to return
* flag: currently unused
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
int
__bt_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
{
BTREE *t;
EPG *e;
int exact, status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Get currently doesn't take any flags. */
if (flags) {
errno = EINVAL;
return (RET_ERROR);
}
if ((e = __bt_search(t, key, &exact)) == NULL)
return (RET_ERROR);
if (!exact) {
mpool_put(t->bt_mp, e->page, 0);
return (RET_SPECIAL);
}
status = __bt_ret(t, e, NULL, NULL, data, &t->bt_rdata, 0);
/*
* If the user is doing concurrent access, we copied the
* key/data, toss the page.
*/
if (F_ISSET(t, B_DB_LOCK))
mpool_put(t->bt_mp, e->page, 0);
else
t->bt_pinned = e->page;
return (status);
}
diff --git a/lib/libc/db/btree/bt_open.c b/lib/libc/db/btree/bt_open.c
index fcc3a9a9abb4..ed7c06eb24e8 100644
--- a/lib/libc/db/btree/bt_open.c
+++ b/lib/libc/db/btree/bt_open.c
@@ -1,448 +1,447 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_open.c 8.10 (Berkeley) 8/17/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* Implementation of btree access method for 4.4BSD.
*
* The design here was originally based on that of the btree access method
* used in the Postgres database system at UC Berkeley. This implementation
* is wholly independent of the Postgres code.
*/
#include "namespace.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
#include <db.h>
#include "btree.h"
#ifdef DEBUG
#undef MINPSIZE
#define MINPSIZE 128
#endif
static int byteorder(void);
static int nroot(BTREE *);
static int tmp(void);
/*
* __BT_OPEN -- Open a btree.
*
* Creates and fills a DB struct, and calls the routine that actually
* opens the btree.
*
* Parameters:
* fname: filename (NULL for in-memory trees)
* flags: open flag bits
* mode: open permission bits
* b: BTREEINFO pointer
*
* Returns:
* NULL on failure, pointer to DB on success.
*
*/
DB *
__bt_open(const char *fname, int flags, int mode, const BTREEINFO *openinfo, int dflags)
{
struct stat sb;
BTMETA m;
BTREE *t;
BTREEINFO b;
DB *dbp;
pgno_t ncache;
ssize_t nr;
int machine_lorder, saved_errno;
t = NULL;
/*
* Intention is to make sure all of the user's selections are okay
* here and then use them without checking. Can't be complete, since
* we don't know the right page size, lorder or flags until the backing
* file is opened. Also, the file's page size can cause the cachesize
* to change.
*/
machine_lorder = byteorder();
if (openinfo) {
b = *openinfo;
/* Flags: R_DUP. */
if (b.flags & ~(R_DUP))
goto einval;
/*
* Page size must be indx_t aligned and >= MINPSIZE. Default
* page size is set farther on, based on the underlying file
* transfer size.
*/
if (b.psize &&
(b.psize < MINPSIZE || b.psize > MAX_PAGE_OFFSET + 1 ||
b.psize & (sizeof(indx_t) - 1) ))
goto einval;
/* Minimum number of keys per page; absolute minimum is 2. */
if (b.minkeypage) {
if (b.minkeypage < 2)
goto einval;
} else
b.minkeypage = DEFMINKEYPAGE;
/* If no comparison, use default comparison and prefix. */
if (b.compare == NULL) {
b.compare = __bt_defcmp;
if (b.prefix == NULL)
b.prefix = __bt_defpfx;
}
if (b.lorder == 0)
b.lorder = machine_lorder;
} else {
b.compare = __bt_defcmp;
b.cachesize = 0;
b.flags = 0;
b.lorder = machine_lorder;
b.minkeypage = DEFMINKEYPAGE;
b.prefix = __bt_defpfx;
b.psize = 0;
}
/* Check for the ubiquitous PDP-11. */
if (b.lorder != BIG_ENDIAN && b.lorder != LITTLE_ENDIAN)
goto einval;
/* Allocate and initialize DB and BTREE structures. */
if ((t = (BTREE *)calloc(1, sizeof(BTREE))) == NULL)
goto err;
t->bt_fd = -1; /* Don't close unopened fd on error. */
t->bt_lorder = b.lorder;
t->bt_order = NOT;
t->bt_cmp = b.compare;
t->bt_pfx = b.prefix;
t->bt_rfd = -1;
if ((t->bt_dbp = dbp = (DB *)calloc(1, sizeof(DB))) == NULL)
goto err;
if (t->bt_lorder != machine_lorder)
F_SET(t, B_NEEDSWAP);
dbp->type = DB_BTREE;
dbp->internal = t;
dbp->close = __bt_close;
dbp->del = __bt_delete;
dbp->fd = __bt_fd;
dbp->get = __bt_get;
dbp->put = __bt_put;
dbp->seq = __bt_seq;
dbp->sync = __bt_sync;
/*
* If no file name was supplied, this is an in-memory btree and we
* open a backing temporary file. Otherwise, it's a disk-based tree.
*/
if (fname) {
switch (flags & O_ACCMODE) {
case O_RDONLY:
F_SET(t, B_RDONLY);
break;
case O_RDWR:
break;
case O_WRONLY:
default:
goto einval;
}
if ((t->bt_fd = _open(fname, flags | O_CLOEXEC, mode)) < 0)
goto err;
} else {
if ((flags & O_ACCMODE) != O_RDWR)
goto einval;
if ((t->bt_fd = tmp()) == -1)
goto err;
F_SET(t, B_INMEM);
}
if (_fstat(t->bt_fd, &sb))
goto err;
if (sb.st_size) {
if ((nr = _read(t->bt_fd, &m, sizeof(BTMETA))) < 0)
goto err;
if (nr != sizeof(BTMETA))
goto eftype;
/*
* Read in the meta-data. This can change the notion of what
* the lorder, page size and flags are, and, when the page size
* changes, the cachesize value can change too. If the user
* specified the wrong byte order for an existing database, we
* don't bother to return an error, we just clear the NEEDSWAP
* bit.
*/
if (m.magic == BTREEMAGIC)
F_CLR(t, B_NEEDSWAP);
else {
F_SET(t, B_NEEDSWAP);
M_32_SWAP(m.magic);
M_32_SWAP(m.version);
M_32_SWAP(m.psize);
M_32_SWAP(m.free);
M_32_SWAP(m.nrecs);
M_32_SWAP(m.flags);
}
if (m.magic != BTREEMAGIC || m.version != BTREEVERSION)
goto eftype;
if (m.psize < MINPSIZE || m.psize > MAX_PAGE_OFFSET + 1 ||
m.psize & (sizeof(indx_t) - 1) )
goto eftype;
if (m.flags & ~SAVEMETA)
goto eftype;
b.psize = m.psize;
F_SET(t, m.flags);
t->bt_free = m.free;
t->bt_nrecs = m.nrecs;
} else {
/*
* Set the page size to the best value for I/O to this file.
* Don't overflow the page offset type.
*/
if (b.psize == 0) {
b.psize = sb.st_blksize;
if (b.psize < MINPSIZE)
b.psize = MINPSIZE;
if (b.psize > MAX_PAGE_OFFSET + 1)
b.psize = MAX_PAGE_OFFSET + 1;
}
/* Set flag if duplicates permitted. */
if (!(b.flags & R_DUP))
F_SET(t, B_NODUPS);
t->bt_free = P_INVALID;
t->bt_nrecs = 0;
F_SET(t, B_METADIRTY);
}
t->bt_psize = b.psize;
/* Set the cache size; must be a multiple of the page size. */
if (b.cachesize && b.cachesize & (b.psize - 1) )
b.cachesize += (~b.cachesize & (b.psize - 1) ) + 1;
if (b.cachesize < b.psize * MINCACHE)
b.cachesize = b.psize * MINCACHE;
/* Calculate number of pages to cache. */
ncache = howmany(b.cachesize, t->bt_psize);
/*
* The btree data structure requires that at least two keys can fit on
* a page, but other than that there's no fixed requirement. The user
* specified a minimum number per page, and we translated that into the
* number of bytes a key/data pair can use before being placed on an
* overflow page. This calculation includes the page header, the size
* of the index referencing the leaf item and the size of the leaf item
* structure. Also, don't let the user specify a minkeypage such that
* a key/data pair won't fit even if both key and data are on overflow
* pages.
*/
t->bt_ovflsize = (t->bt_psize - BTDATAOFF) / b.minkeypage -
(sizeof(indx_t) + NBLEAFDBT(0, 0));
if (t->bt_ovflsize < NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t))
t->bt_ovflsize =
NBLEAFDBT(NOVFLSIZE, NOVFLSIZE) + sizeof(indx_t);
/* Initialize the buffer pool. */
if ((t->bt_mp =
mpool_open(NULL, t->bt_fd, t->bt_psize, ncache)) == NULL)
goto err;
if (!F_ISSET(t, B_INMEM))
mpool_filter(t->bt_mp, __bt_pgin, __bt_pgout, t);
/* Create a root page if new tree. */
if (nroot(t) == RET_ERROR)
goto err;
/* Global flags. */
if (dflags & DB_LOCK)
F_SET(t, B_DB_LOCK);
if (dflags & DB_SHMEM)
F_SET(t, B_DB_SHMEM);
if (dflags & DB_TXN)
F_SET(t, B_DB_TXN);
return (dbp);
einval: errno = EINVAL;
goto err;
eftype: errno = EFTYPE;
goto err;
err: saved_errno = errno;
if (t) {
if (t->bt_dbp)
free(t->bt_dbp);
if (t->bt_fd != -1)
(void)_close(t->bt_fd);
free(t);
}
errno = saved_errno;
return (NULL);
}
/*
* NROOT -- Create the root of a new tree.
*
* Parameters:
* t: tree
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
nroot(BTREE *t)
{
PAGE *meta, *root;
pgno_t npg;
if ((root = mpool_get(t->bt_mp, 1, 0)) != NULL) {
if (root->lower == 0 &&
root->pgno == 0 &&
root->linp[0] == 0) {
mpool_delete(t->bt_mp, root);
errno = EINVAL;
} else {
mpool_put(t->bt_mp, root, 0);
return (RET_SUCCESS);
}
}
if (errno != EINVAL) /* It's OK to not exist. */
return (RET_ERROR);
errno = 0;
if ((meta = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL)
return (RET_ERROR);
if ((root = mpool_new(t->bt_mp, &npg, MPOOL_PAGE_NEXT)) == NULL)
return (RET_ERROR);
if (npg != P_ROOT)
return (RET_ERROR);
root->pgno = npg;
root->prevpg = root->nextpg = P_INVALID;
root->lower = BTDATAOFF;
root->upper = t->bt_psize;
root->flags = P_BLEAF;
memset(meta, 0, t->bt_psize);
mpool_put(t->bt_mp, meta, MPOOL_DIRTY);
mpool_put(t->bt_mp, root, MPOOL_DIRTY);
return (RET_SUCCESS);
}
static int
tmp(void)
{
sigset_t set, oset;
int fd, len;
char *envtmp;
char path[MAXPATHLEN];
envtmp = secure_getenv("TMPDIR");
len = snprintf(path,
sizeof(path), "%s/bt.XXXXXXXXXX", envtmp ? envtmp : "/tmp");
if (len < 0 || len >= (int)sizeof(path)) {
errno = ENAMETOOLONG;
return(-1);
}
(void)sigfillset(&set);
(void)__libc_sigprocmask(SIG_BLOCK, &set, &oset);
if ((fd = mkostemp(path, O_CLOEXEC)) != -1)
(void)unlink(path);
(void)__libc_sigprocmask(SIG_SETMASK, &oset, NULL);
return(fd);
}
static int
byteorder(void)
{
u_int32_t x;
u_char *p;
x = 0x01020304;
p = (u_char *)&x;
switch (*p) {
case 1:
return (BIG_ENDIAN);
case 4:
return (LITTLE_ENDIAN);
default:
return (0);
}
}
int
__bt_fd(const DB *dbp)
{
BTREE *t;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* In-memory database can't have a file descriptor. */
if (F_ISSET(t, B_INMEM)) {
errno = ENOENT;
return (-1);
}
return (t->bt_fd);
}
diff --git a/lib/libc/db/btree/bt_overflow.c b/lib/libc/db/btree/bt_overflow.c
index f2c565789311..01c52ee2bef6 100644
--- a/lib/libc/db/btree/bt_overflow.c
+++ b/lib/libc/db/btree/bt_overflow.c
@@ -1,216 +1,215 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_overflow.c 8.5 (Berkeley) 7/16/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "btree.h"
/*
* Big key/data code.
*
* Big key and data entries are stored on linked lists of pages. The initial
* reference is byte string stored with the key or data and is the page number
* and size. The actual record is stored in a chain of pages linked by the
* nextpg field of the PAGE header.
*
* The first page of the chain has a special property. If the record is used
* by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
* in the header.
*
* XXX
* A single DBT is written to each chain, so a lot of space on the last page
* is wasted. This is a fairly major bug for some data sets.
*/
/*
* __OVFL_GET -- Get an overflow key/data item.
*
* Parameters:
* t: tree
* p: pointer to { pgno_t, u_int32_t }
* buf: storage address
* bufsz: storage size
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__ovfl_get(BTREE *t, void *p, size_t *ssz, void **buf, size_t *bufsz)
{
PAGE *h;
pgno_t pg;
size_t nb, plen;
u_int32_t sz;
memmove(&pg, p, sizeof(pgno_t));
memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_t));
*ssz = sz;
#ifdef DEBUG
if (pg == P_INVALID || sz == 0)
abort();
#endif
/* Make the buffer bigger as necessary. */
if (*bufsz < sz) {
*buf = reallocf(*buf, sz);
if (*buf == NULL)
return (RET_ERROR);
*bufsz = sz;
}
/*
* Step through the linked list of pages, copying the data on each one
* into the buffer. Never copy more than the data's length.
*/
plen = t->bt_psize - BTDATAOFF;
for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
nb = MIN(sz, plen);
memmove(p, (char *)h + BTDATAOFF, nb);
mpool_put(t->bt_mp, h, 0);
if ((sz -= nb) == 0)
break;
}
return (RET_SUCCESS);
}
/*
* __OVFL_PUT -- Store an overflow key/data item.
*
* Parameters:
* t: tree
* data: DBT to store
* pgno: storage page number
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__ovfl_put(BTREE *t, const DBT *dbt, pgno_t *pg)
{
PAGE *h, *last;
void *p;
pgno_t npg;
size_t nb, plen;
u_int32_t sz;
/*
* Allocate pages and copy the key/data record into them. Store the
* number of the first page in the chain.
*/
plen = t->bt_psize - BTDATAOFF;
for (last = NULL, p = dbt->data, sz = dbt->size;;
p = (char *)p + plen, last = h) {
if ((h = __bt_new(t, &npg)) == NULL)
return (RET_ERROR);
h->pgno = npg;
h->nextpg = h->prevpg = P_INVALID;
h->flags = P_OVERFLOW;
h->lower = h->upper = 0;
nb = MIN(sz, plen);
memmove((char *)h + BTDATAOFF, p, nb);
if (last) {
last->nextpg = h->pgno;
mpool_put(t->bt_mp, last, MPOOL_DIRTY);
} else
*pg = h->pgno;
if ((sz -= nb) == 0) {
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
}
}
return (RET_SUCCESS);
}
/*
* __OVFL_DELETE -- Delete an overflow chain.
*
* Parameters:
* t: tree
* p: pointer to { pgno_t, u_int32_t }
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__ovfl_delete(BTREE *t, void *p)
{
PAGE *h;
pgno_t pg;
size_t plen;
u_int32_t sz;
memmove(&pg, p, sizeof(pgno_t));
memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(u_int32_t));
#ifdef DEBUG
if (pg == P_INVALID || sz == 0)
abort();
#endif
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Don't delete chains used by internal pages. */
if (h->flags & P_PRESERVE) {
mpool_put(t->bt_mp, h, 0);
return (RET_SUCCESS);
}
/* Step through the chain, calling the free routine for each page. */
for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
pg = h->nextpg;
__bt_free(t, h);
if (sz <= plen)
break;
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
}
return (RET_SUCCESS);
}
diff --git a/lib/libc/db/btree/bt_page.c b/lib/libc/db/btree/bt_page.c
index aaec36ecfac9..2baf036c54e0 100644
--- a/lib/libc/db/btree/bt_page.c
+++ b/lib/libc/db/btree/bt_page.c
@@ -1,94 +1,93 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_page.c 8.3 (Berkeley) 7/14/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
#include <db.h>
#include "btree.h"
/*
* __bt_free --
* Put a page on the freelist.
*
* Parameters:
* t: tree
* h: page to free
*
* Returns:
* RET_ERROR, RET_SUCCESS
*
* Side-effect:
* mpool_put's the page.
*/
int
__bt_free(BTREE *t, PAGE *h)
{
/* Insert the page at the head of the free list. */
h->prevpg = P_INVALID;
h->nextpg = t->bt_free;
t->bt_free = h->pgno;
F_SET(t, B_METADIRTY);
/* Make sure the page gets written back. */
return (mpool_put(t->bt_mp, h, MPOOL_DIRTY));
}
/*
* __bt_new --
* Get a new page, preferably from the freelist.
*
* Parameters:
* t: tree
* npg: storage for page number.
*
* Returns:
* Pointer to a page, NULL on error.
*/
PAGE *
__bt_new(BTREE *t, pgno_t *npg)
{
PAGE *h;
if (t->bt_free != P_INVALID &&
(h = mpool_get(t->bt_mp, t->bt_free, 0)) != NULL) {
*npg = t->bt_free;
t->bt_free = h->nextpg;
F_SET(t, B_METADIRTY);
return (h);
}
return (mpool_new(t->bt_mp, npg, MPOOL_PAGE_NEXT));
}
diff --git a/lib/libc/db/btree/bt_put.c b/lib/libc/db/btree/bt_put.c
index 9b4ea51f184d..d3fb5cf88cab 100644
--- a/lib/libc/db/btree/bt_put.c
+++ b/lib/libc/db/btree/bt_put.c
@@ -1,315 +1,314 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_put.c 8.8 (Berkeley) 7/26/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "btree.h"
static EPG *bt_fast(BTREE *, const DBT *, const DBT *, int *);
/*
* __BT_PUT -- Add a btree item to the tree.
*
* Parameters:
* dbp: pointer to access method
* key: key
* data: data
* flag: R_NOOVERWRITE, R_SETCURSOR, R_CURSOR
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is already in the
* tree and R_NOOVERWRITE specified.
*/
int
__bt_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
{
BTREE *t;
DBT tkey, tdata;
EPG *e;
PAGE *h;
indx_t idx, nxtindex;
pgno_t pg;
u_int32_t nbytes, tmp;
int dflags, exact, status;
char *dest, db[NOVFLSIZE], kb[NOVFLSIZE];
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Check for change to a read-only tree. */
if (F_ISSET(t, B_RDONLY)) {
errno = EPERM;
return (RET_ERROR);
}
switch (flags) {
case 0:
case R_NOOVERWRITE:
case R_SETCURSOR:
break;
case R_CURSOR:
/*
* If flags is R_CURSOR, put the cursor. Must already
* have started a scan and not have already deleted it.
*/
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor,
CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE))
break;
/* FALLTHROUGH */
default:
errno = EINVAL;
return (RET_ERROR);
}
/*
* If the key/data pair won't fit on a page, store it on overflow
* pages. Only put the key on the overflow page if the pair are
* still too big after moving the data to an overflow page.
*
* XXX
* If the insert fails later on, the overflow pages aren't recovered.
*/
dflags = 0;
if (key->size + data->size > t->bt_ovflsize) {
if (key->size > t->bt_ovflsize) {
storekey: if (__ovfl_put(t, key, &pg) == RET_ERROR)
return (RET_ERROR);
tkey.data = kb;
tkey.size = NOVFLSIZE;
memmove(kb, &pg, sizeof(pgno_t));
tmp = key->size;
memmove(kb + sizeof(pgno_t),
&tmp, sizeof(u_int32_t));
dflags |= P_BIGKEY;
key = &tkey;
}
if (key->size + data->size > t->bt_ovflsize) {
if (__ovfl_put(t, data, &pg) == RET_ERROR)
return (RET_ERROR);
tdata.data = db;
tdata.size = NOVFLSIZE;
memmove(db, &pg, sizeof(pgno_t));
tmp = data->size;
memmove(db + sizeof(pgno_t),
&tmp, sizeof(u_int32_t));
dflags |= P_BIGDATA;
data = &tdata;
}
if (key->size + data->size > t->bt_ovflsize)
goto storekey;
}
/* Replace the cursor. */
if (flags == R_CURSOR) {
if ((h = mpool_get(t->bt_mp, t->bt_cursor.pg.pgno, 0)) == NULL)
return (RET_ERROR);
idx = t->bt_cursor.pg.index;
goto delete;
}
/*
* Find the key to delete, or, the location at which to insert.
* Bt_fast and __bt_search both pin the returned page.
*/
if (t->bt_order == NOT || (e = bt_fast(t, key, data, &exact)) == NULL)
if ((e = __bt_search(t, key, &exact)) == NULL)
return (RET_ERROR);
h = e->page;
idx = e->index;
/*
* Add the key/data pair to the tree. If an identical key is already
* in the tree, and R_NOOVERWRITE is set, an error is returned. If
* R_NOOVERWRITE is not set, the key is either added (if duplicates are
* permitted) or an error is returned.
*/
switch (flags) {
case R_NOOVERWRITE:
if (!exact)
break;
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
default:
if (!exact || !F_ISSET(t, B_NODUPS))
break;
/*
* !!!
* Note, the delete may empty the page, so we need to put a
* new entry into the page immediately.
*/
delete: if (__bt_dleaf(t, key, h, idx) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
break;
}
/*
* If not enough room, or the user has put a ceiling on the number of
* keys permitted in the page, split the page. The split code will
* insert the key and data and unpin the current page. If inserting
* into the offset array, shift the pointers up.
*/
nbytes = NBLEAFDBT(key->size, data->size);
if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
if ((status = __bt_split(t, h, key,
data, dflags, nbytes, idx)) != RET_SUCCESS)
return (status);
goto success;
}
if (idx < (nxtindex = NEXTINDEX(h)))
memmove(h->linp + idx + 1, h->linp + idx,
(nxtindex - idx) * sizeof(indx_t));
h->lower += sizeof(indx_t);
h->linp[idx] = h->upper -= nbytes;
dest = (char *)h + h->upper;
WR_BLEAF(dest, key, data, dflags);
/* If the cursor is on this page, adjust it as necessary. */
if (F_ISSET(&t->bt_cursor, CURS_INIT) &&
!F_ISSET(&t->bt_cursor, CURS_ACQUIRE) &&
t->bt_cursor.pg.pgno == h->pgno && t->bt_cursor.pg.index >= idx)
++t->bt_cursor.pg.index;
if (t->bt_order == NOT) {
if (h->nextpg == P_INVALID) {
if (idx == NEXTINDEX(h) - 1) {
t->bt_order = FORWARD;
t->bt_last.index = idx;
t->bt_last.pgno = h->pgno;
}
} else if (h->prevpg == P_INVALID) {
if (idx == 0) {
t->bt_order = BACK;
t->bt_last.index = 0;
t->bt_last.pgno = h->pgno;
}
}
}
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
success:
if (flags == R_SETCURSOR)
__bt_setcur(t, e->page->pgno, e->index);
F_SET(t, B_MODIFIED);
return (RET_SUCCESS);
}
#ifdef STATISTICS
u_long bt_cache_hit, bt_cache_miss;
#endif
/*
* BT_FAST -- Do a quick check for sorted data.
*
* Parameters:
* t: tree
* key: key to insert
*
* Returns:
* EPG for new record or NULL if not found.
*/
static EPG *
bt_fast(BTREE *t, const DBT *key, const DBT *data, int *exactp)
{
PAGE *h;
u_int32_t nbytes;
int cmp;
if ((h = mpool_get(t->bt_mp, t->bt_last.pgno, 0)) == NULL) {
t->bt_order = NOT;
return (NULL);
}
t->bt_cur.page = h;
t->bt_cur.index = t->bt_last.index;
/*
* If won't fit in this page or have too many keys in this page,
* have to search to get split stack.
*/
nbytes = NBLEAFDBT(key->size, data->size);
if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t))
goto miss;
if (t->bt_order == FORWARD) {
if (t->bt_cur.page->nextpg != P_INVALID)
goto miss;
if (t->bt_cur.index != NEXTINDEX(h) - 1)
goto miss;
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) < 0)
goto miss;
t->bt_last.index = cmp ? ++t->bt_cur.index : t->bt_cur.index;
} else {
if (t->bt_cur.page->prevpg != P_INVALID)
goto miss;
if (t->bt_cur.index != 0)
goto miss;
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) > 0)
goto miss;
t->bt_last.index = 0;
}
*exactp = cmp == 0;
#ifdef STATISTICS
++bt_cache_hit;
#endif
return (&t->bt_cur);
miss:
#ifdef STATISTICS
++bt_cache_miss;
#endif
t->bt_order = NOT;
mpool_put(t->bt_mp, h, 0);
return (NULL);
}
diff --git a/lib/libc/db/btree/bt_search.c b/lib/libc/db/btree/bt_search.c
index bf5245fe1fd0..1cc612714035 100644
--- a/lib/libc/db/btree/bt_search.c
+++ b/lib/libc/db/btree/bt_search.c
@@ -1,200 +1,199 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_search.c 8.8 (Berkeley) 7/31/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
#include <db.h>
#include "btree.h"
static int __bt_snext(BTREE *, PAGE *, const DBT *, int *);
static int __bt_sprev(BTREE *, PAGE *, const DBT *, int *);
/*
* __bt_search --
* Search a btree for a key.
*
* Parameters:
* t: tree to search
* key: key to find
* exactp: pointer to exact match flag
*
* Returns:
* The EPG for matching record, if any, or the EPG for the location
* of the key, if it were inserted into the tree, is entered into
* the bt_cur field of the tree. A pointer to the field is returned.
*/
EPG *
__bt_search(BTREE *t, const DBT *key, int *exactp)
{
PAGE *h;
indx_t base, idx, lim;
pgno_t pg;
int cmp;
BT_CLR(t);
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (NULL);
/* Do a binary search on the current page. */
t->bt_cur.page = h;
for (base = 0, lim = NEXTINDEX(h); lim; lim >>= 1) {
t->bt_cur.index = idx = base + (lim >> 1);
if ((cmp = __bt_cmp(t, key, &t->bt_cur)) == 0) {
if (h->flags & P_BLEAF) {
*exactp = 1;
return (&t->bt_cur);
}
goto next;
}
if (cmp > 0) {
base = idx + 1;
--lim;
}
}
/*
* If it's a leaf page, we're almost done. If no duplicates
* are allowed, or we have an exact match, we're done. Else,
* it's possible that there were matching keys on this page,
* which later deleted, and we're on a page with no matches
* while there are matches on other pages. If at the start or
* end of a page, check the adjacent page.
*/
if (h->flags & P_BLEAF) {
if (!F_ISSET(t, B_NODUPS)) {
if (base == 0 &&
h->prevpg != P_INVALID &&
__bt_sprev(t, h, key, exactp))
return (&t->bt_cur);
if (base == NEXTINDEX(h) &&
h->nextpg != P_INVALID &&
__bt_snext(t, h, key, exactp))
return (&t->bt_cur);
}
*exactp = 0;
t->bt_cur.index = base;
return (&t->bt_cur);
}
/*
* No match found. Base is the smallest index greater than
* key and may be zero or a last + 1 index. If it's non-zero,
* decrement by one, and record the internal page which should
* be a parent page for the key. If a split later occurs, the
* inserted page will be to the right of the saved page.
*/
idx = base ? base - 1 : base;
next: BT_PUSH(t, h->pgno, idx);
pg = GETBINTERNAL(h, idx)->pgno;
mpool_put(t->bt_mp, h, 0);
}
}
/*
* __bt_snext --
* Check for an exact match after the key.
*
* Parameters:
* t: tree
* h: current page
* key: key
* exactp: pointer to exact match flag
*
* Returns:
* If an exact match found.
*/
static int
__bt_snext(BTREE *t, PAGE *h, const DBT *key, int *exactp)
{
EPG e;
/*
* Get the next page. The key is either an exact
* match, or not as good as the one we already have.
*/
if ((e.page = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL)
return (0);
e.index = 0;
if (__bt_cmp(t, key, &e) == 0) {
mpool_put(t->bt_mp, h, 0);
t->bt_cur = e;
*exactp = 1;
return (1);
}
mpool_put(t->bt_mp, e.page, 0);
return (0);
}
/*
* __bt_sprev --
* Check for an exact match before the key.
*
* Parameters:
* t: tree
* h: current page
* key: key
* exactp: pointer to exact match flag
*
* Returns:
* If an exact match found.
*/
static int
__bt_sprev(BTREE *t, PAGE *h, const DBT *key, int *exactp)
{
EPG e;
/*
* Get the previous page. The key is either an exact
* match, or not as good as the one we already have.
*/
if ((e.page = mpool_get(t->bt_mp, h->prevpg, 0)) == NULL)
return (0);
e.index = NEXTINDEX(e.page) - 1;
if (__bt_cmp(t, key, &e) == 0) {
mpool_put(t->bt_mp, h, 0);
t->bt_cur = e;
*exactp = 1;
return (1);
}
mpool_put(t->bt_mp, e.page, 0);
return (0);
}
diff --git a/lib/libc/db/btree/bt_seq.c b/lib/libc/db/btree/bt_seq.c
index c68c7d3717de..80799e399182 100644
--- a/lib/libc/db/btree/bt_seq.c
+++ b/lib/libc/db/btree/bt_seq.c
@@ -1,441 +1,440 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_seq.c 8.7 (Berkeley) 7/20/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <db.h>
#include "btree.h"
static int __bt_first(BTREE *, const DBT *, EPG *, int *);
static int __bt_seqadv(BTREE *, EPG *, int);
static int __bt_seqset(BTREE *, EPG *, DBT *, int);
/*
* Sequential scan support.
*
* The tree can be scanned sequentially, starting from either end of the
* tree or from any specific key. A scan request before any scanning is
* done is initialized as starting from the least node.
*/
/*
* __bt_seq --
* Btree sequential scan interface.
*
* Parameters:
* dbp: pointer to access method
* key: key for positioning and return value
* data: data return value
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
int
__bt_seq(const DB *dbp, DBT *key, DBT *data, u_int flags)
{
BTREE *t;
EPG e;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/*
* If scan unitialized as yet, or starting at a specific record, set
* the scan to a specific key. Both __bt_seqset and __bt_seqadv pin
* the page the cursor references if they're successful.
*/
switch (flags) {
case R_NEXT:
case R_PREV:
if (F_ISSET(&t->bt_cursor, CURS_INIT)) {
status = __bt_seqadv(t, &e, flags);
break;
}
/* FALLTHROUGH */
case R_FIRST:
case R_LAST:
case R_CURSOR:
status = __bt_seqset(t, &e, key, flags);
break;
default:
errno = EINVAL;
return (RET_ERROR);
}
if (status == RET_SUCCESS) {
__bt_setcur(t, e.page->pgno, e.index);
status =
__bt_ret(t, &e, key, &t->bt_rkey, data, &t->bt_rdata, 0);
/*
* If the user is doing concurrent access, we copied the
* key/data, toss the page.
*/
if (F_ISSET(t, B_DB_LOCK))
mpool_put(t->bt_mp, e.page, 0);
else
t->bt_pinned = e.page;
}
return (status);
}
/*
* __bt_seqset --
* Set the sequential scan to a specific key.
*
* Parameters:
* t: tree
* ep: storage for returned key
* key: key for initial scan position
* flags: R_CURSOR, R_FIRST, R_LAST, R_NEXT, R_PREV
*
* Side effects:
* Pins the page the cursor references.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
__bt_seqset(BTREE *t, EPG *ep, DBT *key, int flags)
{
PAGE *h;
pgno_t pg;
int exact;
/*
* Find the first, last or specific key in the tree and point the
* cursor at it. The cursor may not be moved until a new key has
* been found.
*/
switch (flags) {
case R_CURSOR: /* Keyed scan. */
/*
* Find the first instance of the key or the smallest key
* which is greater than or equal to the specified key.
*/
if (key->data == NULL || key->size == 0) {
errno = EINVAL;
return (RET_ERROR);
}
return (__bt_first(t, key, ep, &exact));
case R_FIRST: /* First record. */
case R_NEXT:
/* Walk down the left-hand side of the tree. */
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
}
if (h->flags & (P_BLEAF | P_RLEAF))
break;
pg = GETBINTERNAL(h, 0)->pgno;
mpool_put(t->bt_mp, h, 0);
}
ep->page = h;
ep->index = 0;
break;
case R_LAST: /* Last record. */
case R_PREV:
/* Walk down the right-hand side of the tree. */
for (pg = P_ROOT;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
/* Check for an empty tree. */
if (NEXTINDEX(h) == 0) {
mpool_put(t->bt_mp, h, 0);
return (RET_SPECIAL);
}
if (h->flags & (P_BLEAF | P_RLEAF))
break;
pg = GETBINTERNAL(h, NEXTINDEX(h) - 1)->pgno;
mpool_put(t->bt_mp, h, 0);
}
ep->page = h;
ep->index = NEXTINDEX(h) - 1;
break;
}
return (RET_SUCCESS);
}
/*
* __bt_seqadvance --
* Advance the sequential scan.
*
* Parameters:
* t: tree
* flags: R_NEXT, R_PREV
*
* Side effects:
* Pins the page the new key/data record is on.
*
* Returns:
* RET_ERROR, RET_SUCCESS or RET_SPECIAL if there's no next key.
*/
static int
__bt_seqadv(BTREE *t, EPG *ep, int flags)
{
CURSOR *c;
PAGE *h;
indx_t idx;
pgno_t pg;
int exact;
/*
* There are a couple of states that we can be in. The cursor has
* been initialized by the time we get here, but that's all we know.
*/
c = &t->bt_cursor;
/*
* The cursor was deleted where there weren't any duplicate records,
* so the key was saved. Find out where that key would go in the
* current tree. It doesn't matter if the returned key is an exact
* match or not -- if it's an exact match, the record was added after
* the delete so we can just return it. If not, as long as there's
* a record there, return it.
*/
if (F_ISSET(c, CURS_ACQUIRE))
return (__bt_first(t, &c->key, ep, &exact));
/* Get the page referenced by the cursor. */
if ((h = mpool_get(t->bt_mp, c->pg.pgno, 0)) == NULL)
return (RET_ERROR);
/*
* Find the next/previous record in the tree and point the cursor at
* it. The cursor may not be moved until a new key has been found.
*/
switch (flags) {
case R_NEXT: /* Next record. */
/*
* The cursor was deleted in duplicate records, and moved
* forward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_AFTER))
goto usecurrent;
idx = c->pg.index;
if (++idx == NEXTINDEX(h)) {
pg = h->nextpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
idx = 0;
}
break;
case R_PREV: /* Previous record. */
/*
* The cursor was deleted in duplicate records, and moved
* backward to a record that has yet to be returned. Clear
* that flag, and return the record.
*/
if (F_ISSET(c, CURS_BEFORE)) {
usecurrent: F_CLR(c, CURS_AFTER | CURS_BEFORE);
ep->page = h;
ep->index = c->pg.index;
return (RET_SUCCESS);
}
idx = c->pg.index;
if (idx == 0) {
pg = h->prevpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
idx = NEXTINDEX(h) - 1;
} else
--idx;
break;
}
ep->page = h;
ep->index = idx;
return (RET_SUCCESS);
}
/*
* __bt_first --
* Find the first entry.
*
* Parameters:
* t: the tree
* key: the key
* erval: return EPG
* exactp: pointer to exact match flag
*
* Returns:
* The first entry in the tree greater than or equal to key,
* or RET_SPECIAL if no such key exists.
*/
static int
__bt_first(BTREE *t, const DBT *key, EPG *erval, int *exactp)
{
PAGE *h;
EPG *ep, save;
pgno_t pg;
/*
* Find any matching record; __bt_search pins the page.
*
* If it's an exact match and duplicates are possible, walk backwards
* in the tree until we find the first one. Otherwise, make sure it's
* a valid key (__bt_search may return an index just past the end of a
* page) and return it.
*/
if ((ep = __bt_search(t, key, exactp)) == NULL)
return (0);
if (*exactp) {
if (F_ISSET(t, B_NODUPS)) {
*erval = *ep;
return (RET_SUCCESS);
}
/*
* Walk backwards, as long as the entry matches and there are
* keys left in the tree. Save a copy of each match in case
* we go too far.
*/
save = *ep;
h = ep->page;
do {
if (save.page->pgno != ep->page->pgno) {
mpool_put(t->bt_mp, save.page, 0);
save = *ep;
} else
save.index = ep->index;
/*
* Don't unpin the page the last (or original) match
* was on, but make sure it's unpinned if an error
* occurs.
*/
if (ep->index == 0) {
if (h->prevpg == P_INVALID)
break;
if (h->pgno != save.page->pgno)
mpool_put(t->bt_mp, h, 0);
if ((h = mpool_get(t->bt_mp,
h->prevpg, 0)) == NULL) {
if (h->pgno == save.page->pgno)
mpool_put(t->bt_mp,
save.page, 0);
return (RET_ERROR);
}
ep->page = h;
ep->index = NEXTINDEX(h);
}
--ep->index;
} while (__bt_cmp(t, key, ep) == 0);
/*
* Reach here with the last page that was looked at pinned,
* which may or may not be the same as the last (or original)
* match page. If it's not useful, release it.
*/
if (h->pgno != save.page->pgno)
mpool_put(t->bt_mp, h, 0);
*erval = save;
return (RET_SUCCESS);
}
/* If at the end of a page, find the next entry. */
if (ep->index == NEXTINDEX(ep->page)) {
h = ep->page;
pg = h->nextpg;
mpool_put(t->bt_mp, h, 0);
if (pg == P_INVALID)
return (RET_SPECIAL);
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
ep->index = 0;
ep->page = h;
}
*erval = *ep;
return (RET_SUCCESS);
}
/*
* __bt_setcur --
* Set the cursor to an entry in the tree.
*
* Parameters:
* t: the tree
* pgno: page number
* idx: page index
*/
void
__bt_setcur(BTREE *t, pgno_t pgno, u_int idx)
{
/* Lose any already deleted key. */
if (t->bt_cursor.key.data != NULL) {
free(t->bt_cursor.key.data);
t->bt_cursor.key.size = 0;
t->bt_cursor.key.data = NULL;
}
F_CLR(&t->bt_cursor, CURS_ACQUIRE | CURS_AFTER | CURS_BEFORE);
/* Update the cursor. */
t->bt_cursor.pg.pgno = pgno;
t->bt_cursor.pg.index = idx;
F_SET(&t->bt_cursor, CURS_INIT);
}
diff --git a/lib/libc/db/btree/bt_split.c b/lib/libc/db/btree/bt_split.c
index cae6ebd81c33..4c1896d307aa 100644
--- a/lib/libc/db/btree/bt_split.c
+++ b/lib/libc/db/btree/bt_split.c
@@ -1,802 +1,801 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_split.c 8.10 (Berkeley) 1/9/95";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "btree.h"
static int bt_broot(BTREE *, PAGE *, PAGE *, PAGE *);
static PAGE *bt_page(BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t);
static int bt_preserve(BTREE *, pgno_t);
static PAGE *bt_psplit(BTREE *, PAGE *, PAGE *, PAGE *, indx_t *, size_t);
static PAGE *bt_root(BTREE *, PAGE *, PAGE **, PAGE **, indx_t *, size_t);
static int bt_rroot(BTREE *, PAGE *, PAGE *, PAGE *);
static recno_t rec_total(PAGE *);
#ifdef STATISTICS
u_long bt_rootsplit, bt_split, bt_sortsplit, bt_pfxsaved;
#endif
/*
* __BT_SPLIT -- Split the tree.
*
* Parameters:
* t: tree
* sp: page to split
* key: key to insert
* data: data to insert
* flags: BIGKEY/BIGDATA flags
* ilen: insert length
* skip: index to leave open
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__bt_split(BTREE *t, PAGE *sp, const DBT *key, const DBT *data, int flags,
size_t ilen, u_int32_t argskip)
{
BINTERNAL *bi;
BLEAF *bl, *tbl;
DBT a, b;
EPGNO *parent;
PAGE *h, *l, *r, *lchild, *rchild;
indx_t nxtindex;
u_int16_t skip;
u_int32_t n, nbytes, nksize;
int parentsplit;
char *dest;
/*
* Split the page into two pages, l and r. The split routines return
* a pointer to the page into which the key should be inserted and with
* skip set to the offset which should be used. Additionally, l and r
* are pinned.
*/
skip = argskip;
h = sp->pgno == P_ROOT ?
bt_root(t, sp, &l, &r, &skip, ilen) :
bt_page(t, sp, &l, &r, &skip, ilen);
if (h == NULL)
return (RET_ERROR);
/*
* Insert the new key/data pair into the leaf page. (Key inserts
* always cause a leaf page to split first.)
*/
h->linp[skip] = h->upper -= ilen;
dest = (char *)h + h->upper;
if (F_ISSET(t, R_RECNO))
WR_RLEAF(dest, data, flags)
else
WR_BLEAF(dest, key, data, flags)
/* If the root page was split, make it look right. */
if (sp->pgno == P_ROOT &&
(F_ISSET(t, R_RECNO) ?
bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
goto err2;
/*
* Now we walk the parent page stack -- a LIFO stack of the pages that
* were traversed when we searched for the page that split. Each stack
* entry is a page number and a page index offset. The offset is for
* the page traversed on the search. We've just split a page, so we
* have to insert a new key into the parent page.
*
* If the insert into the parent page causes it to split, may have to
* continue splitting all the way up the tree. We stop if the root
* splits or the page inserted into didn't have to split to hold the
* new key. Some algorithms replace the key for the old page as well
* as the new page. We don't, as there's no reason to believe that the
* first key on the old page is any better than the key we have, and,
* in the case of a key being placed at index 0 causing the split, the
* key is unavailable.
*
* There are a maximum of 5 pages pinned at any time. We keep the left
* and right pages pinned while working on the parent. The 5 are the
* two children, left parent and right parent (when the parent splits)
* and the root page or the overflow key page when calling bt_preserve.
* This code must make sure that all pins are released other than the
* root page or overflow page which is unlocked elsewhere.
*/
while ((parent = BT_POP(t)) != NULL) {
lchild = l;
rchild = r;
/* Get the parent page. */
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
goto err2;
/*
* The new key goes ONE AFTER the index, because the split
* was to the right.
*/
skip = parent->index + 1;
/*
* Calculate the space needed on the parent page.
*
* Prefix trees: space hack when inserting into BINTERNAL
* pages. Retain only what's needed to distinguish between
* the new entry and the LAST entry on the page to its left.
* If the keys compare equal, retain the entire key. Note,
* we don't touch overflow keys, and the entire key must be
* retained for the next-to-left most key on the leftmost
* page of each level, or the search will fail. Applicable
* ONLY to internal pages that have leaf pages as children.
* Further reduction of the key between pairs of internal
* pages loses too much information.
*/
switch (rchild->flags & P_TYPE) {
case P_BINTERNAL:
bi = GETBINTERNAL(rchild, 0);
nbytes = NBINTERNAL(bi->ksize);
break;
case P_BLEAF:
bl = GETBLEAF(rchild, 0);
nbytes = NBINTERNAL(bl->ksize);
if (t->bt_pfx && !(bl->flags & P_BIGKEY) &&
(h->prevpg != P_INVALID || skip > 1)) {
tbl = GETBLEAF(lchild, NEXTINDEX(lchild) - 1);
a.size = tbl->ksize;
a.data = tbl->bytes;
b.size = bl->ksize;
b.data = bl->bytes;
nksize = t->bt_pfx(&a, &b);
n = NBINTERNAL(nksize);
if (n < nbytes) {
#ifdef STATISTICS
bt_pfxsaved += nbytes - n;
#endif
nbytes = n;
} else
nksize = 0;
} else
nksize = 0;
break;
case P_RINTERNAL:
case P_RLEAF:
nbytes = NRINTERNAL;
break;
default:
abort();
}
/* Split the parent page if necessary or shift the indices. */
if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
sp = h;
h = h->pgno == P_ROOT ?
bt_root(t, h, &l, &r, &skip, nbytes) :
bt_page(t, h, &l, &r, &skip, nbytes);
if (h == NULL)
goto err1;
parentsplit = 1;
} else {
if (skip < (nxtindex = NEXTINDEX(h)))
memmove(h->linp + skip + 1, h->linp + skip,
(nxtindex - skip) * sizeof(indx_t));
h->lower += sizeof(indx_t);
parentsplit = 0;
}
/* Insert the key into the parent page. */
switch (rchild->flags & P_TYPE) {
case P_BINTERNAL:
h->linp[skip] = h->upper -= nbytes;
dest = (char *)h + h->linp[skip];
memmove(dest, bi, nbytes);
((BINTERNAL *)dest)->pgno = rchild->pgno;
break;
case P_BLEAF:
h->linp[skip] = h->upper -= nbytes;
dest = (char *)h + h->linp[skip];
WR_BINTERNAL(dest, nksize ? nksize : bl->ksize,
rchild->pgno, bl->flags & P_BIGKEY);
memmove(dest, bl->bytes, nksize ? nksize : bl->ksize);
if (bl->flags & P_BIGKEY) {
pgno_t pgno;
memcpy(&pgno, bl->bytes, sizeof(pgno));
if (bt_preserve(t, pgno) == RET_ERROR)
goto err1;
}
break;
case P_RINTERNAL:
/*
* Update the left page count. If split
* added at index 0, fix the correct page.
*/
if (skip > 0)
dest = (char *)h + h->linp[skip - 1];
else
dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
((RINTERNAL *)dest)->nrecs = rec_total(lchild);
((RINTERNAL *)dest)->pgno = lchild->pgno;
/* Update the right page count. */
h->linp[skip] = h->upper -= nbytes;
dest = (char *)h + h->linp[skip];
((RINTERNAL *)dest)->nrecs = rec_total(rchild);
((RINTERNAL *)dest)->pgno = rchild->pgno;
break;
case P_RLEAF:
/*
* Update the left page count. If split
* added at index 0, fix the correct page.
*/
if (skip > 0)
dest = (char *)h + h->linp[skip - 1];
else
dest = (char *)l + l->linp[NEXTINDEX(l) - 1];
((RINTERNAL *)dest)->nrecs = NEXTINDEX(lchild);
((RINTERNAL *)dest)->pgno = lchild->pgno;
/* Update the right page count. */
h->linp[skip] = h->upper -= nbytes;
dest = (char *)h + h->linp[skip];
((RINTERNAL *)dest)->nrecs = NEXTINDEX(rchild);
((RINTERNAL *)dest)->pgno = rchild->pgno;
break;
default:
abort();
}
/* Unpin the held pages. */
if (!parentsplit) {
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
}
/* If the root page was split, make it look right. */
if (sp->pgno == P_ROOT &&
(F_ISSET(t, R_RECNO) ?
bt_rroot(t, sp, l, r) : bt_broot(t, sp, l, r)) == RET_ERROR)
goto err1;
mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
}
/* Unpin the held pages. */
mpool_put(t->bt_mp, l, MPOOL_DIRTY);
mpool_put(t->bt_mp, r, MPOOL_DIRTY);
/* Clear any pages left on the stack. */
return (RET_SUCCESS);
/*
* If something fails in the above loop we were already walking back
* up the tree and the tree is now inconsistent. Nothing much we can
* do about it but release any memory we're holding.
*/
err1: mpool_put(t->bt_mp, lchild, MPOOL_DIRTY);
mpool_put(t->bt_mp, rchild, MPOOL_DIRTY);
err2: mpool_put(t->bt_mp, l, 0);
mpool_put(t->bt_mp, r, 0);
__dbpanic(t->bt_dbp);
return (RET_ERROR);
}
/*
* BT_PAGE -- Split a non-root page of a btree.
*
* Parameters:
* t: tree
* h: root page
* lp: pointer to left page pointer
* rp: pointer to right page pointer
* skip: pointer to index to leave open
* ilen: insert length
*
* Returns:
* Pointer to page in which to insert or NULL on error.
*/
static PAGE *
bt_page(BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
{
PAGE *l, *r, *tp;
pgno_t npg;
#ifdef STATISTICS
++bt_split;
#endif
/* Put the new right page for the split into place. */
if ((r = __bt_new(t, &npg)) == NULL)
return (NULL);
r->pgno = npg;
r->lower = BTDATAOFF;
r->upper = t->bt_psize;
r->nextpg = h->nextpg;
r->prevpg = h->pgno;
r->flags = h->flags & P_TYPE;
/*
* If we're splitting the last page on a level because we're appending
* a key to it (skip is NEXTINDEX()), it's likely that the data is
* sorted. Adding an empty page on the side of the level is less work
* and can push the fill factor much higher than normal. If we're
* wrong it's no big deal, we'll just do the split the right way next
* time. It may look like it's equally easy to do a similar hack for
* reverse sorted data, that is, split the tree left, but it's not.
* Don't even try.
*/
if (h->nextpg == P_INVALID && *skip == NEXTINDEX(h)) {
#ifdef STATISTICS
++bt_sortsplit;
#endif
h->nextpg = r->pgno;
r->lower = BTDATAOFF + sizeof(indx_t);
*skip = 0;
*lp = h;
*rp = r;
return (r);
}
/* Put the new left page for the split into place. */
if ((l = (PAGE *)calloc(1, t->bt_psize)) == NULL) {
mpool_put(t->bt_mp, r, 0);
return (NULL);
}
l->pgno = h->pgno;
l->nextpg = r->pgno;
l->prevpg = h->prevpg;
l->lower = BTDATAOFF;
l->upper = t->bt_psize;
l->flags = h->flags & P_TYPE;
/* Fix up the previous pointer of the page after the split page. */
if (h->nextpg != P_INVALID) {
if ((tp = mpool_get(t->bt_mp, h->nextpg, 0)) == NULL) {
free(l);
/* XXX mpool_free(t->bt_mp, r->pgno); */
return (NULL);
}
tp->prevpg = r->pgno;
mpool_put(t->bt_mp, tp, MPOOL_DIRTY);
}
/*
* Split right. The key/data pairs aren't sorted in the btree page so
* it's simpler to copy the data from the split page onto two new pages
* instead of copying half the data to the right page and compacting
* the left page in place. Since the left page can't change, we have
* to swap the original and the allocated left page after the split.
*/
tp = bt_psplit(t, h, l, r, skip, ilen);
/* Move the new left page onto the old left page. */
memmove(h, l, t->bt_psize);
if (tp == l)
tp = h;
free(l);
*lp = h;
*rp = r;
return (tp);
}
/*
* BT_ROOT -- Split the root page of a btree.
*
* Parameters:
* t: tree
* h: root page
* lp: pointer to left page pointer
* rp: pointer to right page pointer
* skip: pointer to index to leave open
* ilen: insert length
*
* Returns:
* Pointer to page in which to insert or NULL on error.
*/
static PAGE *
bt_root(BTREE *t, PAGE *h, PAGE **lp, PAGE **rp, indx_t *skip, size_t ilen)
{
PAGE *l, *r, *tp;
pgno_t lnpg, rnpg;
#ifdef STATISTICS
++bt_split;
++bt_rootsplit;
#endif
/* Put the new left and right pages for the split into place. */
if ((l = __bt_new(t, &lnpg)) == NULL ||
(r = __bt_new(t, &rnpg)) == NULL)
return (NULL);
l->pgno = lnpg;
r->pgno = rnpg;
l->nextpg = r->pgno;
r->prevpg = l->pgno;
l->prevpg = r->nextpg = P_INVALID;
l->lower = r->lower = BTDATAOFF;
l->upper = r->upper = t->bt_psize;
l->flags = r->flags = h->flags & P_TYPE;
/* Split the root page. */
tp = bt_psplit(t, h, l, r, skip, ilen);
*lp = l;
*rp = r;
return (tp);
}
/*
* BT_RROOT -- Fix up the recno root page after it has been split.
*
* Parameters:
* t: tree
* h: root page
* l: left page
* r: right page
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
bt_rroot(BTREE *t, PAGE *h, PAGE *l, PAGE *r)
{
char *dest;
/* Insert the left and right keys, set the header information. */
h->linp[0] = h->upper = t->bt_psize - NRINTERNAL;
dest = (char *)h + h->upper;
WR_RINTERNAL(dest,
l->flags & P_RLEAF ? NEXTINDEX(l) : rec_total(l), l->pgno);
__PAST_END(h->linp, 1) = h->upper -= NRINTERNAL;
dest = (char *)h + h->upper;
WR_RINTERNAL(dest,
r->flags & P_RLEAF ? NEXTINDEX(r) : rec_total(r), r->pgno);
h->lower = BTDATAOFF + 2 * sizeof(indx_t);
/* Unpin the root page, set to recno internal page. */
h->flags &= ~P_TYPE;
h->flags |= P_RINTERNAL;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* BT_BROOT -- Fix up the btree root page after it has been split.
*
* Parameters:
* t: tree
* h: root page
* l: left page
* r: right page
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
static int
bt_broot(BTREE *t, PAGE *h, PAGE *l, PAGE *r)
{
BINTERNAL *bi;
BLEAF *bl;
u_int32_t nbytes;
char *dest;
/*
* If the root page was a leaf page, change it into an internal page.
* We copy the key we split on (but not the key's data, in the case of
* a leaf page) to the new root page.
*
* The btree comparison code guarantees that the left-most key on any
* level of the tree is never used, so it doesn't need to be filled in.
*/
nbytes = NBINTERNAL(0);
h->linp[0] = h->upper = t->bt_psize - nbytes;
dest = (char *)h + h->upper;
WR_BINTERNAL(dest, 0, l->pgno, 0);
switch (h->flags & P_TYPE) {
case P_BLEAF:
bl = GETBLEAF(r, 0);
nbytes = NBINTERNAL(bl->ksize);
__PAST_END(h->linp, 1) = h->upper -= nbytes;
dest = (char *)h + h->upper;
WR_BINTERNAL(dest, bl->ksize, r->pgno, 0);
memmove(dest, bl->bytes, bl->ksize);
/*
* If the key is on an overflow page, mark the overflow chain
* so it isn't deleted when the leaf copy of the key is deleted.
*/
if (bl->flags & P_BIGKEY) {
pgno_t pgno;
memcpy(&pgno, bl->bytes, sizeof(pgno));
if (bt_preserve(t, pgno) == RET_ERROR)
return (RET_ERROR);
}
break;
case P_BINTERNAL:
bi = GETBINTERNAL(r, 0);
nbytes = NBINTERNAL(bi->ksize);
__PAST_END(h->linp, 1) = h->upper -= nbytes;
dest = (char *)h + h->upper;
memmove(dest, bi, nbytes);
((BINTERNAL *)dest)->pgno = r->pgno;
break;
default:
abort();
}
/* There are two keys on the page. */
h->lower = BTDATAOFF + 2 * sizeof(indx_t);
/* Unpin the root page, set to btree internal page. */
h->flags &= ~P_TYPE;
h->flags |= P_BINTERNAL;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* BT_PSPLIT -- Do the real work of splitting the page.
*
* Parameters:
* t: tree
* h: page to be split
* l: page to put lower half of data
* r: page to put upper half of data
* pskip: pointer to index to leave open
* ilen: insert length
*
* Returns:
* Pointer to page in which to insert.
*/
static PAGE *
bt_psplit(BTREE *t, PAGE *h, PAGE *l, PAGE *r, indx_t *pskip, size_t ilen)
{
BINTERNAL *bi;
BLEAF *bl;
CURSOR *c;
RLEAF *rl;
PAGE *rval;
void *src;
indx_t full, half, nxt, off, skip, top, used;
u_int32_t nbytes;
int bigkeycnt, isbigkey;
/*
* Split the data to the left and right pages. Leave the skip index
* open. Additionally, make some effort not to split on an overflow
* key. This makes internal page processing faster and can save
* space as overflow keys used by internal pages are never deleted.
*/
bigkeycnt = 0;
skip = *pskip;
full = t->bt_psize - BTDATAOFF;
half = full / 2;
used = 0;
for (nxt = off = 0, top = NEXTINDEX(h); nxt < top; ++off) {
if (skip == off) {
nbytes = ilen;
isbigkey = 0; /* XXX: not really known. */
} else
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
src = bi = GETBINTERNAL(h, nxt);
nbytes = NBINTERNAL(bi->ksize);
isbigkey = bi->flags & P_BIGKEY;
break;
case P_BLEAF:
src = bl = GETBLEAF(h, nxt);
nbytes = NBLEAF(bl);
isbigkey = bl->flags & P_BIGKEY;
break;
case P_RINTERNAL:
src = GETRINTERNAL(h, nxt);
nbytes = NRINTERNAL;
isbigkey = 0;
break;
case P_RLEAF:
src = rl = GETRLEAF(h, nxt);
nbytes = NRLEAF(rl);
isbigkey = 0;
break;
default:
abort();
}
/*
* If the key/data pairs are substantial fractions of the max
* possible size for the page, it's possible to get situations
* where we decide to try and copy too much onto the left page.
* Make sure that doesn't happen.
*/
if ((skip <= off && used + nbytes + sizeof(indx_t) >= full) ||
nxt == top - 1) {
--off;
break;
}
/* Copy the key/data pair, if not the skipped index. */
if (skip != off) {
++nxt;
l->linp[off] = l->upper -= nbytes;
memmove((char *)l + l->upper, src, nbytes);
}
used += nbytes + sizeof(indx_t);
if (used >= half) {
if (!isbigkey || bigkeycnt == 3)
break;
else
++bigkeycnt;
}
}
/*
* Off is the last offset that's valid for the left page.
* Nxt is the first offset to be placed on the right page.
*/
l->lower += (off + 1) * sizeof(indx_t);
/*
* If splitting the page that the cursor was on, the cursor has to be
* adjusted to point to the same record as before the split. If the
* cursor is at or past the skipped slot, the cursor is incremented by
* one. If the cursor is on the right page, it is decremented by the
* number of records split to the left page.
*/
c = &t->bt_cursor;
if (F_ISSET(c, CURS_INIT) && c->pg.pgno == h->pgno) {
if (c->pg.index >= skip)
++c->pg.index;
if (c->pg.index < nxt) /* Left page. */
c->pg.pgno = l->pgno;
else { /* Right page. */
c->pg.pgno = r->pgno;
c->pg.index -= nxt;
}
}
/*
* If the skipped index was on the left page, just return that page.
* Otherwise, adjust the skip index to reflect the new position on
* the right page.
*/
if (skip <= off) {
skip = MAX_PAGE_OFFSET;
rval = l;
} else {
rval = r;
*pskip -= nxt;
}
for (off = 0; nxt < top; ++off) {
if (skip == nxt) {
++off;
skip = MAX_PAGE_OFFSET;
}
switch (h->flags & P_TYPE) {
case P_BINTERNAL:
src = bi = GETBINTERNAL(h, nxt);
nbytes = NBINTERNAL(bi->ksize);
break;
case P_BLEAF:
src = bl = GETBLEAF(h, nxt);
nbytes = NBLEAF(bl);
break;
case P_RINTERNAL:
src = GETRINTERNAL(h, nxt);
nbytes = NRINTERNAL;
break;
case P_RLEAF:
src = rl = GETRLEAF(h, nxt);
nbytes = NRLEAF(rl);
break;
default:
abort();
}
++nxt;
r->linp[off] = r->upper -= nbytes;
memmove((char *)r + r->upper, src, nbytes);
}
r->lower += off * sizeof(indx_t);
/* If the key is being appended to the page, adjust the index. */
if (skip == top)
r->lower += sizeof(indx_t);
return (rval);
}
/*
* BT_PRESERVE -- Mark a chain of pages as used by an internal node.
*
* Chains of indirect blocks pointed to by leaf nodes get reclaimed when the
* record that references them gets deleted. Chains pointed to by internal
* pages never get deleted. This routine marks a chain as pointed to by an
* internal page.
*
* Parameters:
* t: tree
* pg: page number of first page in the chain.
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
static int
bt_preserve(BTREE *t, pgno_t pg)
{
PAGE *h;
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
return (RET_ERROR);
h->flags |= P_PRESERVE;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* REC_TOTAL -- Return the number of recno entries below a page.
*
* Parameters:
* h: page
*
* Returns:
* The number of recno entries below a page.
*
* XXX
* These values could be set by the bt_psplit routine. The problem is that the
* entry has to be popped off of the stack etc. or the values have to be passed
* all the way back to bt_split/bt_rroot and it's not very clean.
*/
static recno_t
rec_total(PAGE *h)
{
recno_t recs;
indx_t nxt, top;
for (recs = 0, nxt = 0, top = NEXTINDEX(h); nxt < top; ++nxt)
recs += GETRINTERNAL(h, nxt)->nrecs;
return (recs);
}
diff --git a/lib/libc/db/btree/bt_utils.c b/lib/libc/db/btree/bt_utils.c
index bc78ef871ff0..0e151fee7f63 100644
--- a/lib/libc/db/btree/bt_utils.c
+++ b/lib/libc/db/btree/bt_utils.c
@@ -1,246 +1,245 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bt_utils.c 8.8 (Berkeley) 7/20/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "btree.h"
/*
* __bt_ret --
* Build return key/data pair.
*
* Parameters:
* t: tree
* e: key/data pair to be returned
* key: user's key structure (NULL if not to be filled in)
* rkey: memory area to hold key
* data: user's data structure (NULL if not to be filled in)
* rdata: memory area to hold data
* copy: always copy the key/data item
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__bt_ret(BTREE *t, EPG *e, DBT *key, DBT *rkey, DBT *data, DBT *rdata, int copy)
{
BLEAF *bl;
void *p;
bl = GETBLEAF(e->page, e->index);
/*
* We must copy big keys/data to make them contigous. Otherwise,
* leave the page pinned and don't copy unless the user specified
* concurrent access.
*/
if (key == NULL)
goto dataonly;
if (bl->flags & P_BIGKEY) {
if (__ovfl_get(t, bl->bytes,
&key->size, &rkey->data, &rkey->size))
return (RET_ERROR);
key->data = rkey->data;
} else if (copy || F_ISSET(t, B_DB_LOCK)) {
if (bl->ksize > rkey->size) {
p = realloc(rkey->data, bl->ksize);
if (p == NULL)
return (RET_ERROR);
rkey->data = p;
rkey->size = bl->ksize;
}
memmove(rkey->data, bl->bytes, bl->ksize);
key->size = bl->ksize;
key->data = rkey->data;
} else {
key->size = bl->ksize;
key->data = bl->bytes;
}
dataonly:
if (data == NULL)
return (RET_SUCCESS);
if (bl->flags & P_BIGDATA) {
if (__ovfl_get(t, bl->bytes + bl->ksize,
&data->size, &rdata->data, &rdata->size))
return (RET_ERROR);
data->data = rdata->data;
} else if (copy || F_ISSET(t, B_DB_LOCK)) {
/* Use +1 in case the first record retrieved is 0 length. */
if (bl->dsize + 1 > rdata->size) {
p = realloc(rdata->data, bl->dsize + 1);
if (p == NULL)
return (RET_ERROR);
rdata->data = p;
rdata->size = bl->dsize + 1;
}
memmove(rdata->data, bl->bytes + bl->ksize, bl->dsize);
data->size = bl->dsize;
data->data = rdata->data;
} else {
data->size = bl->dsize;
data->data = bl->bytes + bl->ksize;
}
return (RET_SUCCESS);
}
/*
* __BT_CMP -- Compare a key to a given record.
*
* Parameters:
* t: tree
* k1: DBT pointer of first arg to comparison
* e: pointer to EPG for comparison
*
* Returns:
* < 0 if k1 is < record
* = 0 if k1 is = record
* > 0 if k1 is > record
*/
int
__bt_cmp(BTREE *t, const DBT *k1, EPG *e)
{
BINTERNAL *bi;
BLEAF *bl;
DBT k2;
PAGE *h;
void *bigkey;
/*
* The left-most key on internal pages, at any level of the tree, is
* guaranteed by the following code to be less than any user key.
* This saves us from having to update the leftmost key on an internal
* page when the user inserts a new key in the tree smaller than
* anything we've yet seen.
*/
h = e->page;
if (e->index == 0 && h->prevpg == P_INVALID && !(h->flags & P_BLEAF))
return (1);
bigkey = NULL;
if (h->flags & P_BLEAF) {
bl = GETBLEAF(h, e->index);
if (bl->flags & P_BIGKEY)
bigkey = bl->bytes;
else {
k2.data = bl->bytes;
k2.size = bl->ksize;
}
} else {
bi = GETBINTERNAL(h, e->index);
if (bi->flags & P_BIGKEY)
bigkey = bi->bytes;
else {
k2.data = bi->bytes;
k2.size = bi->ksize;
}
}
if (bigkey) {
if (__ovfl_get(t, bigkey,
&k2.size, &t->bt_rdata.data, &t->bt_rdata.size))
return (RET_ERROR);
k2.data = t->bt_rdata.data;
}
return ((*t->bt_cmp)(k1, &k2));
}
/*
* __BT_DEFCMP -- Default comparison routine.
*
* Parameters:
* a: DBT #1
* b: DBT #2
*
* Returns:
* < 0 if a is < b
* = 0 if a is = b
* > 0 if a is > b
*/
int
__bt_defcmp(const DBT *a, const DBT *b)
{
size_t len;
u_char *p1, *p2;
/*
* XXX
* If a size_t doesn't fit in an int, this routine can lose.
* What we need is an integral type which is guaranteed to be
* larger than a size_t, and there is no such thing.
*/
len = MIN(a->size, b->size);
for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2)
if (*p1 != *p2)
return ((int)*p1 - (int)*p2);
return ((int)a->size - (int)b->size);
}
/*
* __BT_DEFPFX -- Default prefix routine.
*
* Parameters:
* a: DBT #1
* b: DBT #2
*
* Returns:
* Number of bytes needed to distinguish b from a.
*/
size_t
__bt_defpfx(const DBT *a, const DBT *b)
{
u_char *p1, *p2;
size_t cnt, len;
cnt = 1;
len = MIN(a->size, b->size);
for (p1 = a->data, p2 = b->data; len--; ++p1, ++p2, ++cnt)
if (*p1 != *p2)
return (cnt);
/* a->size must be <= b->size, or they wouldn't be in this order. */
return (a->size < b->size ? a->size + 1 : a->size);
}
diff --git a/lib/libc/db/db/db.c b/lib/libc/db/db/db.c
index 0f061ab5b41c..6ca2de2572dd 100644
--- a/lib/libc/db/db/db.c
+++ b/lib/libc/db/db/db.c
@@ -1,104 +1,103 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)db.c 8.4 (Berkeley) 2/21/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <fcntl.h>
#include <stddef.h>
#include <stdio.h>
#include <db.h>
static int __dberr(void);
#ifndef O_CLOEXEC
#define O_CLOEXEC 0
#endif
#ifndef O_EXLOCK
#define O_EXLOCK 0
#endif
#ifndef O_SHLOCK
#define O_SHLOCK 0
#endif
DB *
dbopen(const char *fname, int flags, int mode, DBTYPE type, const void *openinfo)
{
#define DB_FLAGS (DB_LOCK | DB_SHMEM | DB_TXN)
#define USE_OPEN_FLAGS \
(O_CREAT | O_EXCL | O_EXLOCK | O_NOFOLLOW | O_NONBLOCK | \
O_RDONLY | O_RDWR | O_SHLOCK | O_SYNC | O_TRUNC | O_CLOEXEC)
if ((flags & ~(USE_OPEN_FLAGS | DB_FLAGS)) == 0)
switch (type) {
case DB_BTREE:
return (__bt_open(fname, flags & USE_OPEN_FLAGS,
mode, openinfo, flags & DB_FLAGS));
case DB_HASH:
return (__hash_open(fname, flags & USE_OPEN_FLAGS,
mode, openinfo, flags & DB_FLAGS));
case DB_RECNO:
return (__rec_open(fname, flags & USE_OPEN_FLAGS,
mode, openinfo, flags & DB_FLAGS));
}
errno = EINVAL;
return (NULL);
}
static int
__dberr(void)
{
return (RET_ERROR);
}
/*
* __DBPANIC -- Stop.
*
* Parameters:
* dbp: pointer to the DB structure.
*/
void
__dbpanic(DB *dbp)
{
/* The only thing that can succeed is a close. */
dbp->del = (int (*)(const struct __db *, const DBT*, u_int))__dberr;
dbp->fd = (int (*)(const struct __db *))__dberr;
dbp->get = (int (*)(const struct __db *, const DBT*, DBT *, u_int))__dberr;
dbp->put = (int (*)(const struct __db *, DBT *, const DBT *, u_int))__dberr;
dbp->seq = (int (*)(const struct __db *, DBT *, DBT *, u_int))__dberr;
dbp->sync = (int (*)(const struct __db *, u_int))__dberr;
}
diff --git a/lib/libc/db/hash/hash.c b/lib/libc/db/hash/hash.c
index b707ee5ff3ac..96f06e038f16 100644
--- a/lib/libc/db/hash/hash.c
+++ b/lib/libc/db/hash/hash.c
@@ -1,967 +1,966 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)hash.c 8.9 (Berkeley) 6/16/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef DEBUG
#include <assert.h>
#endif
#include "un-namespace.h"
#include <db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
static int alloc_segs(HTAB *, int);
static int flush_meta(HTAB *);
static int hash_access(HTAB *, ACTION, DBT *, DBT *);
static int hash_close(DB *);
static int hash_delete(const DB *, const DBT *, u_int32_t);
static int hash_fd(const DB *);
static int hash_get(const DB *, const DBT *, DBT *, u_int32_t);
static int hash_put(const DB *, DBT *, const DBT *, u_int32_t);
static void *hash_realloc(SEGMENT **, int, int);
static int hash_seq(const DB *, DBT *, DBT *, u_int32_t);
static int hash_sync(const DB *, u_int32_t);
static int hdestroy(HTAB *);
static HTAB *init_hash(HTAB *, const char *, const HASHINFO *);
static int init_htab(HTAB *, int);
#if BYTE_ORDER == LITTLE_ENDIAN
static void swap_header(HTAB *);
static void swap_header_copy(HASHHDR *, HASHHDR *);
#endif
/* Fast arithmetic, relying on powers of 2, */
#define MOD(x, y) ((x) & ((y) - 1))
#define RETURN_ERROR(ERR, LOC) { save_errno = ERR; goto LOC; }
/* Return values */
#define SUCCESS (0)
#define ERROR (-1)
#define ABNORMAL (1)
#ifdef HASH_STATISTICS
int hash_accesses, hash_collisions, hash_expansions, hash_overflows;
#endif
/************************** INTERFACE ROUTINES ***************************/
/* OPEN/CLOSE */
/* ARGSUSED */
DB *
__hash_open(const char *file, int flags, int mode,
const HASHINFO *info, /* Special directives for create */
int dflags)
{
HTAB *hashp;
struct stat statbuf;
DB *dbp;
int bpages, hdrsize, new_table, nsegs, save_errno;
if ((flags & O_ACCMODE) == O_WRONLY) {
errno = EINVAL;
return (NULL);
}
if (!(hashp = (HTAB *)calloc(1, sizeof(HTAB))))
return (NULL);
hashp->fp = -1;
/*
* Even if user wants write only, we need to be able to read
* the actual file, so we need to open it read/write. But, the
* field in the hashp structure needs to be accurate so that
* we can check accesses.
*/
hashp->flags = flags;
if (file) {
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;
} else
new_table = 1;
if (new_table) {
if (!(hashp = init_hash(hashp, file, info)))
RETURN_ERROR(errno, error1);
} else {
/* Table already exists */
if (info && info->hash)
hashp->hash = info->hash;
else
hashp->hash = __default_hash;
hdrsize = _read(hashp->fp, &hashp->hdr, sizeof(HASHHDR));
#if BYTE_ORDER == LITTLE_ENDIAN
swap_header(hashp);
#endif
if (hdrsize == -1)
RETURN_ERROR(errno, error1);
if (hdrsize != sizeof(HASHHDR))
RETURN_ERROR(EFTYPE, error1);
/* Verify file type, versions and hash function */
if (hashp->MAGIC != HASHMAGIC)
RETURN_ERROR(EFTYPE, error1);
#define OLDHASHVERSION 1
if (hashp->VERSION != HASHVERSION &&
hashp->VERSION != OLDHASHVERSION)
RETURN_ERROR(EFTYPE, error1);
if ((int32_t)hashp->hash(CHARKEY, sizeof(CHARKEY)) != hashp->H_CHARKEY)
RETURN_ERROR(EFTYPE, error1);
/*
* Figure out how many segments we need. Max_Bucket is the
* maximum bucket number, so the number of buckets is
* max_bucket + 1.
*/
nsegs = howmany(hashp->MAX_BUCKET + 1, hashp->SGSIZE);
if (alloc_segs(hashp, nsegs))
/*
* If alloc_segs fails, table will have been destroyed
* and errno will have been set.
*/
return (NULL);
/* Read in bitmaps */
bpages = (hashp->SPARES[hashp->OVFL_POINT] +
(hashp->BSIZE << BYTE_SHIFT) - 1) >>
(hashp->BSHIFT + BYTE_SHIFT);
hashp->nmaps = bpages;
(void)memset(&hashp->mapp[0], 0, bpages * sizeof(u_int32_t *));
}
/* Initialize Buffer Manager */
if (info && info->cachesize)
__buf_init(hashp, info->cachesize);
else
__buf_init(hashp, DEF_BUFSIZE);
hashp->new_file = new_table;
hashp->save_file = file && (hashp->flags & O_RDWR);
hashp->cbucket = -1;
if (!(dbp = (DB *)malloc(sizeof(DB)))) {
save_errno = errno;
hdestroy(hashp);
errno = save_errno;
return (NULL);
}
dbp->internal = hashp;
dbp->close = hash_close;
dbp->del = hash_delete;
dbp->fd = hash_fd;
dbp->get = hash_get;
dbp->put = hash_put;
dbp->seq = hash_seq;
dbp->sync = hash_sync;
dbp->type = DB_HASH;
#ifdef DEBUG
(void)fprintf(stderr,
"%s\n%s%p\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%d\n%s%x\n%s%x\n%s%d\n%s%d\n",
"init_htab:",
"TABLE POINTER ", hashp,
"BUCKET SIZE ", hashp->BSIZE,
"BUCKET SHIFT ", hashp->BSHIFT,
"DIRECTORY SIZE ", hashp->DSIZE,
"SEGMENT SIZE ", hashp->SGSIZE,
"SEGMENT SHIFT ", hashp->SSHIFT,
"FILL FACTOR ", hashp->FFACTOR,
"MAX BUCKET ", hashp->MAX_BUCKET,
"OVFL POINT ", hashp->OVFL_POINT,
"LAST FREED ", hashp->LAST_FREED,
"HIGH MASK ", hashp->HIGH_MASK,
"LOW MASK ", hashp->LOW_MASK,
"NSEGS ", hashp->nsegs,
"NKEYS ", hashp->NKEYS);
#endif
#ifdef HASH_STATISTICS
hash_overflows = hash_accesses = hash_collisions = hash_expansions = 0;
#endif
return (dbp);
error1:
if (hashp != NULL)
(void)_close(hashp->fp);
error0:
free(hashp);
errno = save_errno;
return (NULL);
}
static int
hash_close(DB *dbp)
{
HTAB *hashp;
int retval;
if (!dbp)
return (ERROR);
hashp = (HTAB *)dbp->internal;
retval = hdestroy(hashp);
free(dbp);
return (retval);
}
static int
hash_fd(const DB *dbp)
{
HTAB *hashp;
if (!dbp)
return (ERROR);
hashp = (HTAB *)dbp->internal;
if (hashp->fp == -1) {
errno = ENOENT;
return (-1);
}
return (hashp->fp);
}
/************************** LOCAL CREATION ROUTINES **********************/
static HTAB *
init_hash(HTAB *hashp, const char *file, const HASHINFO *info)
{
struct stat statbuf;
int nelem;
nelem = 1;
hashp->NKEYS = 0;
hashp->LORDER = BYTE_ORDER;
hashp->BSIZE = DEF_BUCKET_SIZE;
hashp->BSHIFT = DEF_BUCKET_SHIFT;
hashp->SGSIZE = DEF_SEGSIZE;
hashp->SSHIFT = DEF_SEGSIZE_SHIFT;
hashp->DSIZE = DEF_DIRSIZE;
hashp->FFACTOR = DEF_FFACTOR;
hashp->hash = __default_hash;
memset(hashp->SPARES, 0, sizeof(hashp->SPARES));
memset(hashp->BITMAPS, 0, sizeof (hashp->BITMAPS));
/* Fix bucket size to be optimal for file system */
if (file != NULL) {
if (stat(file, &statbuf))
return (NULL);
hashp->BSIZE = statbuf.st_blksize;
if (hashp->BSIZE > MAX_BSIZE)
hashp->BSIZE = MAX_BSIZE;
hashp->BSHIFT = __log2(hashp->BSIZE);
}
if (info) {
if (info->bsize) {
/* Round pagesize up to power of 2 */
hashp->BSHIFT = __log2(info->bsize);
hashp->BSIZE = 1 << hashp->BSHIFT;
if (hashp->BSIZE > MAX_BSIZE) {
errno = EINVAL;
return (NULL);
}
}
if (info->ffactor)
hashp->FFACTOR = info->ffactor;
if (info->hash)
hashp->hash = info->hash;
if (info->nelem)
nelem = info->nelem;
if (info->lorder) {
if (info->lorder != BIG_ENDIAN &&
info->lorder != LITTLE_ENDIAN) {
errno = EINVAL;
return (NULL);
}
hashp->LORDER = info->lorder;
}
}
/* init_htab should destroy the table and set errno if it fails */
if (init_htab(hashp, nelem))
return (NULL);
else
return (hashp);
}
/*
* This calls alloc_segs which may run out of memory. Alloc_segs will destroy
* the table and set errno, so we just pass the error information along.
*
* Returns 0 on No Error
*/
static int
init_htab(HTAB *hashp, int nelem)
{
int nbuckets, nsegs, l2;
/*
* Divide number of elements by the fill factor and determine a
* desired number of buckets. Allocate space for the next greater
* power of two number of buckets.
*/
nelem = (nelem - 1) / hashp->FFACTOR + 1;
l2 = __log2(MAX(nelem, 2));
nbuckets = 1 << l2;
hashp->SPARES[l2] = l2 + 1;
hashp->SPARES[l2 + 1] = l2 + 1;
hashp->OVFL_POINT = l2;
hashp->LAST_FREED = 2;
/* First bitmap page is at: splitpoint l2 page offset 1 */
if (__ibitmap(hashp, OADDR_OF(l2, 1), l2 + 1, 0))
return (-1);
hashp->MAX_BUCKET = hashp->LOW_MASK = nbuckets - 1;
hashp->HIGH_MASK = (nbuckets << 1) - 1;
hashp->HDRPAGES = ((MAX(sizeof(HASHHDR), MINHDRSIZE) - 1) >>
hashp->BSHIFT) + 1;
nsegs = (nbuckets - 1) / hashp->SGSIZE + 1;
nsegs = 1 << __log2(nsegs);
if (nsegs > hashp->DSIZE)
hashp->DSIZE = nsegs;
return (alloc_segs(hashp, nsegs));
}
/********************** DESTROY/CLOSE ROUTINES ************************/
/*
* Flushes any changes to the file if necessary and destroys the hashp
* structure, freeing all allocated space.
*/
static int
hdestroy(HTAB *hashp)
{
int i, save_errno;
save_errno = 0;
#ifdef HASH_STATISTICS
(void)fprintf(stderr, "hdestroy: accesses %ld collisions %ld\n",
hash_accesses, hash_collisions);
(void)fprintf(stderr, "hdestroy: expansions %ld\n",
hash_expansions);
(void)fprintf(stderr, "hdestroy: overflows %ld\n",
hash_overflows);
(void)fprintf(stderr, "keys %ld maxp %d segmentcount %d\n",
hashp->NKEYS, hashp->MAX_BUCKET, hashp->nsegs);
for (i = 0; i < NCACHED; i++)
(void)fprintf(stderr,
"spares[%d] = %d\n", i, hashp->SPARES[i]);
#endif
/*
* Call on buffer manager to free buffers, and if required,
* write them to disk.
*/
if (__buf_free(hashp, 1, hashp->save_file))
save_errno = errno;
if (hashp->dir) {
free(*hashp->dir); /* Free initial segments */
/* Free extra segments */
while (hashp->exsegs--)
free(hashp->dir[--hashp->nsegs]);
free(hashp->dir);
}
if (flush_meta(hashp) && !save_errno)
save_errno = errno;
/* Free Bigmaps */
for (i = 0; i < hashp->nmaps; i++)
if (hashp->mapp[i])
free(hashp->mapp[i]);
if (hashp->tmp_key)
free(hashp->tmp_key);
if (hashp->tmp_buf)
free(hashp->tmp_buf);
if (hashp->fp != -1) {
if (hashp->save_file)
(void)_fsync(hashp->fp);
(void)_close(hashp->fp);
}
free(hashp);
if (save_errno) {
errno = save_errno;
return (ERROR);
}
return (SUCCESS);
}
/*
* Write modified pages to disk
*
* Returns:
* 0 == OK
* -1 ERROR
*/
static int
hash_sync(const DB *dbp, u_int32_t flags)
{
HTAB *hashp;
if (flags != 0) {
errno = EINVAL;
return (ERROR);
}
if (!dbp)
return (ERROR);
hashp = (HTAB *)dbp->internal;
if (!hashp->save_file)
return (0);
if (__buf_free(hashp, 0, 1) || flush_meta(hashp))
return (ERROR);
if (hashp->fp != -1 && _fsync(hashp->fp) != 0)
return (ERROR);
hashp->new_file = 0;
return (0);
}
/*
* Returns:
* 0 == OK
* -1 indicates that errno should be set
*/
static int
flush_meta(HTAB *hashp)
{
HASHHDR *whdrp;
#if BYTE_ORDER == LITTLE_ENDIAN
HASHHDR whdr;
#endif
int fp, i, wsize;
if (!hashp->save_file)
return (0);
hashp->MAGIC = HASHMAGIC;
hashp->VERSION = HASHVERSION;
hashp->H_CHARKEY = hashp->hash(CHARKEY, sizeof(CHARKEY));
fp = hashp->fp;
whdrp = &hashp->hdr;
#if BYTE_ORDER == LITTLE_ENDIAN
whdrp = &whdr;
swap_header_copy(&hashp->hdr, whdrp);
#endif
if ((wsize = pwrite(fp, whdrp, sizeof(HASHHDR), (off_t)0)) == -1)
return (-1);
else
if (wsize != sizeof(HASHHDR)) {
errno = EFTYPE;
hashp->error = errno;
return (-1);
}
for (i = 0; i < NCACHED; i++)
if (hashp->mapp[i])
if (__put_page(hashp, (char *)hashp->mapp[i],
hashp->BITMAPS[i], 0, 1))
return (-1);
return (0);
}
/*******************************SEARCH ROUTINES *****************************/
/*
* All the access routines return
*
* Returns:
* 0 on SUCCESS
* 1 to indicate an external ERROR (i.e. key not found, etc)
* -1 to indicate an internal ERROR (i.e. out of memory, etc)
*/
static int
hash_get(const DB *dbp, const DBT *key, DBT *data, u_int32_t flag)
{
HTAB *hashp;
hashp = (HTAB *)dbp->internal;
if (flag) {
hashp->error = errno = EINVAL;
return (ERROR);
}
return (hash_access(hashp, HASH_GET, (DBT *)key, data));
}
static int
hash_put(const DB *dbp, DBT *key, const DBT *data, u_int32_t flag)
{
HTAB *hashp;
hashp = (HTAB *)dbp->internal;
if (flag && flag != R_NOOVERWRITE) {
hashp->error = errno = EINVAL;
return (ERROR);
}
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
hashp->error = errno = EPERM;
return (ERROR);
}
return (hash_access(hashp, flag == R_NOOVERWRITE ?
HASH_PUTNEW : HASH_PUT, (DBT *)key, (DBT *)data));
}
static int
hash_delete(const DB *dbp, const DBT *key,
u_int32_t flag) /* Ignored */
{
HTAB *hashp;
hashp = (HTAB *)dbp->internal;
if (flag && flag != R_CURSOR) {
hashp->error = errno = EINVAL;
return (ERROR);
}
if ((hashp->flags & O_ACCMODE) == O_RDONLY) {
hashp->error = errno = EPERM;
return (ERROR);
}
return (hash_access(hashp, HASH_DELETE, (DBT *)key, NULL));
}
/*
* Assume that hashp has been set in wrapper routine.
*/
static int
hash_access(HTAB *hashp, ACTION action, DBT *key, DBT *val)
{
BUFHEAD *rbufp;
BUFHEAD *bufp, *save_bufp;
u_int16_t *bp;
int n, ndx, off, size;
char *kp;
u_int16_t pageno;
#ifdef HASH_STATISTICS
hash_accesses++;
#endif
off = hashp->BSIZE;
size = key->size;
kp = (char *)key->data;
rbufp = __get_buf(hashp, __call_hash(hashp, kp, size), NULL, 0);
if (!rbufp)
return (ERROR);
save_bufp = rbufp;
/* Pin the bucket chain */
rbufp->flags |= BUF_PIN;
for (bp = (u_int16_t *)rbufp->page, n = *bp++, ndx = 1; ndx < n;)
if (bp[1] >= REAL_KEY) {
/* Real key/data pair */
if (size == off - *bp &&
memcmp(kp, rbufp->page + *bp, size) == 0)
goto found;
off = bp[1];
#ifdef HASH_STATISTICS
hash_collisions++;
#endif
bp += 2;
ndx += 2;
} else if (bp[1] == OVFLPAGE) {
rbufp = __get_buf(hashp, *bp, rbufp, 0);
if (!rbufp) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
/* FOR LOOP INIT */
bp = (u_int16_t *)rbufp->page;
n = *bp++;
ndx = 1;
off = hashp->BSIZE;
} else if (bp[1] < REAL_KEY) {
if ((ndx =
__find_bigpair(hashp, rbufp, ndx, kp, size)) > 0)
goto found;
if (ndx == -2) {
bufp = rbufp;
if (!(pageno =
__find_last_page(hashp, &bufp))) {
ndx = 0;
rbufp = bufp;
break; /* FOR */
}
rbufp = __get_buf(hashp, pageno, bufp, 0);
if (!rbufp) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
/* FOR LOOP INIT */
bp = (u_int16_t *)rbufp->page;
n = *bp++;
ndx = 1;
off = hashp->BSIZE;
} else {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
}
/* Not found */
switch (action) {
case HASH_PUT:
case HASH_PUTNEW:
if (__addel(hashp, rbufp, key, val)) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
} else {
save_bufp->flags &= ~BUF_PIN;
return (SUCCESS);
}
case HASH_GET:
case HASH_DELETE:
default:
save_bufp->flags &= ~BUF_PIN;
return (ABNORMAL);
}
found:
switch (action) {
case HASH_PUTNEW:
save_bufp->flags &= ~BUF_PIN;
return (ABNORMAL);
case HASH_GET:
bp = (u_int16_t *)rbufp->page;
if (bp[ndx + 1] < REAL_KEY) {
if (__big_return(hashp, rbufp, ndx, val, 0))
return (ERROR);
} else {
val->data = (u_char *)rbufp->page + (int)bp[ndx + 1];
val->size = bp[ndx] - bp[ndx + 1];
}
break;
case HASH_PUT:
if ((__delpair(hashp, rbufp, ndx)) ||
(__addel(hashp, rbufp, key, val))) {
save_bufp->flags &= ~BUF_PIN;
return (ERROR);
}
break;
case HASH_DELETE:
if (__delpair(hashp, rbufp, ndx))
return (ERROR);
break;
default:
abort();
}
save_bufp->flags &= ~BUF_PIN;
return (SUCCESS);
}
static int
hash_seq(const DB *dbp, DBT *key, DBT *data, u_int32_t flag)
{
u_int32_t bucket;
BUFHEAD *bufp;
HTAB *hashp;
u_int16_t *bp, ndx;
hashp = (HTAB *)dbp->internal;
if (flag && flag != R_FIRST && flag != R_NEXT) {
hashp->error = errno = EINVAL;
return (ERROR);
}
#ifdef HASH_STATISTICS
hash_accesses++;
#endif
if ((hashp->cbucket < 0) || (flag == R_FIRST)) {
hashp->cbucket = 0;
hashp->cndx = 1;
hashp->cpage = NULL;
}
next_bucket:
for (bp = NULL; !bp || !bp[0]; ) {
if (!(bufp = hashp->cpage)) {
for (bucket = hashp->cbucket;
bucket <= hashp->MAX_BUCKET;
bucket++, hashp->cndx = 1) {
bufp = __get_buf(hashp, bucket, NULL, 0);
if (!bufp)
return (ERROR);
hashp->cpage = bufp;
bp = (u_int16_t *)bufp->page;
if (bp[0])
break;
}
hashp->cbucket = bucket;
if ((u_int32_t)hashp->cbucket > hashp->MAX_BUCKET) {
hashp->cbucket = -1;
return (ABNORMAL);
}
} else {
bp = (u_int16_t *)hashp->cpage->page;
if (flag == R_NEXT || flag == 0) {
hashp->cndx += 2;
if (hashp->cndx > bp[0]) {
hashp->cpage = NULL;
hashp->cbucket++;
hashp->cndx = 1;
goto next_bucket;
}
}
}
#ifdef DEBUG
assert(bp);
assert(bufp);
#endif
while (bp[hashp->cndx + 1] == OVFLPAGE) {
bufp = hashp->cpage =
__get_buf(hashp, bp[hashp->cndx], bufp, 0);
if (!bufp)
return (ERROR);
bp = (u_int16_t *)(bufp->page);
hashp->cndx = 1;
}
if (!bp[0]) {
hashp->cpage = NULL;
++hashp->cbucket;
}
}
ndx = hashp->cndx;
if (bp[ndx + 1] < REAL_KEY) {
if (__big_keydata(hashp, bufp, key, data, 1))
return (ERROR);
} else {
if (hashp->cpage == NULL)
return (ERROR);
key->data = (u_char *)hashp->cpage->page + bp[ndx];
key->size = (ndx > 1 ? bp[ndx - 1] : hashp->BSIZE) - bp[ndx];
data->data = (u_char *)hashp->cpage->page + bp[ndx + 1];
data->size = bp[ndx] - bp[ndx + 1];
}
return (SUCCESS);
}
/********************************* UTILITIES ************************/
/*
* Returns:
* 0 ==> OK
* -1 ==> Error
*/
int
__expand_table(HTAB *hashp)
{
u_int32_t old_bucket, new_bucket;
int dirsize, new_segnum, spare_ndx;
#ifdef HASH_STATISTICS
hash_expansions++;
#endif
new_bucket = ++hashp->MAX_BUCKET;
old_bucket = (hashp->MAX_BUCKET & hashp->LOW_MASK);
new_segnum = new_bucket >> hashp->SSHIFT;
/* Check if we need a new segment */
if (new_segnum >= hashp->nsegs) {
/* Check if we need to expand directory */
if (new_segnum >= hashp->DSIZE) {
/* Reallocate directory */
dirsize = hashp->DSIZE * sizeof(SEGMENT *);
if (!hash_realloc(&hashp->dir, dirsize, dirsize << 1))
return (-1);
hashp->DSIZE = dirsize << 1;
}
if ((hashp->dir[new_segnum] =
calloc(hashp->SGSIZE, sizeof(SEGMENT))) == NULL)
return (-1);
hashp->exsegs++;
hashp->nsegs++;
}
/*
* If the split point is increasing (MAX_BUCKET's log base 2
* * increases), we need to copy the current contents of the spare
* split bucket to the next bucket.
*/
spare_ndx = __log2(hashp->MAX_BUCKET + 1);
if (spare_ndx > hashp->OVFL_POINT) {
hashp->SPARES[spare_ndx] = hashp->SPARES[hashp->OVFL_POINT];
hashp->OVFL_POINT = spare_ndx;
}
if (new_bucket > hashp->HIGH_MASK) {
/* Starting a new doubling */
hashp->LOW_MASK = hashp->HIGH_MASK;
hashp->HIGH_MASK = new_bucket | hashp->LOW_MASK;
}
/* Relocate records to the new bucket */
return (__split_page(hashp, old_bucket, new_bucket));
}
/*
* If realloc guarantees that the pointer is not destroyed if the realloc
* fails, then this routine can go away.
*/
static void *
hash_realloc(SEGMENT **p_ptr, int oldsize, int newsize)
{
void *p;
if ( (p = malloc(newsize)) ) {
memmove(p, *p_ptr, oldsize);
memset((char *)p + oldsize, 0, newsize - oldsize);
free(*p_ptr);
*p_ptr = p;
}
return (p);
}
u_int32_t
__call_hash(HTAB *hashp, char *k, int len)
{
unsigned int n, bucket;
n = hashp->hash(k, len);
bucket = n & hashp->HIGH_MASK;
if (bucket > hashp->MAX_BUCKET)
bucket = bucket & hashp->LOW_MASK;
return (bucket);
}
/*
* Allocate segment table. On error, destroy the table and set errno.
*
* Returns 0 on success
*/
static int
alloc_segs(HTAB *hashp, int nsegs)
{
int i;
SEGMENT store;
int save_errno;
if ((hashp->dir =
calloc(hashp->DSIZE, sizeof(SEGMENT *))) == NULL) {
save_errno = errno;
(void)hdestroy(hashp);
errno = save_errno;
return (-1);
}
hashp->nsegs = nsegs;
if (nsegs == 0)
return (0);
/* Allocate segments */
if ((store = calloc(nsegs << hashp->SSHIFT, sizeof(SEGMENT))) == NULL) {
save_errno = errno;
(void)hdestroy(hashp);
errno = save_errno;
return (-1);
}
for (i = 0; i < nsegs; i++)
hashp->dir[i] = &store[i << hashp->SSHIFT];
return (0);
}
#if BYTE_ORDER == LITTLE_ENDIAN
/*
* Hashp->hdr needs to be byteswapped.
*/
static void
swap_header_copy(HASHHDR *srcp, HASHHDR *destp)
{
int i;
P_32_COPY(srcp->magic, destp->magic);
P_32_COPY(srcp->version, destp->version);
P_32_COPY(srcp->lorder, destp->lorder);
P_32_COPY(srcp->bsize, destp->bsize);
P_32_COPY(srcp->bshift, destp->bshift);
P_32_COPY(srcp->dsize, destp->dsize);
P_32_COPY(srcp->ssize, destp->ssize);
P_32_COPY(srcp->sshift, destp->sshift);
P_32_COPY(srcp->ovfl_point, destp->ovfl_point);
P_32_COPY(srcp->last_freed, destp->last_freed);
P_32_COPY(srcp->max_bucket, destp->max_bucket);
P_32_COPY(srcp->high_mask, destp->high_mask);
P_32_COPY(srcp->low_mask, destp->low_mask);
P_32_COPY(srcp->ffactor, destp->ffactor);
P_32_COPY(srcp->nkeys, destp->nkeys);
P_32_COPY(srcp->hdrpages, destp->hdrpages);
P_32_COPY(srcp->h_charkey, destp->h_charkey);
for (i = 0; i < NCACHED; i++) {
P_32_COPY(srcp->spares[i], destp->spares[i]);
P_16_COPY(srcp->bitmaps[i], destp->bitmaps[i]);
}
}
static void
swap_header(HTAB *hashp)
{
HASHHDR *hdrp;
int i;
hdrp = &hashp->hdr;
M_32_SWAP(hdrp->magic);
M_32_SWAP(hdrp->version);
M_32_SWAP(hdrp->lorder);
M_32_SWAP(hdrp->bsize);
M_32_SWAP(hdrp->bshift);
M_32_SWAP(hdrp->dsize);
M_32_SWAP(hdrp->ssize);
M_32_SWAP(hdrp->sshift);
M_32_SWAP(hdrp->ovfl_point);
M_32_SWAP(hdrp->last_freed);
M_32_SWAP(hdrp->max_bucket);
M_32_SWAP(hdrp->high_mask);
M_32_SWAP(hdrp->low_mask);
M_32_SWAP(hdrp->ffactor);
M_32_SWAP(hdrp->nkeys);
M_32_SWAP(hdrp->hdrpages);
M_32_SWAP(hdrp->h_charkey);
for (i = 0; i < NCACHED; i++) {
M_32_SWAP(hdrp->spares[i]);
M_16_SWAP(hdrp->bitmaps[i]);
}
}
#endif
diff --git a/lib/libc/db/hash/hash_bigkey.c b/lib/libc/db/hash/hash_bigkey.c
index 301fc98a1a4a..58f39213beb5 100644
--- a/lib/libc/db/hash/hash_bigkey.c
+++ b/lib/libc/db/hash/hash_bigkey.c
@@ -1,646 +1,645 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)hash_bigkey.c 8.3 (Berkeley) 5/31/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* PACKAGE: hash
* DESCRIPTION:
* Big key/data handling for the hashing package.
*
* ROUTINES:
* External
* __big_keydata
* __big_split
* __big_insert
* __big_return
* __big_delete
* __find_last_page
* Internal
* collect_key
* collect_data
*/
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG
#include <assert.h>
#endif
#include <db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
static int collect_key(HTAB *, BUFHEAD *, int, DBT *, int);
static int collect_data(HTAB *, BUFHEAD *, int, int);
/*
* Big_insert
*
* You need to do an insert and the key/data pair is too big
*
* Returns:
* 0 ==> OK
*-1 ==> ERROR
*/
int
__big_insert(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
u_int16_t *p;
int key_size, n;
unsigned int val_size;
u_int16_t space, move_bytes, off;
char *cp, *key_data, *val_data;
cp = bufp->page; /* Character pointer of p. */
p = (u_int16_t *)cp;
key_data = (char *)key->data;
key_size = key->size;
val_data = (char *)val->data;
val_size = val->size;
/* First move the Key */
for (space = FREESPACE(p) - BIGOVERHEAD; key_size;
space = FREESPACE(p) - BIGOVERHEAD) {
move_bytes = MIN(space, key_size);
off = OFFSET(p) - move_bytes;
memmove(cp + off, key_data, move_bytes);
key_size -= move_bytes;
key_data += move_bytes;
n = p[0];
p[++n] = off;
p[0] = ++n;
FREESPACE(p) = off - PAGE_META(n);
OFFSET(p) = off;
p[n] = PARTIAL_KEY;
bufp = __add_ovflpage(hashp, bufp);
if (!bufp)
return (-1);
n = p[0];
if (!key_size) {
space = FREESPACE(p);
if (space) {
move_bytes = MIN(space, val_size);
/*
* If the data would fit exactly in the
* remaining space, we must overflow it to the
* next page; otherwise the invariant that the
* data must end on a page with FREESPACE
* non-zero would fail.
*/
if (space == val_size && val_size == val->size)
goto toolarge;
off = OFFSET(p) - move_bytes;
memmove(cp + off, val_data, move_bytes);
val_data += move_bytes;
val_size -= move_bytes;
p[n] = off;
p[n - 2] = FULL_KEY_DATA;
FREESPACE(p) = FREESPACE(p) - move_bytes;
OFFSET(p) = off;
} else {
toolarge:
p[n - 2] = FULL_KEY;
}
}
p = (u_int16_t *)bufp->page;
cp = bufp->page;
bufp->flags |= BUF_MOD;
}
/* Now move the data */
for (space = FREESPACE(p) - BIGOVERHEAD; val_size;
space = FREESPACE(p) - BIGOVERHEAD) {
move_bytes = MIN(space, val_size);
/*
* Here's the hack to make sure that if the data ends on the
* same page as the key ends, FREESPACE is at least one.
*/
if (space == val_size && val_size == val->size)
move_bytes--;
off = OFFSET(p) - move_bytes;
memmove(cp + off, val_data, move_bytes);
val_size -= move_bytes;
val_data += move_bytes;
n = p[0];
p[++n] = off;
p[0] = ++n;
FREESPACE(p) = off - PAGE_META(n);
OFFSET(p) = off;
if (val_size) {
p[n] = FULL_KEY;
bufp = __add_ovflpage(hashp, bufp);
if (!bufp)
return (-1);
cp = bufp->page;
p = (u_int16_t *)cp;
} else
p[n] = FULL_KEY_DATA;
bufp->flags |= BUF_MOD;
}
return (0);
}
/*
* Called when bufp's page contains a partial key (index should be 1)
*
* All pages in the big key/data pair except bufp are freed. We cannot
* free bufp because the page pointing to it is lost and we can't get rid
* of its pointer.
*
* Returns:
* 0 => OK
*-1 => ERROR
*/
int
__big_delete(HTAB *hashp, BUFHEAD *bufp)
{
BUFHEAD *last_bfp, *rbufp;
u_int16_t *bp, pageno;
int key_done, n;
rbufp = bufp;
last_bfp = NULL;
bp = (u_int16_t *)bufp->page;
pageno = 0;
key_done = 0;
while (!key_done || (bp[2] != FULL_KEY_DATA)) {
if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA)
key_done = 1;
/*
* If there is freespace left on a FULL_KEY_DATA page, then
* the data is short and fits entirely on this page, and this
* is the last page.
*/
if (bp[2] == FULL_KEY_DATA && FREESPACE(bp))
break;
pageno = bp[bp[0] - 1];
rbufp->flags |= BUF_MOD;
rbufp = __get_buf(hashp, pageno, rbufp, 0);
if (last_bfp)
__free_ovflpage(hashp, last_bfp);
last_bfp = rbufp;
if (!rbufp)
return (-1); /* Error. */
bp = (u_int16_t *)rbufp->page;
}
/*
* If we get here then rbufp points to the last page of the big
* key/data pair. Bufp points to the first one -- it should now be
* empty pointing to the next page after this pair. Can't free it
* because we don't have the page pointing to it.
*/
/* This is information from the last page of the pair. */
n = bp[0];
pageno = bp[n - 1];
/* Now, bp is the first page of the pair. */
bp = (u_int16_t *)bufp->page;
if (n > 2) {
/* There is an overflow page. */
bp[1] = pageno;
bp[2] = OVFLPAGE;
bufp->ovfl = rbufp->ovfl;
} else
/* This is the last page. */
bufp->ovfl = NULL;
n -= 2;
bp[0] = n;
FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
OFFSET(bp) = hashp->BSIZE;
bufp->flags |= BUF_MOD;
if (rbufp)
__free_ovflpage(hashp, rbufp);
if (last_bfp && last_bfp != rbufp)
__free_ovflpage(hashp, last_bfp);
hashp->NKEYS--;
return (0);
}
/*
* Returns:
* 0 = key not found
* -1 = get next overflow page
* -2 means key not found and this is big key/data
* -3 error
*/
int
__find_bigpair(HTAB *hashp, BUFHEAD *bufp, int ndx, char *key, int size)
{
u_int16_t *bp;
char *p;
int ksize;
u_int16_t bytes;
char *kkey;
bp = (u_int16_t *)bufp->page;
p = bufp->page;
ksize = size;
kkey = key;
for (bytes = hashp->BSIZE - bp[ndx];
bytes <= size && bp[ndx + 1] == PARTIAL_KEY;
bytes = hashp->BSIZE - bp[ndx]) {
if (memcmp(p + bp[ndx], kkey, bytes))
return (-2);
kkey += bytes;
ksize -= bytes;
bufp = __get_buf(hashp, bp[ndx + 2], bufp, 0);
if (!bufp)
return (-3);
p = bufp->page;
bp = (u_int16_t *)p;
ndx = 1;
}
if (bytes != ksize || memcmp(p + bp[ndx], kkey, bytes)) {
#ifdef HASH_STATISTICS
++hash_collisions;
#endif
return (-2);
} else
return (ndx);
}
/*
* Given the buffer pointer of the first overflow page of a big pair,
* find the end of the big pair
*
* This will set bpp to the buffer header of the last page of the big pair.
* It will return the pageno of the overflow page following the last page
* of the pair; 0 if there isn't any (i.e. big pair is the last key in the
* bucket)
*/
u_int16_t
__find_last_page(HTAB *hashp, BUFHEAD **bpp)
{
BUFHEAD *bufp;
u_int16_t *bp, pageno;
int n;
bufp = *bpp;
bp = (u_int16_t *)bufp->page;
for (;;) {
n = bp[0];
/*
* This is the last page if: the tag is FULL_KEY_DATA and
* either only 2 entries OVFLPAGE marker is explicit there
* is freespace on the page.
*/
if (bp[2] == FULL_KEY_DATA &&
((n == 2) || (bp[n] == OVFLPAGE) || (FREESPACE(bp))))
break;
pageno = bp[n - 1];
bufp = __get_buf(hashp, pageno, bufp, 0);
if (!bufp)
return (0); /* Need to indicate an error! */
bp = (u_int16_t *)bufp->page;
}
*bpp = bufp;
if (bp[0] > 2)
return (bp[3]);
else
return (0);
}
/*
* Return the data for the key/data pair that begins on this page at this
* index (index should always be 1).
*/
int
__big_return(HTAB *hashp, BUFHEAD *bufp, int ndx, DBT *val, int set_current)
{
BUFHEAD *save_p;
u_int16_t *bp, len, off, save_addr;
char *tp;
bp = (u_int16_t *)bufp->page;
while (bp[ndx + 1] == PARTIAL_KEY) {
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (u_int16_t *)bufp->page;
ndx = 1;
}
if (bp[ndx + 1] == FULL_KEY) {
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (u_int16_t *)bufp->page;
save_p = bufp;
save_addr = save_p->addr;
off = bp[1];
len = 0;
} else
if (!FREESPACE(bp)) {
/*
* This is a hack. We can't distinguish between
* FULL_KEY_DATA that contains complete data or
* incomplete data, so we require that if the data
* is complete, there is at least 1 byte of free
* space left.
*/
off = bp[bp[0]];
len = bp[1] - off;
save_p = bufp;
save_addr = bufp->addr;
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (u_int16_t *)bufp->page;
} else {
/* The data is all on one page. */
tp = (char *)bp;
off = bp[bp[0]];
val->data = (u_char *)tp + off;
val->size = bp[1] - off;
if (set_current) {
if (bp[0] == 2) { /* No more buckets in
* chain */
hashp->cpage = NULL;
hashp->cbucket++;
hashp->cndx = 1;
} else {
hashp->cpage = __get_buf(hashp,
bp[bp[0] - 1], bufp, 0);
if (!hashp->cpage)
return (-1);
hashp->cndx = 1;
if (!((u_int16_t *)
hashp->cpage->page)[0]) {
hashp->cbucket++;
hashp->cpage = NULL;
}
}
}
return (0);
}
val->size = (size_t)collect_data(hashp, bufp, (int)len, set_current);
if (val->size == (size_t)-1)
return (-1);
if (save_p->addr != save_addr) {
/* We are pretty short on buffers. */
errno = EINVAL; /* OUT OF BUFFERS */
return (-1);
}
memmove(hashp->tmp_buf, (save_p->page) + off, len);
val->data = (u_char *)hashp->tmp_buf;
return (0);
}
/*
* Count how big the total datasize is by recursing through the pages. Then
* allocate a buffer and copy the data as you recurse up.
*/
static int
collect_data(HTAB *hashp, BUFHEAD *bufp, int len, int set)
{
u_int16_t *bp;
char *p;
BUFHEAD *xbp;
u_int16_t save_addr;
int mylen, totlen;
p = bufp->page;
bp = (u_int16_t *)p;
mylen = hashp->BSIZE - bp[1];
save_addr = bufp->addr;
if (bp[2] == FULL_KEY_DATA) { /* End of Data */
totlen = len + mylen;
if (hashp->tmp_buf)
free(hashp->tmp_buf);
if ((hashp->tmp_buf = (char *)malloc(totlen)) == NULL)
return (-1);
if (set) {
hashp->cndx = 1;
if (bp[0] == 2) { /* No more buckets in chain */
hashp->cpage = NULL;
hashp->cbucket++;
} else {
hashp->cpage =
__get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!hashp->cpage)
return (-1);
else if (!((u_int16_t *)hashp->cpage->page)[0]) {
hashp->cbucket++;
hashp->cpage = NULL;
}
}
}
} else {
xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!xbp || ((totlen =
collect_data(hashp, xbp, len + mylen, set)) < 1))
return (-1);
}
if (bufp->addr != save_addr) {
errno = EINVAL; /* Out of buffers. */
return (-1);
}
memmove(&hashp->tmp_buf[len], (bufp->page) + bp[1], mylen);
return (totlen);
}
/*
* Fill in the key and data for this big pair.
*/
int
__big_keydata(HTAB *hashp, BUFHEAD *bufp, DBT *key, DBT *val, int set)
{
key->size = (size_t)collect_key(hashp, bufp, 0, val, set);
if (key->size == (size_t)-1)
return (-1);
key->data = (u_char *)hashp->tmp_key;
return (0);
}
/*
* Count how big the total key size is by recursing through the pages. Then
* collect the data, allocate a buffer and copy the key as you recurse up.
*/
static int
collect_key(HTAB *hashp, BUFHEAD *bufp, int len, DBT *val, int set)
{
BUFHEAD *xbp;
char *p;
int mylen, totlen;
u_int16_t *bp, save_addr;
p = bufp->page;
bp = (u_int16_t *)p;
mylen = hashp->BSIZE - bp[1];
save_addr = bufp->addr;
totlen = len + mylen;
if (bp[2] == FULL_KEY || bp[2] == FULL_KEY_DATA) { /* End of Key. */
if (hashp->tmp_key != NULL)
free(hashp->tmp_key);
if ((hashp->tmp_key = (char *)malloc(totlen)) == NULL)
return (-1);
if (__big_return(hashp, bufp, 1, val, set))
return (-1);
} else {
xbp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!xbp || ((totlen =
collect_key(hashp, xbp, totlen, val, set)) < 1))
return (-1);
}
if (bufp->addr != save_addr) {
errno = EINVAL; /* MIS -- OUT OF BUFFERS */
return (-1);
}
memmove(&hashp->tmp_key[len], (bufp->page) + bp[1], mylen);
return (totlen);
}
/*
* Returns:
* 0 => OK
* -1 => error
*/
int
__big_split(HTAB *hashp,
BUFHEAD *op, /* Pointer to where to put keys that go in old bucket */
BUFHEAD *np, /* Pointer to new bucket page */
BUFHEAD *big_keyp, /* Pointer to first page containing the big key/data */
int addr, /* Address of big_keyp */
u_int32_t obucket, /* Old Bucket */
SPLIT_RETURN *ret)
{
BUFHEAD *bp, *tmpp;
DBT key, val;
u_int32_t change;
u_int16_t free_space, n, off, *tp;
bp = big_keyp;
/* Now figure out where the big key/data goes */
if (__big_keydata(hashp, big_keyp, &key, &val, 0))
return (-1);
change = (__call_hash(hashp, key.data, key.size) != obucket);
if ( (ret->next_addr = __find_last_page(hashp, &big_keyp)) ) {
if (!(ret->nextp =
__get_buf(hashp, ret->next_addr, big_keyp, 0)))
return (-1);
} else
ret->nextp = NULL;
/* Now make one of np/op point to the big key/data pair */
#ifdef DEBUG
assert(np->ovfl == NULL);
#endif
if (change)
tmpp = np;
else
tmpp = op;
tmpp->flags |= BUF_MOD;
#ifdef DEBUG1
(void)fprintf(stderr,
"BIG_SPLIT: %d->ovfl was %d is now %d\n", tmpp->addr,
(tmpp->ovfl ? tmpp->ovfl->addr : 0), (bp ? bp->addr : 0));
#endif
tmpp->ovfl = bp; /* one of op/np point to big_keyp */
tp = (u_int16_t *)tmpp->page;
#ifdef DEBUG
assert(FREESPACE(tp) >= OVFLSIZE);
#endif
n = tp[0];
off = OFFSET(tp);
free_space = FREESPACE(tp);
tp[++n] = (u_int16_t)addr;
tp[++n] = OVFLPAGE;
tp[0] = n;
OFFSET(tp) = off;
FREESPACE(tp) = free_space - OVFLSIZE;
/*
* Finally, set the new and old return values. BIG_KEYP contains a
* pointer to the last page of the big key_data pair. Make sure that
* big_keyp has no following page (2 elements) or create an empty
* following page.
*/
ret->newp = np;
ret->oldp = op;
tp = (u_int16_t *)big_keyp->page;
big_keyp->flags |= BUF_MOD;
if (tp[0] > 2) {
/*
* There may be either one or two offsets on this page. If
* there is one, then the overflow page is linked on normally
* and tp[4] is OVFLPAGE. If there are two, tp[4] contains
* the second offset and needs to get stuffed in after the
* next overflow page is added.
*/
n = tp[4];
free_space = FREESPACE(tp);
off = OFFSET(tp);
tp[0] -= 2;
FREESPACE(tp) = free_space + OVFLSIZE;
OFFSET(tp) = off;
tmpp = __add_ovflpage(hashp, big_keyp);
if (!tmpp)
return (-1);
tp[4] = n;
} else
tmpp = big_keyp;
if (change)
ret->newp = tmpp;
else
ret->oldp = tmpp;
return (0);
}
diff --git a/lib/libc/db/hash/hash_buf.c b/lib/libc/db/hash/hash_buf.c
index 72c74d38f1b2..5ec286cc6748 100644
--- a/lib/libc/db/hash/hash_buf.c
+++ b/lib/libc/db/hash/hash_buf.c
@@ -1,358 +1,357 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)hash_buf.c 8.5 (Berkeley) 7/15/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* PACKAGE: hash
*
* DESCRIPTION:
* Contains buffer management
*
* ROUTINES:
* External
* __buf_init
* __get_buf
* __buf_free
* __reclaim_buf
* Internal
* newbuf
*/
#include <sys/param.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef DEBUG
#include <assert.h>
#endif
#include <db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
static BUFHEAD *newbuf(HTAB *, u_int32_t, BUFHEAD *);
/* Unlink B from its place in the lru */
#define BUF_REMOVE(B) { \
(B)->prev->next = (B)->next; \
(B)->next->prev = (B)->prev; \
}
/* Insert B after P */
#define BUF_INSERT(B, P) { \
(B)->next = (P)->next; \
(B)->prev = (P); \
(P)->next = (B); \
(B)->next->prev = (B); \
}
#define MRU hashp->bufhead.next
#define LRU hashp->bufhead.prev
#define MRU_INSERT(B) BUF_INSERT((B), &hashp->bufhead)
#define LRU_INSERT(B) BUF_INSERT((B), LRU)
/*
* We are looking for a buffer with address "addr". If prev_bp is NULL, then
* address is a bucket index. If prev_bp is not NULL, then it points to the
* page previous to an overflow page that we are trying to find.
*
* CAVEAT: The buffer header accessed via prev_bp's ovfl field may no longer
* be valid. Therefore, you must always verify that its address matches the
* address you are seeking.
*/
BUFHEAD *
__get_buf(HTAB *hashp, u_int32_t addr,
BUFHEAD *prev_bp, /* If prev_bp set, indicates a new overflow page. */
int newpage)
{
BUFHEAD *bp;
u_int32_t is_disk_mask;
int is_disk, segment_ndx;
SEGMENT segp;
is_disk = 0;
is_disk_mask = 0;
if (prev_bp) {
bp = prev_bp->ovfl;
if (!bp || (bp->addr != addr))
bp = NULL;
if (!newpage)
is_disk = BUF_DISK;
} else {
/* Grab buffer out of directory */
segment_ndx = addr & (hashp->SGSIZE - 1);
/* valid segment ensured by __call_hash() */
segp = hashp->dir[addr >> hashp->SSHIFT];
#ifdef DEBUG
assert(segp != NULL);
#endif
bp = PTROF(segp[segment_ndx]);
is_disk_mask = ISDISK(segp[segment_ndx]);
is_disk = is_disk_mask || !hashp->new_file;
}
if (!bp) {
bp = newbuf(hashp, addr, prev_bp);
if (!bp ||
__get_page(hashp, bp->page, addr, !prev_bp, is_disk, 0))
return (NULL);
if (!prev_bp)
segp[segment_ndx] =
(BUFHEAD *)((intptr_t)bp | is_disk_mask);
} else {
BUF_REMOVE(bp);
MRU_INSERT(bp);
}
return (bp);
}
/*
* We need a buffer for this page. Either allocate one, or evict a resident
* one (if we have as many buffers as we're allowed) and put this one in.
*
* If newbuf finds an error (returning NULL), it also sets errno.
*/
static BUFHEAD *
newbuf(HTAB *hashp, u_int32_t addr, BUFHEAD *prev_bp)
{
BUFHEAD *bp; /* The buffer we're going to use */
BUFHEAD *xbp; /* Temp pointer */
BUFHEAD *next_xbp;
SEGMENT segp;
int segment_ndx;
u_int16_t oaddr, *shortp;
oaddr = 0;
bp = LRU;
/* It is bad to overwrite the page under the cursor. */
if (bp == hashp->cpage) {
BUF_REMOVE(bp);
MRU_INSERT(bp);
bp = LRU;
}
/* If prev_bp is part of bp overflow, create a new buffer. */
if (hashp->nbufs == 0 && prev_bp && bp->ovfl) {
BUFHEAD *ovfl;
for (ovfl = bp->ovfl; ovfl ; ovfl = ovfl->ovfl) {
if (ovfl == prev_bp) {
hashp->nbufs++;
break;
}
}
}
/*
* If LRU buffer is pinned, the buffer pool is too small. We need to
* allocate more buffers.
*/
if (hashp->nbufs || (bp->flags & BUF_PIN) || bp == hashp->cpage) {
/* Allocate a new one */
if ((bp = (BUFHEAD *)calloc(1, sizeof(BUFHEAD))) == NULL)
return (NULL);
if ((bp->page = (char *)calloc(1, hashp->BSIZE)) == NULL) {
free(bp);
return (NULL);
}
if (hashp->nbufs)
hashp->nbufs--;
} else {
/* Kick someone out */
BUF_REMOVE(bp);
/*
* If this is an overflow page with addr 0, it's already been
* flushed back in an overflow chain and initialized.
*/
if ((bp->addr != 0) || (bp->flags & BUF_BUCKET)) {
/*
* Set oaddr before __put_page so that you get it
* before bytes are swapped.
*/
shortp = (u_int16_t *)bp->page;
if (shortp[0])
oaddr = shortp[shortp[0] - 1];
if ((bp->flags & BUF_MOD) && __put_page(hashp, bp->page,
bp->addr, (int)IS_BUCKET(bp->flags), 0))
return (NULL);
/*
* Update the pointer to this page (i.e. invalidate it).
*
* If this is a new file (i.e. we created it at open
* time), make sure that we mark pages which have been
* written to disk so we retrieve them from disk later,
* rather than allocating new pages.
*/
if (IS_BUCKET(bp->flags)) {
segment_ndx = bp->addr & (hashp->SGSIZE - 1);
segp = hashp->dir[bp->addr >> hashp->SSHIFT];
#ifdef DEBUG
assert(segp != NULL);
#endif
if (hashp->new_file &&
((bp->flags & BUF_MOD) ||
ISDISK(segp[segment_ndx])))
segp[segment_ndx] = (BUFHEAD *)BUF_DISK;
else
segp[segment_ndx] = NULL;
}
/*
* Since overflow pages can only be access by means of
* their bucket, free overflow pages associated with
* this bucket.
*/
for (xbp = bp; xbp->ovfl;) {
next_xbp = xbp->ovfl;
xbp->ovfl = NULL;
xbp = next_xbp;
/* Check that ovfl pointer is up date. */
if (IS_BUCKET(xbp->flags) ||
(oaddr != xbp->addr))
break;
shortp = (u_int16_t *)xbp->page;
if (shortp[0])
/* set before __put_page */
oaddr = shortp[shortp[0] - 1];
if ((xbp->flags & BUF_MOD) && __put_page(hashp,
xbp->page, xbp->addr, 0, 0))
return (NULL);
xbp->addr = 0;
xbp->flags = 0;
BUF_REMOVE(xbp);
LRU_INSERT(xbp);
}
}
}
/* Now assign this buffer */
bp->addr = addr;
#ifdef DEBUG1
(void)fprintf(stderr, "NEWBUF1: %d->ovfl was %d is now %d\n",
bp->addr, (bp->ovfl ? bp->ovfl->addr : 0), 0);
#endif
bp->ovfl = NULL;
if (prev_bp) {
/*
* If prev_bp is set, this is an overflow page, hook it in to
* the buffer overflow links.
*/
#ifdef DEBUG1
(void)fprintf(stderr, "NEWBUF2: %d->ovfl was %d is now %d\n",
prev_bp->addr, (prev_bp->ovfl ? prev_bp->ovfl->addr : 0),
(bp ? bp->addr : 0));
#endif
prev_bp->ovfl = bp;
bp->flags = 0;
} else
bp->flags = BUF_BUCKET;
MRU_INSERT(bp);
return (bp);
}
void
__buf_init(HTAB *hashp, int nbytes)
{
BUFHEAD *bfp;
int npages;
bfp = &(hashp->bufhead);
npages = (nbytes + hashp->BSIZE - 1) >> hashp->BSHIFT;
npages = MAX(npages, MIN_BUFFERS);
hashp->nbufs = npages;
bfp->next = bfp;
bfp->prev = bfp;
/*
* This space is calloc'd so these are already null.
*
* bfp->ovfl = NULL;
* bfp->flags = 0;
* bfp->page = NULL;
* bfp->addr = 0;
*/
}
int
__buf_free(HTAB *hashp, int do_free, int to_disk)
{
BUFHEAD *bp;
/* Need to make sure that buffer manager has been initialized */
if (!LRU)
return (0);
for (bp = LRU; bp != &hashp->bufhead;) {
/* Check that the buffer is valid */
if (bp->addr || IS_BUCKET(bp->flags)) {
if (to_disk && (bp->flags & BUF_MOD) &&
__put_page(hashp, bp->page,
bp->addr, IS_BUCKET(bp->flags), 0))
return (-1);
}
/* Check if we are freeing stuff */
if (do_free) {
if (bp->page) {
(void)memset(bp->page, 0, hashp->BSIZE);
free(bp->page);
}
BUF_REMOVE(bp);
free(bp);
bp = LRU;
} else
bp = bp->prev;
}
return (0);
}
void
__reclaim_buf(HTAB *hashp, BUFHEAD *bp)
{
bp->ovfl = NULL;
bp->addr = 0;
bp->flags = 0;
BUF_REMOVE(bp);
LRU_INSERT(bp);
}
diff --git a/lib/libc/db/hash/hash_func.c b/lib/libc/db/hash/hash_func.c
index dc7e276b03a9..4577e77a7ef4 100644
--- a/lib/libc/db/hash/hash_func.c
+++ b/lib/libc/db/hash/hash_func.c
@@ -1,190 +1,189 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)hash_func.c 8.2 (Berkeley) 2/21/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
#ifdef notdef
static u_int32_t hash1(const void *, size_t) __unused;
static u_int32_t hash2(const void *, size_t) __unused;
static u_int32_t hash3(const void *, size_t) __unused;
#endif
static u_int32_t hash4(const void *, size_t);
/* Default hash function. */
u_int32_t (*__default_hash)(const void *, size_t) = hash4;
#ifdef notdef
/*
* Assume that we've already split the bucket to which this key hashes,
* calculate that bucket, and check that in fact we did already split it.
*
* EJB's original hsearch hash.
*/
#define PRIME1 37
#define PRIME2 1048583
u_int32_t
hash1(const void *key, size_t len)
{
u_int32_t h;
u_int8_t *k;
h = 0;
k = (u_int8_t *)key;
/* Convert string to integer */
while (len--)
h = h * PRIME1 ^ (*k++ - ' ');
h %= PRIME2;
return (h);
}
/*
* Phong Vo's linear congruential hash
*/
#define dcharhash(h, c) ((h) = 0x63c63cd9*(h) + 0x9c39c33d + (c))
u_int32_t
hash2(const void *key, size_t len)
{
u_int32_t h;
u_int8_t *e, c, *k;
k = (u_int8_t *)key;
e = k + len;
for (h = 0; k != e;) {
c = *k++;
if (!c && k > e)
break;
dcharhash(h, c);
}
return (h);
}
/*
* This is INCREDIBLY ugly, but fast. We break the string up into 8 byte
* units. On the first time through the loop we get the "leftover bytes"
* (strlen % 8). On every other iteration, we perform 8 HASHC's so we handle
* all 8 bytes. Essentially, this saves us 7 cmp & branch instructions. If
* this routine is heavily used enough, it's worth the ugly coding.
*
* Ozan Yigit's original sdbm hash.
*/
u_int32_t
hash3(const void *key, size_t len)
{
u_int32_t n, loop;
u_int8_t *k;
#define HASHC n = *k++ + 65599 * n
n = 0;
k = (u_int8_t *)key;
if (len > 0) {
loop = (len + 8 - 1) >> 3;
switch (len & (8 - 1)) {
case 0:
do { /* All fall throughs */
HASHC;
case 7:
HASHC;
case 6:
HASHC;
case 5:
HASHC;
case 4:
HASHC;
case 3:
HASHC;
case 2:
HASHC;
case 1:
HASHC;
} while (--loop);
}
}
return (n);
}
#endif /* notdef */
/* Chris Torek's hash function. */
u_int32_t
hash4(const void *key, size_t len)
{
u_int32_t h, loop;
const u_int8_t *k;
#define HASH4a h = (h << 5) - h + *k++;
#define HASH4b h = (h << 5) + h + *k++;
#define HASH4 HASH4b
h = 0;
k = key;
if (len > 0) {
loop = (len + 8 - 1) >> 3;
switch (len & (8 - 1)) {
case 0:
do { /* All fall throughs */
HASH4;
case 7:
HASH4;
case 6:
HASH4;
case 5:
HASH4;
case 4:
HASH4;
case 3:
HASH4;
case 2:
HASH4;
case 1:
HASH4;
} while (--loop);
}
}
return (h);
}
diff --git a/lib/libc/db/hash/hash_log2.c b/lib/libc/db/hash/hash_log2.c
index 62c57b3ef1c7..d43984629611 100644
--- a/lib/libc/db/hash/hash_log2.c
+++ b/lib/libc/db/hash/hash_log2.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)hash_log2.c 8.2 (Berkeley) 5/31/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
u_int32_t
__log2(u_int32_t num)
{
u_int32_t i, limit;
limit = 1;
for (i = 0; limit < num; limit = limit << 1, i++);
return (i);
}
diff --git a/lib/libc/db/hash/hash_page.c b/lib/libc/db/hash/hash_page.c
index 2f86db8106c1..5c91d6ca23fa 100644
--- a/lib/libc/db/hash/hash_page.c
+++ b/lib/libc/db/hash/hash_page.c
@@ -1,939 +1,938 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)hash_page.c 8.7 (Berkeley) 8/16/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* PACKAGE: hashing
*
* DESCRIPTION:
* Page manipulation for hashing package.
*
* ROUTINES:
*
* External
* __get_page
* __add_ovflpage
* Internal
* overflow_page
* open_temp
*/
#include "namespace.h"
#include <sys/param.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#ifdef DEBUG
#include <assert.h>
#endif
#include "un-namespace.h"
#include "libc_private.h"
#include <db.h>
#include "hash.h"
#include "page.h"
#include "extern.h"
static u_int32_t *fetch_bitmap(HTAB *, int);
static u_int32_t first_free(u_int32_t);
static int open_temp(HTAB *);
static u_int16_t overflow_page(HTAB *);
static void putpair(char *, const DBT *, const DBT *);
static void squeeze_key(u_int16_t *, const DBT *, const DBT *);
static int ugly_split(HTAB *, u_int32_t, BUFHEAD *, BUFHEAD *, int, int);
#define PAGE_INIT(P) { \
((u_int16_t *)(P))[0] = 0; \
((u_int16_t *)(P))[1] = hashp->BSIZE - 3 * sizeof(u_int16_t); \
((u_int16_t *)(P))[2] = hashp->BSIZE; \
}
/*
* This is called AFTER we have verified that there is room on the page for
* the pair (PAIRFITS has returned true) so we go right ahead and start moving
* stuff on.
*/
static void
putpair(char *p, const DBT *key, const DBT *val)
{
u_int16_t *bp, n, off;
bp = (u_int16_t *)p;
/* Enter the key first. */
n = bp[0];
off = OFFSET(bp) - key->size;
memmove(p + off, key->data, key->size);
bp[++n] = off;
/* Now the data. */
off -= val->size;
memmove(p + off, val->data, val->size);
bp[++n] = off;
/* Adjust page info. */
bp[0] = n;
bp[n + 1] = off - ((n + 3) * sizeof(u_int16_t));
bp[n + 2] = off;
}
/*
* Returns:
* 0 OK
* -1 error
*/
int
__delpair(HTAB *hashp, BUFHEAD *bufp, int ndx)
{
u_int16_t *bp, newoff, pairlen;
int n;
bp = (u_int16_t *)bufp->page;
n = bp[0];
if (bp[ndx + 1] < REAL_KEY)
return (__big_delete(hashp, bufp));
if (ndx != 1)
newoff = bp[ndx - 1];
else
newoff = hashp->BSIZE;
pairlen = newoff - bp[ndx + 1];
if (ndx != (n - 1)) {
/* Hard Case -- need to shuffle keys */
int i;
char *src = bufp->page + (int)OFFSET(bp);
char *dst = src + (int)pairlen;
memmove(dst, src, bp[ndx + 1] - OFFSET(bp));
/* Now adjust the pointers */
for (i = ndx + 2; i <= n; i += 2) {
if (bp[i + 1] == OVFLPAGE) {
bp[i - 2] = bp[i];
bp[i - 1] = bp[i + 1];
} else {
bp[i - 2] = bp[i] + pairlen;
bp[i - 1] = bp[i + 1] + pairlen;
}
}
if (ndx == hashp->cndx) {
/*
* We just removed pair we were "pointing" to.
* By moving back the cndx we ensure subsequent
* hash_seq() calls won't skip over any entries.
*/
hashp->cndx -= 2;
}
}
/* Finally adjust the page data */
bp[n] = OFFSET(bp) + pairlen;
bp[n - 1] = bp[n + 1] + pairlen + 2 * sizeof(u_int16_t);
bp[0] = n - 2;
hashp->NKEYS--;
bufp->flags |= BUF_MOD;
return (0);
}
/*
* Returns:
* 0 ==> OK
* -1 ==> Error
*/
int
__split_page(HTAB *hashp, u_int32_t obucket, u_int32_t nbucket)
{
BUFHEAD *new_bufp, *old_bufp;
u_int16_t *ino;
char *np;
DBT key, val;
int n, ndx, retval;
u_int16_t copyto, diff, off, moved;
char *op;
copyto = (u_int16_t)hashp->BSIZE;
off = (u_int16_t)hashp->BSIZE;
old_bufp = __get_buf(hashp, obucket, NULL, 0);
if (old_bufp == NULL)
return (-1);
new_bufp = __get_buf(hashp, nbucket, NULL, 0);
if (new_bufp == NULL)
return (-1);
old_bufp->flags |= (BUF_MOD | BUF_PIN);
new_bufp->flags |= (BUF_MOD | BUF_PIN);
ino = (u_int16_t *)(op = old_bufp->page);
np = new_bufp->page;
moved = 0;
for (n = 1, ndx = 1; n < ino[0]; n += 2) {
if (ino[n + 1] < REAL_KEY) {
retval = ugly_split(hashp, obucket, old_bufp, new_bufp,
(int)copyto, (int)moved);
old_bufp->flags &= ~BUF_PIN;
new_bufp->flags &= ~BUF_PIN;
return (retval);
}
key.data = (u_char *)op + ino[n];
key.size = off - ino[n];
if (__call_hash(hashp, key.data, key.size) == obucket) {
/* Don't switch page */
diff = copyto - off;
if (diff) {
copyto = ino[n + 1] + diff;
memmove(op + copyto, op + ino[n + 1],
off - ino[n + 1]);
ino[ndx] = copyto + ino[n] - ino[n + 1];
ino[ndx + 1] = copyto;
} else
copyto = ino[n + 1];
ndx += 2;
} else {
/* Switch page */
val.data = (u_char *)op + ino[n + 1];
val.size = ino[n] - ino[n + 1];
putpair(np, &key, &val);
moved += 2;
}
off = ino[n + 1];
}
/* Now clean up the page */
ino[0] -= moved;
FREESPACE(ino) = copyto - sizeof(u_int16_t) * (ino[0] + 3);
OFFSET(ino) = copyto;
#ifdef DEBUG3
(void)fprintf(stderr, "split %d/%d\n",
((u_int16_t *)np)[0] / 2,
((u_int16_t *)op)[0] / 2);
#endif
/* unpin both pages */
old_bufp->flags &= ~BUF_PIN;
new_bufp->flags &= ~BUF_PIN;
return (0);
}
/*
* Called when we encounter an overflow or big key/data page during split
* handling. This is special cased since we have to begin checking whether
* the key/data pairs fit on their respective pages and because we may need
* overflow pages for both the old and new pages.
*
* The first page might be a page with regular key/data pairs in which case
* we have a regular overflow condition and just need to go on to the next
* page or it might be a big key/data pair in which case we need to fix the
* big key/data pair.
*
* Returns:
* 0 ==> success
* -1 ==> failure
*/
static int
ugly_split(HTAB *hashp,
u_int32_t obucket, /* Same as __split_page. */
BUFHEAD *old_bufp,
BUFHEAD *new_bufp,
int copyto, /* First byte on page which contains key/data values. */
int moved) /* Number of pairs moved to new page. */
{
BUFHEAD *bufp; /* Buffer header for ino */
u_int16_t *ino; /* Page keys come off of */
u_int16_t *np; /* New page */
u_int16_t *op; /* Page keys go on to if they aren't moving */
BUFHEAD *last_bfp; /* Last buf header OVFL needing to be freed */
DBT key, val;
SPLIT_RETURN ret;
u_int16_t n, off, ov_addr, scopyto;
char *cino; /* Character value of ino */
bufp = old_bufp;
ino = (u_int16_t *)old_bufp->page;
np = (u_int16_t *)new_bufp->page;
op = (u_int16_t *)old_bufp->page;
last_bfp = NULL;
scopyto = (u_int16_t)copyto; /* ANSI */
n = ino[0] - 1;
while (n < ino[0]) {
if (ino[2] < REAL_KEY && ino[2] != OVFLPAGE) {
if (__big_split(hashp, old_bufp,
new_bufp, bufp, bufp->addr, obucket, &ret))
return (-1);
old_bufp = ret.oldp;
if (!old_bufp)
return (-1);
op = (u_int16_t *)old_bufp->page;
new_bufp = ret.newp;
if (!new_bufp)
return (-1);
np = (u_int16_t *)new_bufp->page;
bufp = ret.nextp;
if (!bufp)
return (0);
cino = (char *)bufp->page;
ino = (u_int16_t *)cino;
last_bfp = ret.nextp;
} else if (ino[n + 1] == OVFLPAGE) {
ov_addr = ino[n];
/*
* Fix up the old page -- the extra 2 are the fields
* which contained the overflow information.
*/
ino[0] -= (moved + 2);
FREESPACE(ino) =
scopyto - sizeof(u_int16_t) * (ino[0] + 3);
OFFSET(ino) = scopyto;
bufp = __get_buf(hashp, ov_addr, bufp, 0);
if (!bufp)
return (-1);
ino = (u_int16_t *)bufp->page;
n = 1;
scopyto = hashp->BSIZE;
moved = 0;
if (last_bfp)
__free_ovflpage(hashp, last_bfp);
last_bfp = bufp;
}
/* Move regular sized pairs of there are any */
off = hashp->BSIZE;
for (n = 1; (n < ino[0]) && (ino[n + 1] >= REAL_KEY); n += 2) {
cino = (char *)ino;
key.data = (u_char *)cino + ino[n];
key.size = off - ino[n];
val.data = (u_char *)cino + ino[n + 1];
val.size = ino[n] - ino[n + 1];
off = ino[n + 1];
if (__call_hash(hashp, key.data, key.size) == obucket) {
/* Keep on old page */
if (PAIRFITS(op, (&key), (&val)))
putpair((char *)op, &key, &val);
else {
old_bufp =
__add_ovflpage(hashp, old_bufp);
if (!old_bufp)
return (-1);
op = (u_int16_t *)old_bufp->page;
putpair((char *)op, &key, &val);
}
old_bufp->flags |= BUF_MOD;
} else {
/* Move to new page */
if (PAIRFITS(np, (&key), (&val)))
putpair((char *)np, &key, &val);
else {
new_bufp =
__add_ovflpage(hashp, new_bufp);
if (!new_bufp)
return (-1);
np = (u_int16_t *)new_bufp->page;
putpair((char *)np, &key, &val);
}
new_bufp->flags |= BUF_MOD;
}
}
}
if (last_bfp)
__free_ovflpage(hashp, last_bfp);
return (0);
}
/*
* Add the given pair to the page
*
* Returns:
* 0 ==> OK
* 1 ==> failure
*/
int
__addel(HTAB *hashp, BUFHEAD *bufp, const DBT *key, const DBT *val)
{
u_int16_t *bp, *sop;
int do_expand;
bp = (u_int16_t *)bufp->page;
do_expand = 0;
while (bp[0] && (bp[2] < REAL_KEY || bp[bp[0]] < REAL_KEY))
/* Exception case */
if (bp[2] == FULL_KEY_DATA && bp[0] == 2)
/* This is the last page of a big key/data pair
and we need to add another page */
break;
else if (bp[2] < REAL_KEY && bp[bp[0]] != OVFLPAGE) {
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (u_int16_t *)bufp->page;
} else if (bp[bp[0]] != OVFLPAGE) {
/* Short key/data pairs, no more pages */
break;
} else {
/* Try to squeeze key on this page */
if (bp[2] >= REAL_KEY &&
FREESPACE(bp) >= PAIRSIZE(key, val)) {
squeeze_key(bp, key, val);
goto stats;
} else {
bufp = __get_buf(hashp, bp[bp[0] - 1], bufp, 0);
if (!bufp)
return (-1);
bp = (u_int16_t *)bufp->page;
}
}
if (PAIRFITS(bp, key, val))
putpair(bufp->page, key, val);
else {
do_expand = 1;
bufp = __add_ovflpage(hashp, bufp);
if (!bufp)
return (-1);
sop = (u_int16_t *)bufp->page;
if (PAIRFITS(sop, key, val))
putpair((char *)sop, key, val);
else
if (__big_insert(hashp, bufp, key, val))
return (-1);
}
stats:
bufp->flags |= BUF_MOD;
/*
* If the average number of keys per bucket exceeds the fill factor,
* expand the table.
*/
hashp->NKEYS++;
if (do_expand ||
(hashp->NKEYS / (hashp->MAX_BUCKET + 1) > hashp->FFACTOR))
return (__expand_table(hashp));
return (0);
}
/*
*
* Returns:
* pointer on success
* NULL on error
*/
BUFHEAD *
__add_ovflpage(HTAB *hashp, BUFHEAD *bufp)
{
u_int16_t *sp, ndx, ovfl_num;
#ifdef DEBUG1
int tmp1, tmp2;
#endif
sp = (u_int16_t *)bufp->page;
/* Check if we are dynamically determining the fill factor */
if (hashp->FFACTOR == DEF_FFACTOR) {
hashp->FFACTOR = sp[0] >> 1;
if (hashp->FFACTOR < MIN_FFACTOR)
hashp->FFACTOR = MIN_FFACTOR;
}
bufp->flags |= BUF_MOD;
ovfl_num = overflow_page(hashp);
#ifdef DEBUG1
tmp1 = bufp->addr;
tmp2 = bufp->ovfl ? bufp->ovfl->addr : 0;
#endif
if (!ovfl_num || !(bufp->ovfl = __get_buf(hashp, ovfl_num, bufp, 1)))
return (NULL);
bufp->ovfl->flags |= BUF_MOD;
#ifdef DEBUG1
(void)fprintf(stderr, "ADDOVFLPAGE: %d->ovfl was %d is now %d\n",
tmp1, tmp2, bufp->ovfl->addr);
#endif
ndx = sp[0];
/*
* Since a pair is allocated on a page only if there's room to add
* an overflow page, we know that the OVFL information will fit on
* the page.
*/
sp[ndx + 4] = OFFSET(sp);
sp[ndx + 3] = FREESPACE(sp) - OVFLSIZE;
sp[ndx + 1] = ovfl_num;
sp[ndx + 2] = OVFLPAGE;
sp[0] = ndx + 2;
#ifdef HASH_STATISTICS
hash_overflows++;
#endif
return (bufp->ovfl);
}
/*
* Returns:
* 0 indicates SUCCESS
* -1 indicates FAILURE
*/
int
__get_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_disk,
int is_bitmap)
{
int fd, page, size, rsize;
u_int16_t *bp;
fd = hashp->fp;
size = hashp->BSIZE;
if ((fd == -1) || !is_disk) {
PAGE_INIT(p);
return (0);
}
if (is_bucket)
page = BUCKET_TO_PAGE(bucket);
else
page = OADDR_TO_PAGE(bucket);
if ((rsize = pread(fd, p, size, (off_t)page << hashp->BSHIFT)) == -1)
return (-1);
bp = (u_int16_t *)p;
if (!rsize)
bp[0] = 0; /* We hit the EOF, so initialize a new page */
else
if (rsize != size) {
errno = EFTYPE;
return (-1);
}
if (!is_bitmap && !bp[0]) {
PAGE_INIT(p);
} else
if (hashp->LORDER != BYTE_ORDER) {
int i, max;
if (is_bitmap) {
max = hashp->BSIZE >> 2; /* divide by 4 */
for (i = 0; i < max; i++)
M_32_SWAP(((int *)p)[i]);
} else {
M_16_SWAP(bp[0]);
max = bp[0] + 2;
for (i = 1; i <= max; i++)
M_16_SWAP(bp[i]);
}
}
return (0);
}
/*
* Write page p to disk
*
* Returns:
* 0 ==> OK
* -1 ==>failure
*/
int
__put_page(HTAB *hashp, char *p, u_int32_t bucket, int is_bucket, int is_bitmap)
{
int fd, page, size;
ssize_t wsize;
char pbuf[MAX_BSIZE];
size = hashp->BSIZE;
if ((hashp->fp == -1) && open_temp(hashp))
return (-1);
fd = hashp->fp;
if (hashp->LORDER != BYTE_ORDER) {
int i, max;
memcpy(pbuf, p, size);
if (is_bitmap) {
max = hashp->BSIZE >> 2; /* divide by 4 */
for (i = 0; i < max; i++)
M_32_SWAP(((int *)pbuf)[i]);
} else {
uint16_t *bp = (uint16_t *)(void *)pbuf;
max = bp[0] + 2;
for (i = 0; i <= max; i++)
M_16_SWAP(bp[i]);
}
p = pbuf;
}
if (is_bucket)
page = BUCKET_TO_PAGE(bucket);
else
page = OADDR_TO_PAGE(bucket);
if ((wsize = pwrite(fd, p, size, (off_t)page << hashp->BSHIFT)) == -1)
/* Errno is set */
return (-1);
if (wsize != size) {
errno = EFTYPE;
return (-1);
}
return (0);
}
#define BYTE_MASK ((1 << INT_BYTE_SHIFT) -1)
/*
* Initialize a new bitmap page. Bitmap pages are left in memory
* once they are read in.
*/
int
__ibitmap(HTAB *hashp, int pnum, int nbits, int ndx)
{
u_int32_t *ip;
int clearbytes, clearints;
if ((ip = (u_int32_t *)malloc(hashp->BSIZE)) == NULL)
return (1);
hashp->nmaps++;
clearints = ((nbits - 1) >> INT_BYTE_SHIFT) + 1;
clearbytes = clearints << INT_TO_BYTE;
(void)memset((char *)ip, 0, clearbytes);
(void)memset(((char *)ip) + clearbytes, 0xFF,
hashp->BSIZE - clearbytes);
ip[clearints - 1] = ALL_SET << (nbits & BYTE_MASK);
SETBIT(ip, 0);
hashp->BITMAPS[ndx] = (u_int16_t)pnum;
hashp->mapp[ndx] = ip;
return (0);
}
static u_int32_t
first_free(u_int32_t map)
{
u_int32_t i, mask;
mask = 0x1;
for (i = 0; i < BITS_PER_MAP; i++) {
if (!(mask & map))
return (i);
mask = mask << 1;
}
return (i);
}
static u_int16_t
overflow_page(HTAB *hashp)
{
u_int32_t *freep;
int max_free, offset, splitnum;
u_int16_t addr;
int bit, first_page, free_bit, free_page, i, in_use_bits, j;
#ifdef DEBUG2
int tmp1, tmp2;
#endif
splitnum = hashp->OVFL_POINT;
max_free = hashp->SPARES[splitnum];
free_page = (max_free - 1) >> (hashp->BSHIFT + BYTE_SHIFT);
free_bit = (max_free - 1) & ((hashp->BSIZE << BYTE_SHIFT) - 1);
/* Look through all the free maps to find the first free block */
first_page = hashp->LAST_FREED >>(hashp->BSHIFT + BYTE_SHIFT);
for ( i = first_page; i <= free_page; i++ ) {
if (!(freep = (u_int32_t *)hashp->mapp[i]) &&
!(freep = fetch_bitmap(hashp, i)))
return (0);
if (i == free_page)
in_use_bits = free_bit;
else
in_use_bits = (hashp->BSIZE << BYTE_SHIFT) - 1;
if (i == first_page) {
bit = hashp->LAST_FREED &
((hashp->BSIZE << BYTE_SHIFT) - 1);
j = bit / BITS_PER_MAP;
bit = rounddown2(bit, BITS_PER_MAP);
} else {
bit = 0;
j = 0;
}
for (; bit <= in_use_bits; j++, bit += BITS_PER_MAP)
if (freep[j] != ALL_SET)
goto found;
}
/* No Free Page Found */
hashp->LAST_FREED = hashp->SPARES[splitnum];
hashp->SPARES[splitnum]++;
offset = hashp->SPARES[splitnum] -
(splitnum ? hashp->SPARES[splitnum - 1] : 0);
#define OVMSG "HASH: Out of overflow pages. Increase page size\n"
if (offset > SPLITMASK) {
if (++splitnum >= NCACHED) {
(void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
errno = EFBIG;
return (0);
}
hashp->OVFL_POINT = splitnum;
hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
hashp->SPARES[splitnum-1]--;
offset = 1;
}
/* Check if we need to allocate a new bitmap page */
if (free_bit == (hashp->BSIZE << BYTE_SHIFT) - 1) {
free_page++;
if (free_page >= NCACHED) {
(void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
errno = EFBIG;
return (0);
}
/*
* This is tricky. The 1 indicates that you want the new page
* allocated with 1 clear bit. Actually, you are going to
* allocate 2 pages from this map. The first is going to be
* the map page, the second is the overflow page we were
* looking for. The init_bitmap routine automatically, sets
* the first bit of itself to indicate that the bitmap itself
* is in use. We would explicitly set the second bit, but
* don't have to if we tell init_bitmap not to leave it clear
* in the first place.
*/
if (__ibitmap(hashp,
(int)OADDR_OF(splitnum, offset), 1, free_page))
return (0);
hashp->SPARES[splitnum]++;
#ifdef DEBUG2
free_bit = 2;
#endif
offset++;
if (offset > SPLITMASK) {
if (++splitnum >= NCACHED) {
(void)_write(STDERR_FILENO, OVMSG,
sizeof(OVMSG) - 1);
errno = EFBIG;
return (0);
}
hashp->OVFL_POINT = splitnum;
hashp->SPARES[splitnum] = hashp->SPARES[splitnum-1];
hashp->SPARES[splitnum-1]--;
offset = 0;
}
} else {
/*
* Free_bit addresses the last used bit. Bump it to address
* the first available bit.
*/
free_bit++;
SETBIT(freep, free_bit);
}
/* Calculate address of the new overflow page */
addr = OADDR_OF(splitnum, offset);
#ifdef DEBUG2
(void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
addr, free_bit, free_page);
#endif
return (addr);
found:
bit = bit + first_free(freep[j]);
SETBIT(freep, bit);
#ifdef DEBUG2
tmp1 = bit;
tmp2 = i;
#endif
/*
* Bits are addressed starting with 0, but overflow pages are addressed
* beginning at 1. Bit is a bit addressnumber, so we need to increment
* it to convert it to a page number.
*/
bit = 1 + bit + (i * (hashp->BSIZE << BYTE_SHIFT));
if (bit >= hashp->LAST_FREED)
hashp->LAST_FREED = bit - 1;
/* Calculate the split number for this page */
for (i = 0; (i < splitnum) && (bit > hashp->SPARES[i]); i++);
offset = (i ? bit - hashp->SPARES[i - 1] : bit);
if (offset >= SPLITMASK) {
(void)_write(STDERR_FILENO, OVMSG, sizeof(OVMSG) - 1);
errno = EFBIG;
return (0); /* Out of overflow pages */
}
addr = OADDR_OF(i, offset);
#ifdef DEBUG2
(void)fprintf(stderr, "OVERFLOW_PAGE: ADDR: %d BIT: %d PAGE %d\n",
addr, tmp1, tmp2);
#endif
/* Allocate and return the overflow page */
return (addr);
}
/*
* Mark this overflow page as free.
*/
void
__free_ovflpage(HTAB *hashp, BUFHEAD *obufp)
{
u_int16_t addr;
u_int32_t *freep;
int bit_address, free_page, free_bit;
u_int16_t ndx;
addr = obufp->addr;
#ifdef DEBUG1
(void)fprintf(stderr, "Freeing %d\n", addr);
#endif
ndx = (((u_int16_t)addr) >> SPLITSHIFT);
bit_address =
(ndx ? hashp->SPARES[ndx - 1] : 0) + (addr & SPLITMASK) - 1;
if (bit_address < hashp->LAST_FREED)
hashp->LAST_FREED = bit_address;
free_page = (bit_address >> (hashp->BSHIFT + BYTE_SHIFT));
free_bit = bit_address & ((hashp->BSIZE << BYTE_SHIFT) - 1);
if (!(freep = hashp->mapp[free_page]))
freep = fetch_bitmap(hashp, free_page);
#ifdef DEBUG
/*
* This had better never happen. It means we tried to read a bitmap
* that has already had overflow pages allocated off it, and we
* failed to read it from the file.
*/
if (!freep)
assert(0);
#endif
CLRBIT(freep, free_bit);
#ifdef DEBUG2
(void)fprintf(stderr, "FREE_OVFLPAGE: ADDR: %d BIT: %d PAGE %d\n",
obufp->addr, free_bit, free_page);
#endif
__reclaim_buf(hashp, obufp);
}
/*
* Returns:
* 0 success
* -1 failure
*/
static int
open_temp(HTAB *hashp)
{
sigset_t set, oset;
int len;
char *envtmp;
char path[MAXPATHLEN];
envtmp = secure_getenv("TMPDIR");
len = snprintf(path,
sizeof(path), "%s/_hash.XXXXXX", envtmp ? envtmp : "/tmp");
if (len < 0 || len >= (int)sizeof(path)) {
errno = ENAMETOOLONG;
return (-1);
}
/* Block signals; make sure file goes away at process exit. */
(void)sigfillset(&set);
(void)__libc_sigprocmask(SIG_BLOCK, &set, &oset);
if ((hashp->fp = mkostemp(path, O_CLOEXEC)) != -1)
(void)unlink(path);
(void)__libc_sigprocmask(SIG_SETMASK, &oset, (sigset_t *)NULL);
return (hashp->fp != -1 ? 0 : -1);
}
/*
* We have to know that the key will fit, but the last entry on the page is
* an overflow pair, so we need to shift things.
*/
static void
squeeze_key(u_int16_t *sp, const DBT *key, const DBT *val)
{
char *p;
u_int16_t free_space, n, off, pageno;
p = (char *)sp;
n = sp[0];
free_space = FREESPACE(sp);
off = OFFSET(sp);
pageno = sp[n - 1];
off -= key->size;
sp[n - 1] = off;
memmove(p + off, key->data, key->size);
off -= val->size;
sp[n] = off;
memmove(p + off, val->data, val->size);
sp[0] = n + 2;
sp[n + 1] = pageno;
sp[n + 2] = OVFLPAGE;
FREESPACE(sp) = free_space - PAIRSIZE(key, val);
OFFSET(sp) = off;
}
static u_int32_t *
fetch_bitmap(HTAB *hashp, int ndx)
{
if (ndx >= hashp->nmaps)
return (NULL);
if ((hashp->mapp[ndx] = (u_int32_t *)malloc(hashp->BSIZE)) == NULL)
return (NULL);
if (__get_page(hashp,
(char *)hashp->mapp[ndx], hashp->BITMAPS[ndx], 0, 1, 1)) {
free(hashp->mapp[ndx]);
return (NULL);
}
return (hashp->mapp[ndx]);
}
#ifdef DEBUG4
int
print_chain(int addr)
{
BUFHEAD *bufp;
short *bp, oaddr;
(void)fprintf(stderr, "%d ", addr);
bufp = __get_buf(hashp, addr, NULL, 0);
bp = (short *)bufp->page;
while (bp[0] && ((bp[bp[0]] == OVFLPAGE) ||
((bp[0] > 2) && bp[2] < REAL_KEY))) {
oaddr = bp[bp[0] - 1];
(void)fprintf(stderr, "%d ", (int)oaddr);
bufp = __get_buf(hashp, (int)oaddr, bufp, 0);
bp = (short *)bufp->page;
}
(void)fprintf(stderr, "\n");
}
#endif
diff --git a/lib/libc/db/hash/ndbm.c b/lib/libc/db/hash/ndbm.c
index 08e2dc7d3eea..0c638ab4a9e9 100644
--- a/lib/libc/db/hash/ndbm.c
+++ b/lib/libc/db/hash/ndbm.c
@@ -1,212 +1,211 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ndbm.c 8.4 (Berkeley) 7/21/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* This package provides a dbm compatible interface to the new hashing
* package described in db(3).
*/
#include <sys/param.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ndbm.h>
#include "hash.h"
/*
* Returns:
* *DBM on success
* NULL on failure
*/
extern DBM *
dbm_open(const char *file, int flags, mode_t mode)
{
HASHINFO info;
char path[MAXPATHLEN];
info.bsize = 4096;
info.ffactor = 40;
info.nelem = 1;
info.cachesize = 0;
info.hash = NULL;
info.lorder = 0;
if( strlen(file) >= sizeof(path) - strlen(DBM_SUFFIX)) {
errno = ENAMETOOLONG;
return(NULL);
}
(void)strcpy(path, file);
(void)strcat(path, DBM_SUFFIX);
return ((DBM *)__hash_open(path, flags, mode, &info, 0));
}
extern void
dbm_close(DBM *db)
{
(void)(db->close)(db);
}
/*
* Returns:
* DATUM on success
* NULL on failure
*/
extern datum
dbm_fetch(DBM *db, datum key)
{
datum retdata;
int status;
DBT dbtkey, dbtretdata;
dbtkey.data = key.dptr;
dbtkey.size = key.dsize;
status = (db->get)(db, &dbtkey, &dbtretdata, 0);
if (status) {
dbtretdata.data = NULL;
dbtretdata.size = 0;
}
retdata.dptr = dbtretdata.data;
retdata.dsize = dbtretdata.size;
return (retdata);
}
/*
* Returns:
* DATUM on success
* NULL on failure
*/
extern datum
dbm_firstkey(DBM *db)
{
int status;
datum retkey;
DBT dbtretkey, dbtretdata;
status = (db->seq)(db, &dbtretkey, &dbtretdata, R_FIRST);
if (status)
dbtretkey.data = NULL;
retkey.dptr = dbtretkey.data;
retkey.dsize = dbtretkey.size;
return (retkey);
}
/*
* Returns:
* DATUM on success
* NULL on failure
*/
extern datum
dbm_nextkey(DBM *db)
{
int status;
datum retkey;
DBT dbtretkey, dbtretdata;
status = (db->seq)(db, &dbtretkey, &dbtretdata, R_NEXT);
if (status)
dbtretkey.data = NULL;
retkey.dptr = dbtretkey.data;
retkey.dsize = dbtretkey.size;
return (retkey);
}
/*
* Returns:
* 0 on success
* <0 failure
*/
extern int
dbm_delete(DBM *db, datum key)
{
int status;
DBT dbtkey;
dbtkey.data = key.dptr;
dbtkey.size = key.dsize;
status = (db->del)(db, &dbtkey, 0);
if (status)
return (-1);
else
return (0);
}
/*
* Returns:
* 0 on success
* <0 failure
* 1 if DBM_INSERT and entry exists
*/
extern int
dbm_store(DBM *db, datum key, datum data, int flags)
{
DBT dbtkey, dbtdata;
dbtkey.data = key.dptr;
dbtkey.size = key.dsize;
dbtdata.data = data.dptr;
dbtdata.size = data.dsize;
return ((db->put)(db, &dbtkey, &dbtdata,
(flags == DBM_INSERT) ? R_NOOVERWRITE : 0));
}
extern int
dbm_error(DBM *db)
{
HTAB *hp;
hp = (HTAB *)db->internal;
return (hp->error);
}
extern int
dbm_clearerr(DBM *db)
{
HTAB *hp;
hp = (HTAB *)db->internal;
hp->error = 0;
return (0);
}
extern int
dbm_dirfno(DBM *db)
{
return(((HTAB *)db->internal)->fp);
}
diff --git a/lib/libc/db/mpool/mpool-compat.c b/lib/libc/db/mpool/mpool-compat.c
index ef0e340f641e..191b1cf6089b 100644
--- a/lib/libc/db/mpool/mpool-compat.c
+++ b/lib/libc/db/mpool/mpool-compat.c
@@ -1,42 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 Xin LI <delphij@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <db.h>
#include <mpool.h>
void *__mpool_new__44bsd(MPOOL *, pgno_t *);
void *
__mpool_new__44bsd(MPOOL *mp, pgno_t *pgnoaddr)
{
return (mpool_new(mp, pgnoaddr, MPOOL_PAGE_NEXT));
}
__sym_compat(mpool_new, __mpool_new_44bsd, FBSD_1.0);
diff --git a/lib/libc/db/mpool/mpool.c b/lib/libc/db/mpool/mpool.c
index 24dd1b68aaac..feeea517315c 100644
--- a/lib/libc/db/mpool/mpool.c
+++ b/lib/libc/db/mpool/mpool.c
@@ -1,493 +1,492 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mpool.c 8.7 (Berkeley) 11/2/95";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include <db.h>
#define __MPOOLINTERFACE_PRIVATE
#include <mpool.h>
static BKT *mpool_bkt(MPOOL *);
static BKT *mpool_look(MPOOL *, pgno_t);
static int mpool_write(MPOOL *, BKT *);
/*
* mpool_open --
* Initialize a memory pool.
*/
/* ARGSUSED */
MPOOL *
mpool_open(void *key, int fd, pgno_t pagesize, pgno_t maxcache)
{
struct stat sb;
MPOOL *mp;
int entry;
/*
* Get information about the file.
*
* XXX
* We don't currently handle pipes, although we should.
*/
if (_fstat(fd, &sb))
return (NULL);
if (!S_ISREG(sb.st_mode)) {
errno = ESPIPE;
return (NULL);
}
/* Allocate and initialize the MPOOL cookie. */
if ((mp = (MPOOL *)calloc(1, sizeof(MPOOL))) == NULL)
return (NULL);
TAILQ_INIT(&mp->lqh);
for (entry = 0; entry < HASHSIZE; ++entry)
TAILQ_INIT(&mp->hqh[entry]);
mp->maxcache = maxcache;
mp->npages = sb.st_size / pagesize;
mp->pagesize = pagesize;
mp->fd = fd;
return (mp);
}
/*
* mpool_filter --
* Initialize input/output filters.
*/
void
mpool_filter(MPOOL *mp, void (*pgin) (void *, pgno_t, void *),
void (*pgout) (void *, pgno_t, void *), void *pgcookie)
{
mp->pgin = pgin;
mp->pgout = pgout;
mp->pgcookie = pgcookie;
}
/*
* mpool_new --
* Get a new page of memory.
*/
void *
mpool_new(MPOOL *mp, pgno_t *pgnoaddr, u_int flags)
{
struct _hqh *head;
BKT *bp;
if (mp->npages == MAX_PAGE_NUMBER) {
(void)fprintf(stderr, "mpool_new: page allocation overflow.\n");
abort();
}
#ifdef STATISTICS
++mp->pagenew;
#endif
/*
* Get a BKT from the cache. Assign a new page number, attach
* it to the head of the hash chain, the tail of the lru chain,
* and return.
*/
if ((bp = mpool_bkt(mp)) == NULL)
return (NULL);
if (flags == MPOOL_PAGE_REQUEST) {
mp->npages++;
bp->pgno = *pgnoaddr;
} else
bp->pgno = *pgnoaddr = mp->npages++;
bp->flags = MPOOL_PINNED | MPOOL_INUSE;
head = &mp->hqh[HASHKEY(bp->pgno)];
TAILQ_INSERT_HEAD(head, bp, hq);
TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
return (bp->page);
}
int
mpool_delete(MPOOL *mp, void *page)
{
struct _hqh *head;
BKT *bp;
bp = (BKT *)((char *)page - sizeof(BKT));
#ifdef DEBUG
if (!(bp->flags & MPOOL_PINNED)) {
(void)fprintf(stderr,
"mpool_delete: page %d not pinned\n", bp->pgno);
abort();
}
#endif
/* Remove from the hash and lru queues. */
head = &mp->hqh[HASHKEY(bp->pgno)];
TAILQ_REMOVE(head, bp, hq);
TAILQ_REMOVE(&mp->lqh, bp, q);
free(bp);
mp->curcache--;
return (RET_SUCCESS);
}
/*
* mpool_get
* Get a page.
*/
/* ARGSUSED */
void *
mpool_get(MPOOL *mp, pgno_t pgno,
u_int flags) /* XXX not used? */
{
struct _hqh *head;
BKT *bp;
off_t off;
int nr;
#ifdef STATISTICS
++mp->pageget;
#endif
/* Check for a page that is cached. */
if ((bp = mpool_look(mp, pgno)) != NULL) {
#ifdef DEBUG
if (!(flags & MPOOL_IGNOREPIN) && bp->flags & MPOOL_PINNED) {
(void)fprintf(stderr,
"mpool_get: page %d already pinned\n", bp->pgno);
abort();
}
#endif
/*
* Move the page to the head of the hash chain and the tail
* of the lru chain.
*/
head = &mp->hqh[HASHKEY(bp->pgno)];
TAILQ_REMOVE(head, bp, hq);
TAILQ_INSERT_HEAD(head, bp, hq);
TAILQ_REMOVE(&mp->lqh, bp, q);
TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
/* Return a pinned page. */
bp->flags |= MPOOL_PINNED;
return (bp->page);
}
/* Get a page from the cache. */
if ((bp = mpool_bkt(mp)) == NULL)
return (NULL);
/* Read in the contents. */
off = mp->pagesize * pgno;
if ((nr = pread(mp->fd, bp->page, mp->pagesize, off)) != (ssize_t)mp->pagesize) {
switch (nr) {
case -1:
/* errno is set for us by pread(). */
free(bp);
mp->curcache--;
return (NULL);
case 0:
/*
* A zero-length read means you need to create a
* new page.
*/
memset(bp->page, 0, mp->pagesize);
break;
default:
/* A partial read is definitely bad. */
free(bp);
mp->curcache--;
errno = EINVAL;
return (NULL);
}
}
#ifdef STATISTICS
++mp->pageread;
#endif
/* Set the page number, pin the page. */
bp->pgno = pgno;
if (!(flags & MPOOL_IGNOREPIN))
bp->flags = MPOOL_PINNED;
bp->flags |= MPOOL_INUSE;
/*
* Add the page to the head of the hash chain and the tail
* of the lru chain.
*/
head = &mp->hqh[HASHKEY(bp->pgno)];
TAILQ_INSERT_HEAD(head, bp, hq);
TAILQ_INSERT_TAIL(&mp->lqh, bp, q);
/* Run through the user's filter. */
if (mp->pgin != NULL)
(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
return (bp->page);
}
/*
* mpool_put
* Return a page.
*/
/* ARGSUSED */
int
mpool_put(MPOOL *mp, void *page, u_int flags)
{
BKT *bp;
#ifdef STATISTICS
++mp->pageput;
#endif
bp = (BKT *)((char *)page - sizeof(BKT));
#ifdef DEBUG
if (!(bp->flags & MPOOL_PINNED)) {
(void)fprintf(stderr,
"mpool_put: page %d not pinned\n", bp->pgno);
abort();
}
#endif
bp->flags &= ~MPOOL_PINNED;
if (flags & MPOOL_DIRTY)
bp->flags |= flags & MPOOL_DIRTY;
return (RET_SUCCESS);
}
/*
* mpool_close
* Close the buffer pool.
*/
int
mpool_close(MPOOL *mp)
{
BKT *bp;
/* Free up any space allocated to the lru pages. */
while (!TAILQ_EMPTY(&mp->lqh)) {
bp = TAILQ_FIRST(&mp->lqh);
TAILQ_REMOVE(&mp->lqh, bp, q);
free(bp);
}
/* Free the MPOOL cookie. */
free(mp);
return (RET_SUCCESS);
}
/*
* mpool_sync
* Sync the pool to disk.
*/
int
mpool_sync(MPOOL *mp)
{
BKT *bp;
/* Walk the lru chain, flushing any dirty pages to disk. */
TAILQ_FOREACH(bp, &mp->lqh, q)
if (bp->flags & MPOOL_DIRTY &&
mpool_write(mp, bp) == RET_ERROR)
return (RET_ERROR);
/* Sync the file descriptor. */
return (_fsync(mp->fd) ? RET_ERROR : RET_SUCCESS);
}
/*
* mpool_bkt
* Get a page from the cache (or create one).
*/
static BKT *
mpool_bkt(MPOOL *mp)
{
struct _hqh *head;
BKT *bp;
/* If under the max cached, always create a new page. */
if (mp->curcache < mp->maxcache)
goto new;
/*
* If the cache is max'd out, walk the lru list for a buffer we
* can flush. If we find one, write it (if necessary) and take it
* off any lists. If we don't find anything we grow the cache anyway.
* The cache never shrinks.
*/
TAILQ_FOREACH(bp, &mp->lqh, q)
if (!(bp->flags & MPOOL_PINNED)) {
/* Flush if dirty. */
if (bp->flags & MPOOL_DIRTY &&
mpool_write(mp, bp) == RET_ERROR)
return (NULL);
#ifdef STATISTICS
++mp->pageflush;
#endif
/* Remove from the hash and lru queues. */
head = &mp->hqh[HASHKEY(bp->pgno)];
TAILQ_REMOVE(head, bp, hq);
TAILQ_REMOVE(&mp->lqh, bp, q);
#ifdef DEBUG
{ void *spage;
spage = bp->page;
memset(bp, 0xff, sizeof(BKT) + mp->pagesize);
bp->page = spage;
}
#endif
bp->flags = 0;
return (bp);
}
new: if ((bp = (BKT *)calloc(1, sizeof(BKT) + mp->pagesize)) == NULL)
return (NULL);
#ifdef STATISTICS
++mp->pagealloc;
#endif
bp->page = (char *)bp + sizeof(BKT);
bp->flags = 0;
++mp->curcache;
return (bp);
}
/*
* mpool_write
* Write a page to disk.
*/
static int
mpool_write(MPOOL *mp, BKT *bp)
{
off_t off;
#ifdef STATISTICS
++mp->pagewrite;
#endif
/* Run through the user's filter. */
if (mp->pgout)
(mp->pgout)(mp->pgcookie, bp->pgno, bp->page);
off = mp->pagesize * bp->pgno;
if (pwrite(mp->fd, bp->page, mp->pagesize, off) != (ssize_t)mp->pagesize)
return (RET_ERROR);
/*
* Re-run through the input filter since this page may soon be
* accessed via the cache, and whatever the user's output filter
* did may screw things up if we don't let the input filter
* restore the in-core copy.
*/
if (mp->pgin)
(mp->pgin)(mp->pgcookie, bp->pgno, bp->page);
bp->flags &= ~MPOOL_DIRTY;
return (RET_SUCCESS);
}
/*
* mpool_look
* Lookup a page in the cache.
*/
static BKT *
mpool_look(MPOOL *mp, pgno_t pgno)
{
struct _hqh *head;
BKT *bp;
head = &mp->hqh[HASHKEY(pgno)];
TAILQ_FOREACH(bp, head, hq)
if ((bp->pgno == pgno) &&
((bp->flags & MPOOL_INUSE) == MPOOL_INUSE)) {
#ifdef STATISTICS
++mp->cachehit;
#endif
return (bp);
}
#ifdef STATISTICS
++mp->cachemiss;
#endif
return (NULL);
}
#ifdef STATISTICS
/*
* mpool_stat
* Print out cache statistics.
*/
void
mpool_stat(MPOOL *mp)
{
BKT *bp;
int cnt;
char *sep;
(void)fprintf(stderr, "%lu pages in the file\n", mp->npages);
(void)fprintf(stderr,
"page size %lu, cacheing %lu pages of %lu page max cache\n",
mp->pagesize, mp->curcache, mp->maxcache);
(void)fprintf(stderr, "%lu page puts, %lu page gets, %lu page new\n",
mp->pageput, mp->pageget, mp->pagenew);
(void)fprintf(stderr, "%lu page allocs, %lu page flushes\n",
mp->pagealloc, mp->pageflush);
if (mp->cachehit + mp->cachemiss)
(void)fprintf(stderr,
"%.0f%% cache hit rate (%lu hits, %lu misses)\n",
((double)mp->cachehit / (mp->cachehit + mp->cachemiss))
* 100, mp->cachehit, mp->cachemiss);
(void)fprintf(stderr, "%lu page reads, %lu page writes\n",
mp->pageread, mp->pagewrite);
sep = "";
cnt = 0;
TAILQ_FOREACH(bp, &mp->lqh, q) {
(void)fprintf(stderr, "%s%d", sep, bp->pgno);
if (bp->flags & MPOOL_DIRTY)
(void)fprintf(stderr, "d");
if (bp->flags & MPOOL_PINNED)
(void)fprintf(stderr, "P");
if (++cnt == 10) {
sep = "\n";
cnt = 0;
} else
sep = ", ";
}
(void)fprintf(stderr, "\n");
}
#endif
diff --git a/lib/libc/db/recno/rec_close.c b/lib/libc/db/recno/rec_close.c
index 7264f6dabd1f..c3d76488b281 100644
--- a/lib/libc/db/recno/rec_close.c
+++ b/lib/libc/db/recno/rec_close.c
@@ -1,182 +1,181 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rec_close.c 8.6 (Berkeley) 8/18/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/uio.h>
#include <sys/mman.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>
#include "un-namespace.h"
#include <db.h>
#include "recno.h"
/*
* __REC_CLOSE -- Close a recno tree.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_close(DB *dbp)
{
BTREE *t;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
if (__rec_sync(dbp, 0) == RET_ERROR)
return (RET_ERROR);
/* Committed to closing. */
status = RET_SUCCESS;
if (F_ISSET(t, R_MEMMAPPED) && munmap(t->bt_smap, t->bt_msize))
status = RET_ERROR;
if (!F_ISSET(t, R_INMEM)) {
if (F_ISSET(t, R_CLOSEFP)) {
if (fclose(t->bt_rfp))
status = RET_ERROR;
} else {
if (_close(t->bt_rfd))
status = RET_ERROR;
}
}
if (__bt_close(dbp) == RET_ERROR)
status = RET_ERROR;
return (status);
}
/*
* __REC_SYNC -- sync the recno tree to disk.
*
* Parameters:
* dbp: pointer to access method
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__rec_sync(const DB *dbp, u_int flags)
{
struct iovec iov[2];
BTREE *t;
DBT data, key;
off_t off;
recno_t scursor, trec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
if (flags == R_RECNOSYNC)
return (__bt_sync(dbp, 0));
if (F_ISSET(t, R_RDONLY | R_INMEM) || !F_ISSET(t, R_MODIFIED))
return (RET_SUCCESS);
/* Read any remaining records into the tree. */
if (!F_ISSET(t, R_EOF) && t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
return (RET_ERROR);
/* Rewind the file descriptor. */
if (lseek(t->bt_rfd, (off_t)0, SEEK_SET) != 0)
return (RET_ERROR);
/* Save the cursor. */
scursor = t->bt_cursor.rcursor;
key.size = sizeof(recno_t);
key.data = &trec;
if (F_ISSET(t, R_FIXLEN)) {
/*
* We assume that fixed length records are all fixed length.
* Any that aren't are either EINVAL'd or corrected by the
* record put code.
*/
status = (dbp->seq)(dbp, &key, &data, R_FIRST);
while (status == RET_SUCCESS) {
if (_write(t->bt_rfd, data.data, data.size) !=
(ssize_t)data.size)
return (RET_ERROR);
status = (dbp->seq)(dbp, &key, &data, R_NEXT);
}
} else {
iov[1].iov_base = &t->bt_bval;
iov[1].iov_len = 1;
status = (dbp->seq)(dbp, &key, &data, R_FIRST);
while (status == RET_SUCCESS) {
iov[0].iov_base = data.data;
iov[0].iov_len = data.size;
if (_writev(t->bt_rfd, iov, 2) != (ssize_t)(data.size + 1))
return (RET_ERROR);
status = (dbp->seq)(dbp, &key, &data, R_NEXT);
}
}
/* Restore the cursor. */
t->bt_cursor.rcursor = scursor;
if (status == RET_ERROR)
return (RET_ERROR);
if ((off = lseek(t->bt_rfd, (off_t)0, SEEK_CUR)) == -1)
return (RET_ERROR);
if (ftruncate(t->bt_rfd, off))
return (RET_ERROR);
F_CLR(t, R_MODIFIED);
return (RET_SUCCESS);
}
diff --git a/lib/libc/db/recno/rec_delete.c b/lib/libc/db/recno/rec_delete.c
index 2e3caac31f0d..749c46128700 100644
--- a/lib/libc/db/recno/rec_delete.c
+++ b/lib/libc/db/recno/rec_delete.c
@@ -1,187 +1,186 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rec_delete.c 8.7 (Berkeley) 7/14/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <db.h>
#include "recno.h"
static int rec_rdelete(BTREE *, recno_t);
/*
* __REC_DELETE -- Delete the item(s) referenced by a key.
*
* Parameters:
* dbp: pointer to access method
* key: key to delete
* flags: R_CURSOR if deleting what the cursor references
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
int
__rec_delete(const DB *dbp, const DBT *key, u_int flags)
{
BTREE *t;
recno_t nrec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
switch(flags) {
case 0:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
if (nrec > t->bt_nrecs)
return (RET_SPECIAL);
--nrec;
status = rec_rdelete(t, nrec);
break;
case R_CURSOR:
if (!F_ISSET(&t->bt_cursor, CURS_INIT))
goto einval;
if (t->bt_nrecs == 0)
return (RET_SPECIAL);
status = rec_rdelete(t, t->bt_cursor.rcursor - 1);
if (status == RET_SUCCESS)
--t->bt_cursor.rcursor;
break;
default:
einval: errno = EINVAL;
return (RET_ERROR);
}
if (status == RET_SUCCESS)
F_SET(t, B_MODIFIED | R_MODIFIED);
return (status);
}
/*
* REC_RDELETE -- Delete the data matching the specified key.
*
* Parameters:
* tree: tree
* nrec: record to delete
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
static int
rec_rdelete(BTREE *t, recno_t nrec)
{
EPG *e;
PAGE *h;
int status;
/* Find the record; __rec_search pins the page. */
if ((e = __rec_search(t, nrec, SDELETE)) == NULL)
return (RET_ERROR);
/* Delete the record. */
h = e->page;
status = __rec_dleaf(t, h, e->index);
if (status != RET_SUCCESS) {
mpool_put(t->bt_mp, h, 0);
return (status);
}
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
/*
* __REC_DLEAF -- Delete a single record from a recno leaf page.
*
* Parameters:
* t: tree
* idx: index on current page to delete
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__rec_dleaf(BTREE *t, PAGE *h, u_int32_t idx)
{
RLEAF *rl;
indx_t *ip, cnt, offset;
u_int32_t nbytes;
char *from;
void *to;
/*
* Delete a record from a recno leaf page. Internal records are never
* deleted from internal pages, regardless of the records that caused
* them to be added being deleted. Pages made empty by deletion are
* not reclaimed. They are, however, made available for reuse.
*
* Pack the remaining entries at the end of the page, shift the indices
* down, overwriting the deleted record and its index. If the record
* uses overflow pages, make them available for reuse.
*/
to = rl = GETRLEAF(h, idx);
if (rl->flags & P_BIGDATA && __ovfl_delete(t, rl->bytes) == RET_ERROR)
return (RET_ERROR);
nbytes = NRLEAF(rl);
/*
* Compress the key/data pairs. Compress and adjust the [BR]LEAF
* offsets. Reset the headers.
*/
from = (char *)h + h->upper;
memmove(from + nbytes, from, (char *)to - from);
h->upper += nbytes;
offset = h->linp[idx];
for (cnt = &h->linp[idx] - (ip = &h->linp[0]); cnt--; ++ip)
if (ip[0] < offset)
ip[0] += nbytes;
for (cnt = &h->linp[NEXTINDEX(h)] - ip; --cnt; ++ip)
ip[0] = ip[1] < offset ? ip[1] + nbytes : ip[1];
h->lower -= sizeof(indx_t);
--t->bt_nrecs;
return (RET_SUCCESS);
}
diff --git a/lib/libc/db/recno/rec_get.c b/lib/libc/db/recno/rec_get.c
index 5a47871af78c..c28018c55baf 100644
--- a/lib/libc/db/recno/rec_get.c
+++ b/lib/libc/db/recno/rec_get.c
@@ -1,291 +1,290 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rec_get.c 8.9 (Berkeley) 8/18/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
#include "recno.h"
/*
* __REC_GET -- Get a record from the btree.
*
* Parameters:
* dbp: pointer to access method
* key: key to find
* data: data to return
* flag: currently unused
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key not found.
*/
int
__rec_get(const DB *dbp, const DBT *key, DBT *data, u_int flags)
{
BTREE *t;
EPG *e;
recno_t nrec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* Get currently doesn't take any flags, and keys of 0 are illegal. */
if (flags || (nrec = *(recno_t *)key->data) == 0) {
errno = EINVAL;
return (RET_ERROR);
}
/*
* If we haven't seen this record yet, try to find it in the
* original file.
*/
if (nrec > t->bt_nrecs) {
if (F_ISSET(t, R_EOF | R_INMEM))
return (RET_SPECIAL);
if ((status = t->bt_irec(t, nrec)) != RET_SUCCESS)
return (status);
}
--nrec;
if ((e = __rec_search(t, nrec, SEARCH)) == NULL)
return (RET_ERROR);
status = __rec_ret(t, e, 0, NULL, data);
if (F_ISSET(t, B_DB_LOCK))
mpool_put(t->bt_mp, e->page, 0);
else
t->bt_pinned = e->page;
return (status);
}
/*
* __REC_FPIPE -- Get fixed length records from a pipe.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_fpipe(BTREE *t, recno_t top)
{
DBT data;
recno_t nrec;
size_t len;
int ch;
u_char *p;
if (t->bt_rdata.size < t->bt_reclen) {
t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_reclen);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
t->bt_rdata.size = t->bt_reclen;
}
data.data = t->bt_rdata.data;
data.size = t->bt_reclen;
for (nrec = t->bt_nrecs; nrec < top;) {
len = t->bt_reclen;
for (p = t->bt_rdata.data;; *p++ = ch)
if ((ch = getc(t->bt_rfp)) == EOF || !--len) {
if (ch != EOF)
*p = ch;
if (len != 0)
memset(p, t->bt_bval, len);
if (__rec_iput(t,
nrec, &data, 0) != RET_SUCCESS)
return (RET_ERROR);
++nrec;
break;
}
if (ch == EOF)
break;
}
if (nrec < top) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
return (RET_SUCCESS);
}
/*
* __REC_VPIPE -- Get variable length records from a pipe.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_vpipe(BTREE *t, recno_t top)
{
DBT data;
recno_t nrec;
size_t len;
size_t sz;
int bval, ch;
u_char *p;
bval = t->bt_bval;
for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
for (p = t->bt_rdata.data,
sz = t->bt_rdata.size;; *p++ = ch, --sz) {
if ((ch = getc(t->bt_rfp)) == EOF || ch == bval) {
data.data = t->bt_rdata.data;
data.size = p - (u_char *)t->bt_rdata.data;
if (ch == EOF && data.size == 0)
break;
if (__rec_iput(t, nrec, &data, 0)
!= RET_SUCCESS)
return (RET_ERROR);
break;
}
if (sz == 0) {
len = p - (u_char *)t->bt_rdata.data;
t->bt_rdata.size += (sz = 256);
t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_rdata.size);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
p = (u_char *)t->bt_rdata.data + len;
}
}
if (ch == EOF)
break;
}
if (nrec < top) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
return (RET_SUCCESS);
}
/*
* __REC_FMAP -- Get fixed length records from a file.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_fmap(BTREE *t, recno_t top)
{
DBT data;
recno_t nrec;
u_char *sp, *ep, *p;
size_t len;
if (t->bt_rdata.size < t->bt_reclen) {
t->bt_rdata.data = reallocf(t->bt_rdata.data, t->bt_reclen);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
t->bt_rdata.size = t->bt_reclen;
}
data.data = t->bt_rdata.data;
data.size = t->bt_reclen;
sp = (u_char *)t->bt_cmap;
ep = (u_char *)t->bt_emap;
for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
if (sp >= ep) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
len = t->bt_reclen;
for (p = t->bt_rdata.data;
sp < ep && len > 0; *p++ = *sp++, --len);
if (len != 0)
memset(p, t->bt_bval, len);
if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
return (RET_ERROR);
}
t->bt_cmap = (caddr_t)sp;
return (RET_SUCCESS);
}
/*
* __REC_VMAP -- Get variable length records from a file.
*
* Parameters:
* t: tree
* cnt: records to read
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_vmap(BTREE *t, recno_t top)
{
DBT data;
u_char *sp, *ep;
recno_t nrec;
int bval;
sp = (u_char *)t->bt_cmap;
ep = (u_char *)t->bt_emap;
bval = t->bt_bval;
for (nrec = t->bt_nrecs; nrec < top; ++nrec) {
if (sp >= ep) {
F_SET(t, R_EOF);
return (RET_SPECIAL);
}
for (data.data = sp; sp < ep && *sp != bval; ++sp);
data.size = sp - (u_char *)data.data;
if (__rec_iput(t, nrec, &data, 0) != RET_SUCCESS)
return (RET_ERROR);
++sp;
}
t->bt_cmap = (caddr_t)sp;
return (RET_SUCCESS);
}
diff --git a/lib/libc/db/recno/rec_open.c b/lib/libc/db/recno/rec_open.c
index ca1d58f1526a..9ef076ba2652 100644
--- a/lib/libc/db/recno/rec_open.c
+++ b/lib/libc/db/recno/rec_open.c
@@ -1,238 +1,237 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rec_open.c 8.10 (Berkeley) 9/1/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stddef.h>
#include <stdio.h>
#include <unistd.h>
#include "un-namespace.h"
#include <db.h>
#include "recno.h"
DB *
__rec_open(const char *fname, int flags, int mode, const RECNOINFO *openinfo,
int dflags)
{
BTREE *t;
BTREEINFO btopeninfo;
DB *dbp;
PAGE *h;
struct stat sb;
int rfd, sverrno;
/* Open the user's file -- if this fails, we're done. */
if (fname != NULL && (rfd = _open(fname, flags | O_CLOEXEC, mode)) < 0)
return (NULL);
/* Create a btree in memory (backed by disk). */
dbp = NULL;
if (openinfo) {
if (openinfo->flags & ~(R_FIXEDLEN | R_NOKEY | R_SNAPSHOT))
goto einval;
btopeninfo.flags = 0;
btopeninfo.cachesize = openinfo->cachesize;
btopeninfo.maxkeypage = 0;
btopeninfo.minkeypage = 0;
btopeninfo.psize = openinfo->psize;
btopeninfo.compare = NULL;
btopeninfo.prefix = NULL;
btopeninfo.lorder = openinfo->lorder;
dbp = __bt_open(openinfo->bfname,
O_RDWR, S_IRUSR | S_IWUSR, &btopeninfo, dflags);
} else
dbp = __bt_open(NULL, O_RDWR, S_IRUSR | S_IWUSR, NULL, dflags);
if (dbp == NULL)
goto err;
/*
* Some fields in the tree structure are recno specific. Fill them
* in and make the btree structure look like a recno structure. We
* don't change the bt_ovflsize value, it's close enough and slightly
* bigger.
*/
t = dbp->internal;
if (openinfo) {
if (openinfo->flags & R_FIXEDLEN) {
F_SET(t, R_FIXLEN);
t->bt_reclen = openinfo->reclen;
if (t->bt_reclen == 0)
goto einval;
}
t->bt_bval = openinfo->bval;
} else
t->bt_bval = '\n';
F_SET(t, R_RECNO);
if (fname == NULL)
F_SET(t, R_EOF | R_INMEM);
else
t->bt_rfd = rfd;
if (fname != NULL) {
/*
* In 4.4BSD, stat(2) returns true for ISSOCK on pipes.
* Unfortunately, that's not portable, so we use lseek
* and check the errno values.
*/
errno = 0;
if (lseek(rfd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) {
switch (flags & O_ACCMODE) {
case O_RDONLY:
F_SET(t, R_RDONLY);
break;
default:
goto einval;
}
slow: if ((t->bt_rfp = fdopen(rfd, "r")) == NULL)
goto err;
F_SET(t, R_CLOSEFP);
t->bt_irec =
F_ISSET(t, R_FIXLEN) ? __rec_fpipe : __rec_vpipe;
} else {
switch (flags & O_ACCMODE) {
case O_RDONLY:
F_SET(t, R_RDONLY);
break;
case O_RDWR:
break;
default:
goto einval;
}
if (_fstat(rfd, &sb))
goto err;
/*
* Kluge -- we'd like to test to see if the file is too
* big to mmap. Since, we don't know what size or type
* off_t's or size_t's are, what the largest unsigned
* integral type is, or what random insanity the local
* C compiler will perpetrate, doing the comparison in
* a portable way is flatly impossible. Hope that mmap
* fails if the file is too large.
*/
if (sb.st_size == 0)
F_SET(t, R_EOF);
else {
#ifdef MMAP_NOT_AVAILABLE
/*
* XXX
* Mmap doesn't work correctly on many current
* systems. In particular, it can fail subtly,
* with cache coherency problems. Don't use it
* for now.
*/
t->bt_msize = sb.st_size;
if ((t->bt_smap = mmap(NULL, t->bt_msize,
PROT_READ, MAP_PRIVATE, rfd,
(off_t)0)) == MAP_FAILED)
goto slow;
t->bt_cmap = t->bt_smap;
t->bt_emap = t->bt_smap + sb.st_size;
t->bt_irec = F_ISSET(t, R_FIXLEN) ?
__rec_fmap : __rec_vmap;
F_SET(t, R_MEMMAPPED);
#else
goto slow;
#endif
}
}
}
/* Use the recno routines. */
dbp->close = __rec_close;
dbp->del = __rec_delete;
dbp->fd = __rec_fd;
dbp->get = __rec_get;
dbp->put = __rec_put;
dbp->seq = __rec_seq;
dbp->sync = __rec_sync;
/* If the root page was created, reset the flags. */
if ((h = mpool_get(t->bt_mp, P_ROOT, 0)) == NULL)
goto err;
if ((h->flags & P_TYPE) == P_BLEAF) {
F_CLR(h, P_TYPE);
F_SET(h, P_RLEAF);
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
} else
mpool_put(t->bt_mp, h, 0);
if (openinfo && openinfo->flags & R_SNAPSHOT &&
!F_ISSET(t, R_EOF | R_INMEM) &&
t->bt_irec(t, MAX_REC_NUMBER) == RET_ERROR)
goto err;
return (dbp);
einval: errno = EINVAL;
err: sverrno = errno;
if (dbp != NULL)
(void)__bt_close(dbp);
if (fname != NULL)
(void)_close(rfd);
errno = sverrno;
return (NULL);
}
int
__rec_fd(const DB *dbp)
{
BTREE *t;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/* In-memory database can't have a file descriptor. */
if (F_ISSET(t, R_INMEM)) {
errno = ENOENT;
return (-1);
}
return (t->bt_rfd);
}
diff --git a/lib/libc/db/recno/rec_put.c b/lib/libc/db/recno/rec_put.c
index e3b307e3450b..b100b9c9b452 100644
--- a/lib/libc/db/recno/rec_put.c
+++ b/lib/libc/db/recno/rec_put.c
@@ -1,274 +1,273 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rec_put.c 8.7 (Berkeley) 8/18/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "recno.h"
/*
* __REC_PUT -- Add a recno item to the tree.
*
* Parameters:
* dbp: pointer to access method
* key: key
* data: data
* flag: R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE
*
* Returns:
* RET_ERROR, RET_SUCCESS and RET_SPECIAL if the key is
* already in the tree and R_NOOVERWRITE specified.
*/
int
__rec_put(const DB *dbp, DBT *key, const DBT *data, u_int flags)
{
BTREE *t;
DBT fdata, tdata;
recno_t nrec;
int status;
t = dbp->internal;
/* Toss any page pinned across calls. */
if (t->bt_pinned != NULL) {
mpool_put(t->bt_mp, t->bt_pinned, 0);
t->bt_pinned = NULL;
}
/*
* If using fixed-length records, and the record is long, return
* EINVAL. If it's short, pad it out. Use the record data return
* memory, it's only short-term.
*/
if (F_ISSET(t, R_FIXLEN) && data->size != t->bt_reclen) {
if (data->size > t->bt_reclen)
goto einval;
if (t->bt_rdata.size < t->bt_reclen) {
t->bt_rdata.data =
reallocf(t->bt_rdata.data, t->bt_reclen);
if (t->bt_rdata.data == NULL)
return (RET_ERROR);
t->bt_rdata.size = t->bt_reclen;
}
memmove(t->bt_rdata.data, data->data, data->size);
memset((char *)t->bt_rdata.data + data->size,
t->bt_bval, t->bt_reclen - data->size);
fdata.data = t->bt_rdata.data;
fdata.size = t->bt_reclen;
} else {
fdata.data = data->data;
fdata.size = data->size;
}
switch (flags) {
case R_CURSOR:
if (!F_ISSET(&t->bt_cursor, CURS_INIT))
goto einval;
nrec = t->bt_cursor.rcursor;
break;
case R_SETCURSOR:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
break;
case R_IAFTER:
if ((nrec = *(recno_t *)key->data) == 0) {
nrec = 1;
flags = R_IBEFORE;
}
break;
case 0:
case R_IBEFORE:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
break;
case R_NOOVERWRITE:
if ((nrec = *(recno_t *)key->data) == 0)
goto einval;
if (nrec <= t->bt_nrecs)
return (RET_SPECIAL);
break;
default:
einval: errno = EINVAL;
return (RET_ERROR);
}
/*
* Make sure that records up to and including the put record are
* already in the database. If skipping records, create empty ones.
*/
if (nrec > t->bt_nrecs) {
if (!F_ISSET(t, R_EOF | R_INMEM) &&
t->bt_irec(t, nrec) == RET_ERROR)
return (RET_ERROR);
if (nrec > t->bt_nrecs + 1) {
if (F_ISSET(t, R_FIXLEN)) {
if ((tdata.data = malloc(t->bt_reclen)) == NULL)
return (RET_ERROR);
tdata.size = t->bt_reclen;
memset(tdata.data, t->bt_bval, tdata.size);
} else {
tdata.data = NULL;
tdata.size = 0;
}
while (nrec > t->bt_nrecs + 1)
if (__rec_iput(t,
t->bt_nrecs, &tdata, 0) != RET_SUCCESS)
return (RET_ERROR);
if (F_ISSET(t, R_FIXLEN))
free(tdata.data);
}
}
if ((status = __rec_iput(t, nrec - 1, &fdata, flags)) != RET_SUCCESS)
return (status);
switch (flags) {
case R_IAFTER:
nrec++;
break;
case R_SETCURSOR:
t->bt_cursor.rcursor = nrec;
break;
}
F_SET(t, R_MODIFIED);
return (__rec_ret(t, NULL, nrec, key, NULL));
}
/*
* __REC_IPUT -- Add a recno item to the tree.
*
* Parameters:
* t: tree
* nrec: record number
* data: data
*
* Returns:
* RET_ERROR, RET_SUCCESS
*/
int
__rec_iput(BTREE *t, recno_t nrec, const DBT *data, u_int flags)
{
DBT tdata;
EPG *e;
PAGE *h;
indx_t idx, nxtindex;
pgno_t pg;
u_int32_t nbytes;
int dflags, status;
char *dest, db[NOVFLSIZE];
/*
* If the data won't fit on a page, store it on indirect pages.
*
* XXX
* If the insert fails later on, these pages aren't recovered.
*/
if (data->size > t->bt_ovflsize) {
if (__ovfl_put(t, data, &pg) == RET_ERROR)
return (RET_ERROR);
tdata.data = db;
tdata.size = NOVFLSIZE;
memcpy(db, &pg, sizeof(pg));
*(u_int32_t *)(db + sizeof(pgno_t)) = data->size;
dflags = P_BIGDATA;
data = &tdata;
} else
dflags = 0;
/* __rec_search pins the returned page. */
if ((e = __rec_search(t, nrec,
nrec > t->bt_nrecs || flags == R_IAFTER || flags == R_IBEFORE ?
SINSERT : SEARCH)) == NULL)
return (RET_ERROR);
h = e->page;
idx = e->index;
/*
* Add the specified key/data pair to the tree. The R_IAFTER and
* R_IBEFORE flags insert the key after/before the specified key.
*
* Pages are split as required.
*/
switch (flags) {
case R_IAFTER:
++idx;
break;
case R_IBEFORE:
break;
default:
if (nrec < t->bt_nrecs &&
__rec_dleaf(t, h, idx) == RET_ERROR) {
mpool_put(t->bt_mp, h, 0);
return (RET_ERROR);
}
break;
}
/*
* If not enough room, split the page. The split code will insert
* the key and data and unpin the current page. If inserting into
* the offset array, shift the pointers up.
*/
nbytes = NRLEAFDBT(data->size);
if ((u_int32_t)(h->upper - h->lower) < nbytes + sizeof(indx_t)) {
status = __bt_split(t, h, NULL, data, dflags, nbytes, idx);
if (status == RET_SUCCESS)
++t->bt_nrecs;
return (status);
}
if (idx < (nxtindex = NEXTINDEX(h)))
memmove(h->linp + idx + 1, h->linp + idx,
(nxtindex - idx) * sizeof(indx_t));
h->lower += sizeof(indx_t);
h->linp[idx] = h->upper -= nbytes;
dest = (char *)h + h->upper;
WR_RLEAF(dest, data, dflags);
++t->bt_nrecs;
F_SET(t, B_MODIFIED);
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
return (RET_SUCCESS);
}
diff --git a/lib/libc/db/recno/rec_search.c b/lib/libc/db/recno/rec_search.c
index c384b9429420..adf43bb25d3c 100644
--- a/lib/libc/db/recno/rec_search.c
+++ b/lib/libc/db/recno/rec_search.c
@@ -1,121 +1,120 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rec_search.c 8.4 (Berkeley) 7/14/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <db.h>
#include "recno.h"
/*
* __REC_SEARCH -- Search a btree for a key.
*
* Parameters:
* t: tree to search
* recno: key to find
* op: search operation
*
* Returns:
* EPG for matching record, if any, or the EPG for the location of the
* key, if it were inserted into the tree.
*
* Returns:
* The EPG for matching record, if any, or the EPG for the location
* of the key, if it were inserted into the tree, is entered into
* the bt_cur field of the tree. A pointer to the field is returned.
*/
EPG *
__rec_search(BTREE *t, recno_t recno, enum SRCHOP op)
{
indx_t idx;
PAGE *h;
EPGNO *parent;
RINTERNAL *r;
pgno_t pg;
indx_t top;
recno_t total;
int sverrno;
BT_CLR(t);
for (pg = P_ROOT, total = 0;;) {
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
goto err;
if (h->flags & P_RLEAF) {
t->bt_cur.page = h;
t->bt_cur.index = recno - total;
return (&t->bt_cur);
}
for (idx = 0, top = NEXTINDEX(h);;) {
r = GETRINTERNAL(h, idx);
if (++idx == top || total + r->nrecs > recno)
break;
total += r->nrecs;
}
BT_PUSH(t, pg, idx - 1);
pg = r->pgno;
switch (op) {
case SDELETE:
--GETRINTERNAL(h, (idx - 1))->nrecs;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
case SINSERT:
++GETRINTERNAL(h, (idx - 1))->nrecs;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
break;
case SEARCH:
mpool_put(t->bt_mp, h, 0);
break;
}
}
/* Try and recover the tree. */
err: sverrno = errno;
if (op != SEARCH)
while ((parent = BT_POP(t)) != NULL) {
if ((h = mpool_get(t->bt_mp, parent->pgno, 0)) == NULL)
break;
if (op == SINSERT)
--GETRINTERNAL(h, parent->index)->nrecs;
else
++GETRINTERNAL(h, parent->index)->nrecs;
mpool_put(t->bt_mp, h, MPOOL_DIRTY);
}
errno = sverrno;
return (NULL);
}
diff --git a/lib/libc/db/recno/rec_utils.c b/lib/libc/db/recno/rec_utils.c
index 48631fd84429..dc00a4047347 100644
--- a/lib/libc/db/recno/rec_utils.c
+++ b/lib/libc/db/recno/rec_utils.c
@@ -1,112 +1,111 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rec_utils.c 8.6 (Berkeley) 7/16/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <db.h>
#include "recno.h"
/*
* __rec_ret --
* Build return data.
*
* Parameters:
* t: tree
* e: key/data pair to be returned
* nrec: record number
* key: user's key structure
* data: user's data structure
*
* Returns:
* RET_SUCCESS, RET_ERROR.
*/
int
__rec_ret(BTREE *t, EPG *e, recno_t nrec, DBT *key, DBT *data)
{
RLEAF *rl;
void *p;
if (key == NULL)
goto dataonly;
/* We have to copy the key, it's not on the page. */
if (sizeof(recno_t) > t->bt_rkey.size) {
p = realloc(t->bt_rkey.data, sizeof(recno_t));
if (p == NULL)
return (RET_ERROR);
t->bt_rkey.data = p;
t->bt_rkey.size = sizeof(recno_t);
}
memmove(t->bt_rkey.data, &nrec, sizeof(recno_t));
key->size = sizeof(recno_t);
key->data = t->bt_rkey.data;
dataonly:
if (data == NULL)
return (RET_SUCCESS);
/*
* We must copy big keys/data to make them contigous. Otherwise,
* leave the page pinned and don't copy unless the user specified
* concurrent access.
*/
rl = GETRLEAF(e->page, e->index);
if (rl->flags & P_BIGDATA) {
if (__ovfl_get(t, rl->bytes,
&data->size, &t->bt_rdata.data, &t->bt_rdata.size))
return (RET_ERROR);
data->data = t->bt_rdata.data;
} else if (F_ISSET(t, B_DB_LOCK)) {
/* Use +1 in case the first record retrieved is 0 length. */
if (rl->dsize + 1 > t->bt_rdata.size) {
p = realloc(t->bt_rdata.data, rl->dsize + 1);
if (p == NULL)
return (RET_ERROR);
t->bt_rdata.data = p;
t->bt_rdata.size = rl->dsize + 1;
}
memmove(t->bt_rdata.data, rl->bytes, rl->dsize);
data->size = rl->dsize;
data->data = t->bt_rdata.data;
} else {
data->size = rl->dsize;
data->data = rl->bytes;
}
return (RET_SUCCESS);
}
diff --git a/lib/libc/db/test/btree.tests/main.c b/lib/libc/db/test/btree.tests/main.c
index 50a769fa9441..c0989ad391cf 100644
--- a/lib/libc/db/test/btree.tests/main.c
+++ b/lib/libc/db/test/btree.tests/main.c
@@ -1,763 +1,762 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Olson.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)main.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <fcntl.h>
#include <db.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "btree.h"
typedef struct cmd_table {
char *cmd;
int nargs;
int rconv;
void (*func)(DB *, char **);
char *usage, *descrip;
} cmd_table;
int stopstop;
DB *globaldb;
void append(DB *, char **);
void bstat(DB *, char **);
void cursor(DB *, char **);
void delcur(DB *, char **);
void delete(DB *, char **);
void dump(DB *, char **);
void first(DB *, char **);
void get(DB *, char **);
void help(DB *, char **);
void iafter(DB *, char **);
void ibefore(DB *, char **);
void icursor(DB *, char **);
void insert(DB *, char **);
void keydata(DBT *, DBT *);
void last(DB *, char **);
void list(DB *, char **);
void load(DB *, char **);
void mstat(DB *, char **);
void next(DB *, char **);
int parse(char *, char **, int);
void previous(DB *, char **);
void show(DB *, char **);
void usage(void);
void user(DB *);
cmd_table commands[] = {
"?", 0, 0, help, "help", NULL,
"a", 2, 1, append, "append key def", "append key with data def",
"b", 0, 0, bstat, "bstat", "stat btree",
"c", 1, 1, cursor, "cursor word", "move cursor to word",
"delc", 0, 0, delcur, "delcur", "delete key the cursor references",
"dele", 1, 1, delete, "delete word", "delete word",
"d", 0, 0, dump, "dump", "dump database",
"f", 0, 0, first, "first", "move cursor to first record",
"g", 1, 1, get, "get key", "locate key",
"h", 0, 0, help, "help", "print command summary",
"ia", 2, 1, iafter, "iafter key data", "insert data after key",
"ib", 2, 1, ibefore, "ibefore key data", "insert data before key",
"ic", 2, 1, icursor, "icursor key data", "replace cursor",
"in", 2, 1, insert, "insert key def", "insert key with data def",
"la", 0, 0, last, "last", "move cursor to last record",
"li", 1, 1, list, "list file", "list to a file",
"loa", 1, 0, load, "load file", NULL,
"loc", 1, 1, get, "get key", NULL,
"m", 0, 0, mstat, "mstat", "stat memory pool",
"n", 0, 0, next, "next", "move cursor forward one record",
"p", 0, 0, previous, "previous", "move cursor back one record",
"q", 0, 0, NULL, "quit", "quit",
"sh", 1, 0, show, "show page", "dump a page",
{ NULL },
};
int recno; /* use record numbers */
char *dict = "words"; /* default dictionary */
char *progname;
int
main(argc, argv)
int argc;
char **argv;
{
int c;
DB *db;
BTREEINFO b;
progname = *argv;
b.flags = 0;
b.cachesize = 0;
b.maxkeypage = 0;
b.minkeypage = 0;
b.psize = 0;
b.compare = NULL;
b.prefix = NULL;
b.lorder = 0;
while ((c = getopt(argc, argv, "bc:di:lp:ru")) != -1) {
switch (c) {
case 'b':
b.lorder = BIG_ENDIAN;
break;
case 'c':
b.cachesize = atoi(optarg);
break;
case 'd':
b.flags |= R_DUP;
break;
case 'i':
dict = optarg;
break;
case 'l':
b.lorder = LITTLE_ENDIAN;
break;
case 'p':
b.psize = atoi(optarg);
break;
case 'r':
recno = 1;
break;
case 'u':
b.flags = 0;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (recno)
db = dbopen(*argv == NULL ? NULL : *argv, O_RDWR,
0, DB_RECNO, NULL);
else
db = dbopen(*argv == NULL ? NULL : *argv, O_CREAT|O_RDWR,
0600, DB_BTREE, &b);
if (db == NULL) {
(void)fprintf(stderr, "dbopen: %s\n", strerror(errno));
exit(1);
}
globaldb = db;
user(db);
exit(0);
/* NOTREACHED */
}
void
user(db)
DB *db;
{
FILE *ifp;
int argc, i, last;
char *lbuf, *argv[4], buf[512];
if ((ifp = fopen("/dev/tty", "r")) == NULL) {
(void)fprintf(stderr,
"/dev/tty: %s\n", strerror(errno));
exit(1);
}
for (last = 0;;) {
(void)printf("> ");
(void)fflush(stdout);
if ((lbuf = fgets(&buf[0], 512, ifp)) == NULL)
break;
if (lbuf[0] == '\n') {
i = last;
goto uselast;
}
lbuf[strlen(lbuf) - 1] = '\0';
if (lbuf[0] == 'q')
break;
argc = parse(lbuf, &argv[0], 3);
if (argc == 0)
continue;
for (i = 0; commands[i].cmd != NULL; i++)
if (strncmp(commands[i].cmd, argv[0],
strlen(commands[i].cmd)) == 0)
break;
if (commands[i].cmd == NULL) {
(void)fprintf(stderr,
"%s: command unknown ('help' for help)\n", lbuf);
continue;
}
if (commands[i].nargs != argc - 1) {
(void)fprintf(stderr, "usage: %s\n", commands[i].usage);
continue;
}
if (recno && commands[i].rconv) {
static recno_t nlong;
nlong = atoi(argv[1]);
argv[1] = (char *)&nlong;
}
uselast: last = i;
(*commands[i].func)(db, argv);
}
if ((db->sync)(db) == RET_ERROR)
perror("dbsync");
else if ((db->close)(db) == RET_ERROR)
perror("dbclose");
}
int
parse(lbuf, argv, maxargc)
char *lbuf, **argv;
int maxargc;
{
int argc = 0;
char *c;
c = lbuf;
while (isspace(*c))
c++;
while (*c != '\0' && argc < maxargc) {
*argv++ = c;
argc++;
while (!isspace(*c) && *c != '\0') {
c++;
}
while (isspace(*c))
*c++ = '\0';
}
return (argc);
}
void
append(db, argv)
DB *db;
char **argv;
{
DBT key, data;
int status;
if (!recno) {
(void)fprintf(stderr,
"append only available for recno db's.\n");
return;
}
key.data = argv[1];
key.size = sizeof(recno_t);
data.data = argv[2];
data.size = strlen(data.data);
status = (db->put)(db, &key, &data, R_APPEND);
switch (status) {
case RET_ERROR:
perror("append/put");
break;
case RET_SPECIAL:
(void)printf("%s (duplicate key)\n", argv[1]);
break;
case RET_SUCCESS:
break;
}
}
void
cursor(db, argv)
DB *db;
char **argv;
{
DBT data, key;
int status;
key.data = argv[1];
if (recno)
key.size = sizeof(recno_t);
else
key.size = strlen(argv[1]) + 1;
status = (*db->seq)(db, &key, &data, R_CURSOR);
switch (status) {
case RET_ERROR:
perror("cursor/seq");
break;
case RET_SPECIAL:
(void)printf("key not found\n");
break;
case RET_SUCCESS:
keydata(&key, &data);
break;
}
}
void
delcur(db, argv)
DB *db;
char **argv;
{
int status;
status = (*db->del)(db, NULL, R_CURSOR);
if (status == RET_ERROR)
perror("delcur/del");
}
void
delete(db, argv)
DB *db;
char **argv;
{
DBT key;
int status;
key.data = argv[1];
if (recno)
key.size = sizeof(recno_t);
else
key.size = strlen(argv[1]) + 1;
status = (*db->del)(db, &key, 0);
switch (status) {
case RET_ERROR:
perror("delete/del");
break;
case RET_SPECIAL:
(void)printf("key not found\n");
break;
case RET_SUCCESS:
break;
}
}
void
dump(db, argv)
DB *db;
char **argv;
{
__bt_dump(db);
}
void
first(db, argv)
DB *db;
char **argv;
{
DBT data, key;
int status;
status = (*db->seq)(db, &key, &data, R_FIRST);
switch (status) {
case RET_ERROR:
perror("first/seq");
break;
case RET_SPECIAL:
(void)printf("no more keys\n");
break;
case RET_SUCCESS:
keydata(&key, &data);
break;
}
}
void
get(db, argv)
DB *db;
char **argv;
{
DBT data, key;
int status;
key.data = argv[1];
if (recno)
key.size = sizeof(recno_t);
else
key.size = strlen(argv[1]) + 1;
status = (*db->get)(db, &key, &data, 0);
switch (status) {
case RET_ERROR:
perror("get/get");
break;
case RET_SPECIAL:
(void)printf("key not found\n");
break;
case RET_SUCCESS:
keydata(&key, &data);
break;
}
}
void
help(db, argv)
DB *db;
char **argv;
{
int i;
for (i = 0; commands[i].cmd; i++)
if (commands[i].descrip)
(void)printf("%s: %s\n",
commands[i].usage, commands[i].descrip);
}
void
iafter(db, argv)
DB *db;
char **argv;
{
DBT key, data;
int status;
if (!recno) {
(void)fprintf(stderr,
"iafter only available for recno db's.\n");
return;
}
key.data = argv[1];
key.size = sizeof(recno_t);
data.data = argv[2];
data.size = strlen(data.data);
status = (db->put)(db, &key, &data, R_IAFTER);
switch (status) {
case RET_ERROR:
perror("iafter/put");
break;
case RET_SPECIAL:
(void)printf("%s (duplicate key)\n", argv[1]);
break;
case RET_SUCCESS:
break;
}
}
void
ibefore(db, argv)
DB *db;
char **argv;
{
DBT key, data;
int status;
if (!recno) {
(void)fprintf(stderr,
"ibefore only available for recno db's.\n");
return;
}
key.data = argv[1];
key.size = sizeof(recno_t);
data.data = argv[2];
data.size = strlen(data.data);
status = (db->put)(db, &key, &data, R_IBEFORE);
switch (status) {
case RET_ERROR:
perror("ibefore/put");
break;
case RET_SPECIAL:
(void)printf("%s (duplicate key)\n", argv[1]);
break;
case RET_SUCCESS:
break;
}
}
void
icursor(db, argv)
DB *db;
char **argv;
{
int status;
DBT data, key;
key.data = argv[1];
if (recno)
key.size = sizeof(recno_t);
else
key.size = strlen(argv[1]) + 1;
data.data = argv[2];
data.size = strlen(argv[2]) + 1;
status = (*db->put)(db, &key, &data, R_CURSOR);
switch (status) {
case RET_ERROR:
perror("icursor/put");
break;
case RET_SPECIAL:
(void)printf("%s (duplicate key)\n", argv[1]);
break;
case RET_SUCCESS:
break;
}
}
void
insert(db, argv)
DB *db;
char **argv;
{
int status;
DBT data, key;
key.data = argv[1];
if (recno)
key.size = sizeof(recno_t);
else
key.size = strlen(argv[1]) + 1;
data.data = argv[2];
data.size = strlen(argv[2]) + 1;
status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
switch (status) {
case RET_ERROR:
perror("insert/put");
break;
case RET_SPECIAL:
(void)printf("%s (duplicate key)\n", argv[1]);
break;
case RET_SUCCESS:
break;
}
}
void
last(db, argv)
DB *db;
char **argv;
{
DBT data, key;
int status;
status = (*db->seq)(db, &key, &data, R_LAST);
switch (status) {
case RET_ERROR:
perror("last/seq");
break;
case RET_SPECIAL:
(void)printf("no more keys\n");
break;
case RET_SUCCESS:
keydata(&key, &data);
break;
}
}
void
list(db, argv)
DB *db;
char **argv;
{
DBT data, key;
FILE *fp;
int status;
if ((fp = fopen(argv[1], "w")) == NULL) {
(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
return;
}
status = (*db->seq)(db, &key, &data, R_FIRST);
while (status == RET_SUCCESS) {
(void)fprintf(fp, "%s\n", key.data);
status = (*db->seq)(db, &key, &data, R_NEXT);
}
if (status == RET_ERROR)
perror("list/seq");
}
DB *BUGdb;
void
load(db, argv)
DB *db;
char **argv;
{
char *p, *t;
FILE *fp;
DBT data, key;
recno_t cnt;
size_t len;
int status;
char *lp, buf[16 * 1024];
BUGdb = db;
if ((fp = fopen(argv[1], "r")) == NULL) {
(void)fprintf(stderr, "%s: %s\n", argv[1], strerror(errno));
return;
}
(void)printf("loading %s...\n", argv[1]);
for (cnt = 1; (lp = fgetline(fp, &len)) != NULL; ++cnt) {
if (recno) {
key.data = &cnt;
key.size = sizeof(recno_t);
data.data = lp;
data.size = len + 1;
} else {
key.data = lp;
key.size = len + 1;
for (p = lp + len - 1, t = buf; p >= lp; *t++ = *p--);
*t = '\0';
data.data = buf;
data.size = len + 1;
}
status = (*db->put)(db, &key, &data, R_NOOVERWRITE);
switch (status) {
case RET_ERROR:
perror("load/put");
exit(1);
case RET_SPECIAL:
if (recno)
(void)fprintf(stderr,
"duplicate: %ld {%s}\n", cnt, data.data);
else
(void)fprintf(stderr,
"duplicate: %ld {%s}\n", cnt, key.data);
exit(1);
case RET_SUCCESS:
break;
}
}
(void)fclose(fp);
}
void
next(db, argv)
DB *db;
char **argv;
{
DBT data, key;
int status;
status = (*db->seq)(db, &key, &data, R_NEXT);
switch (status) {
case RET_ERROR:
perror("next/seq");
break;
case RET_SPECIAL:
(void)printf("no more keys\n");
break;
case RET_SUCCESS:
keydata(&key, &data);
break;
}
}
void
previous(db, argv)
DB *db;
char **argv;
{
DBT data, key;
int status;
status = (*db->seq)(db, &key, &data, R_PREV);
switch (status) {
case RET_ERROR:
perror("previous/seq");
break;
case RET_SPECIAL:
(void)printf("no more keys\n");
break;
case RET_SUCCESS:
keydata(&key, &data);
break;
}
}
void
show(db, argv)
DB *db;
char **argv;
{
BTREE *t;
PAGE *h;
pgno_t pg;
pg = atoi(argv[1]);
t = db->internal;
if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL) {
(void)printf("getpage of %ld failed\n", pg);
return;
}
if (pg == 0)
__bt_dmpage(h);
else
__bt_dpage(h);
mpool_put(t->bt_mp, h, 0);
}
void
bstat(db, argv)
DB *db;
char **argv;
{
(void)printf("BTREE\n");
__bt_stat(db);
}
void
mstat(db, argv)
DB *db;
char **argv;
{
(void)printf("MPOOL\n");
mpool_stat(((BTREE *)db->internal)->bt_mp);
}
void
keydata(key, data)
DBT *key, *data;
{
if (!recno && key->size > 0)
(void)printf("%s/", key->data);
if (data->size > 0)
(void)printf("%s", data->data);
(void)printf("\n");
}
void
usage()
{
(void)fprintf(stderr,
"usage: %s [-bdlu] [-c cache] [-i file] [-p page] [file]\n",
progname);
exit (1);
}
diff --git a/lib/libc/db/test/dbtest.c b/lib/libc/db/test/dbtest.c
index 8b47827db996..e6cd0cdcd2d0 100644
--- a/lib/libc/db/test/dbtest.c
+++ b/lib/libc/db/test/dbtest.c
@@ -1,738 +1,737 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1992, 1993, 1994\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)dbtest.c 8.17 (Berkeley) 9/1/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <db.h>
enum S { COMMAND, COMPARE, GET, PUT, REMOVE, SEQ, SEQFLAG, KEY, DATA };
void compare(DBT *, DBT *);
DBTYPE dbtype(char *);
void dump(DB *, int);
void err(const char *, ...) __printflike(1, 2);
void get(DB *, DBT *);
void getdata(DB *, DBT *, DBT *);
void put(DB *, DBT *, DBT *);
void rem(DB *, DBT *);
char *sflags(int);
void synk(DB *);
void *rfile(char *, size_t *);
void seq(DB *, DBT *);
u_int setflags(char *);
void *setinfo(DBTYPE, char *);
void usage(void);
void *xmalloc(char *, size_t);
DBTYPE type; /* Database type. */
void *infop; /* Iflags. */
u_long lineno; /* Current line in test script. */
u_int flags; /* Current DB flags. */
int ofd = STDOUT_FILENO; /* Standard output fd. */
DB *XXdbp; /* Global for gdb. */
int XXlineno; /* Fast breakpoint for gdb. */
int
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
extern char *optarg;
enum S command, state;
DB *dbp;
DBT data, key, keydata;
size_t len;
int ch, oflags, sflag;
char *fname, *infoarg, *p, *t, buf[8 * 1024];
infoarg = NULL;
fname = NULL;
oflags = O_CREAT | O_RDWR;
sflag = 0;
while ((ch = getopt(argc, argv, "f:i:lo:s")) != -1)
switch (ch) {
case 'f':
fname = optarg;
break;
case 'i':
infoarg = optarg;
break;
case 'l':
oflags |= DB_LOCK;
break;
case 'o':
if ((ofd = open(optarg,
O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
err("%s: %s", optarg, strerror(errno));
break;
case 's':
sflag = 1;
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc != 2)
usage();
/* Set the type. */
type = dbtype(*argv++);
/* Open the descriptor file. */
if (strcmp(*argv, "-") && freopen(*argv, "r", stdin) == NULL)
err("%s: %s", *argv, strerror(errno));
/* Set up the db structure as necessary. */
if (infoarg == NULL)
infop = NULL;
else
for (p = strtok(infoarg, ",\t "); p != NULL;
p = strtok(0, ",\t "))
if (*p != '\0')
infop = setinfo(type, p);
/*
* Open the DB. Delete any preexisting copy, you almost never
* want it around, and it often screws up tests.
*/
if (fname == NULL) {
p = getenv("TMPDIR");
if (p == NULL)
p = "/var/tmp";
(void)snprintf(buf, sizeof(buf), "%s/__dbtest", p);
fname = buf;
(void)unlink(buf);
} else if (!sflag)
(void)unlink(fname);
if ((dbp = dbopen(fname,
oflags, S_IRUSR | S_IWUSR, type, infop)) == NULL)
err("dbopen: %s", strerror(errno));
XXdbp = dbp;
state = COMMAND;
for (lineno = 1;
(p = fgets(buf, sizeof(buf), stdin)) != NULL; ++lineno) {
/* Delete the newline, displaying the key/data is easier. */
if (ofd == STDOUT_FILENO && (t = strchr(p, '\n')) != NULL)
*t = '\0';
if ((len = strlen(buf)) == 0 || isspace(*p) || *p == '#')
continue;
/* Convenient gdb break point. */
if (XXlineno == lineno)
XXlineno = 1;
switch (*p) {
case 'c': /* compare */
if (state != COMMAND)
err("line %lu: not expecting command", lineno);
state = KEY;
command = COMPARE;
break;
case 'e': /* echo */
if (state != COMMAND)
err("line %lu: not expecting command", lineno);
/* Don't display the newline, if CR at EOL. */
if (p[len - 2] == '\r')
--len;
if (write(ofd, p + 1, len - 1) != len - 1 ||
write(ofd, "\n", 1) != 1)
err("write: %s", strerror(errno));
break;
case 'g': /* get */
if (state != COMMAND)
err("line %lu: not expecting command", lineno);
state = KEY;
command = GET;
break;
case 'p': /* put */
if (state != COMMAND)
err("line %lu: not expecting command", lineno);
state = KEY;
command = PUT;
break;
case 'r': /* remove */
if (state != COMMAND)
err("line %lu: not expecting command", lineno);
if (flags == R_CURSOR) {
rem(dbp, &key);
state = COMMAND;
} else {
state = KEY;
command = REMOVE;
}
break;
case 'S': /* sync */
if (state != COMMAND)
err("line %lu: not expecting command", lineno);
synk(dbp);
state = COMMAND;
break;
case 's': /* seq */
if (state != COMMAND)
err("line %lu: not expecting command", lineno);
if (flags == R_CURSOR) {
state = KEY;
command = SEQ;
} else
seq(dbp, &key);
break;
case 'f':
flags = setflags(p + 1);
break;
case 'D': /* data file */
if (state != DATA)
err("line %lu: not expecting data", lineno);
data.data = rfile(p + 1, &data.size);
goto ldata;
case 'd': /* data */
if (state != DATA)
err("line %lu: not expecting data", lineno);
data.data = xmalloc(p + 1, len - 1);
data.size = len - 1;
ldata: switch (command) {
case COMPARE:
compare(&keydata, &data);
break;
case PUT:
put(dbp, &key, &data);
break;
default:
err("line %lu: command doesn't take data",
lineno);
}
if (type != DB_RECNO)
free(key.data);
free(data.data);
state = COMMAND;
break;
case 'K': /* key file */
if (state != KEY)
err("line %lu: not expecting a key", lineno);
if (type == DB_RECNO)
err("line %lu: 'K' not available for recno",
lineno);
key.data = rfile(p + 1, &key.size);
goto lkey;
case 'k': /* key */
if (state != KEY)
err("line %lu: not expecting a key", lineno);
if (type == DB_RECNO) {
static recno_t recno;
recno = atoi(p + 1);
key.data = &recno;
key.size = sizeof(recno);
} else {
key.data = xmalloc(p + 1, len - 1);
key.size = len - 1;
}
lkey: switch (command) {
case COMPARE:
getdata(dbp, &key, &keydata);
state = DATA;
break;
case GET:
get(dbp, &key);
if (type != DB_RECNO)
free(key.data);
state = COMMAND;
break;
case PUT:
state = DATA;
break;
case REMOVE:
rem(dbp, &key);
if ((type != DB_RECNO) && (flags != R_CURSOR))
free(key.data);
state = COMMAND;
break;
case SEQ:
seq(dbp, &key);
if ((type != DB_RECNO) && (flags != R_CURSOR))
free(key.data);
state = COMMAND;
break;
default:
err("line %lu: command doesn't take a key",
lineno);
}
break;
case 'o':
dump(dbp, p[1] == 'r');
break;
default:
err("line %lu: %s: unknown command character",
lineno, p);
}
}
#ifdef STATISTICS
/*
* -l must be used (DB_LOCK must be set) for this to be
* used, otherwise a page will be locked and it will fail.
*/
if (type == DB_BTREE && oflags & DB_LOCK)
__bt_stat(dbp);
#endif
if (dbp->close(dbp))
err("db->close: %s", strerror(errno));
(void)close(ofd);
exit(0);
}
#define NOOVERWRITE "put failed, would overwrite key\n"
void
compare(db1, db2)
DBT *db1, *db2;
{
size_t len;
u_char *p1, *p2;
if (db1->size != db2->size)
printf("compare failed: key->data len %lu != data len %lu\n",
db1->size, db2->size);
len = MIN(db1->size, db2->size);
for (p1 = db1->data, p2 = db2->data; len--;)
if (*p1++ != *p2++) {
printf("compare failed at offset %d\n",
p1 - (u_char *)db1->data);
break;
}
}
void
get(dbp, kp)
DB *dbp;
DBT *kp;
{
DBT data;
switch (dbp->get(dbp, kp, &data, flags)) {
case 0:
(void)write(ofd, data.data, data.size);
if (ofd == STDOUT_FILENO)
(void)write(ofd, "\n", 1);
break;
case -1:
err("line %lu: get: %s", lineno, strerror(errno));
/* NOTREACHED */
case 1:
#define NOSUCHKEY "get failed, no such key\n"
if (ofd != STDOUT_FILENO)
(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
else
(void)fprintf(stderr, "%d: %.*s: %s",
lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
#undef NOSUCHKEY
break;
}
}
void
getdata(dbp, kp, dp)
DB *dbp;
DBT *kp, *dp;
{
switch (dbp->get(dbp, kp, dp, flags)) {
case 0:
return;
case -1:
err("line %lu: getdata: %s", lineno, strerror(errno));
/* NOTREACHED */
case 1:
err("line %lu: getdata failed, no such key", lineno);
/* NOTREACHED */
}
}
void
put(dbp, kp, dp)
DB *dbp;
DBT *kp, *dp;
{
switch (dbp->put(dbp, kp, dp, flags)) {
case 0:
break;
case -1:
err("line %lu: put: %s", lineno, strerror(errno));
/* NOTREACHED */
case 1:
(void)write(ofd, NOOVERWRITE, sizeof(NOOVERWRITE) - 1);
break;
}
}
void
rem(dbp, kp)
DB *dbp;
DBT *kp;
{
switch (dbp->del(dbp, kp, flags)) {
case 0:
break;
case -1:
err("line %lu: rem: %s", lineno, strerror(errno));
/* NOTREACHED */
case 1:
#define NOSUCHKEY "rem failed, no such key\n"
if (ofd != STDOUT_FILENO)
(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
else if (flags != R_CURSOR)
(void)fprintf(stderr, "%d: %.*s: %s",
lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
else
(void)fprintf(stderr,
"%d: rem of cursor failed\n", lineno);
#undef NOSUCHKEY
break;
}
}
void
synk(dbp)
DB *dbp;
{
switch (dbp->sync(dbp, flags)) {
case 0:
break;
case -1:
err("line %lu: synk: %s", lineno, strerror(errno));
/* NOTREACHED */
}
}
void
seq(dbp, kp)
DB *dbp;
DBT *kp;
{
DBT data;
switch (dbp->seq(dbp, kp, &data, flags)) {
case 0:
(void)write(ofd, data.data, data.size);
if (ofd == STDOUT_FILENO)
(void)write(ofd, "\n", 1);
break;
case -1:
err("line %lu: seq: %s", lineno, strerror(errno));
/* NOTREACHED */
case 1:
#define NOSUCHKEY "seq failed, no such key\n"
if (ofd != STDOUT_FILENO)
(void)write(ofd, NOSUCHKEY, sizeof(NOSUCHKEY) - 1);
else if (flags == R_CURSOR)
(void)fprintf(stderr, "%d: %.*s: %s",
lineno, MIN(kp->size, 20), kp->data, NOSUCHKEY);
else
(void)fprintf(stderr,
"%d: seq (%s) failed\n", lineno, sflags(flags));
#undef NOSUCHKEY
break;
}
}
void
dump(dbp, rev)
DB *dbp;
int rev;
{
DBT key, data;
int flags, nflags;
if (rev) {
flags = R_LAST;
nflags = R_PREV;
} else {
flags = R_FIRST;
nflags = R_NEXT;
}
for (;; flags = nflags)
switch (dbp->seq(dbp, &key, &data, flags)) {
case 0:
(void)write(ofd, data.data, data.size);
if (ofd == STDOUT_FILENO)
(void)write(ofd, "\n", 1);
break;
case 1:
goto done;
case -1:
err("line %lu: (dump) seq: %s",
lineno, strerror(errno));
/* NOTREACHED */
}
done: return;
}
u_int
setflags(s)
char *s;
{
char *p, *index();
for (; isspace(*s); ++s);
if (*s == '\n' || *s == '\0')
return (0);
if ((p = index(s, '\n')) != NULL)
*p = '\0';
if (!strcmp(s, "R_CURSOR")) return (R_CURSOR);
if (!strcmp(s, "R_FIRST")) return (R_FIRST);
if (!strcmp(s, "R_IAFTER")) return (R_IAFTER);
if (!strcmp(s, "R_IBEFORE")) return (R_IBEFORE);
if (!strcmp(s, "R_LAST")) return (R_LAST);
if (!strcmp(s, "R_NEXT")) return (R_NEXT);
if (!strcmp(s, "R_NOOVERWRITE")) return (R_NOOVERWRITE);
if (!strcmp(s, "R_PREV")) return (R_PREV);
if (!strcmp(s, "R_SETCURSOR")) return (R_SETCURSOR);
err("line %lu: %s: unknown flag", lineno, s);
/* NOTREACHED */
}
char *
sflags(flags)
int flags;
{
switch (flags) {
case R_CURSOR: return ("R_CURSOR");
case R_FIRST: return ("R_FIRST");
case R_IAFTER: return ("R_IAFTER");
case R_IBEFORE: return ("R_IBEFORE");
case R_LAST: return ("R_LAST");
case R_NEXT: return ("R_NEXT");
case R_NOOVERWRITE: return ("R_NOOVERWRITE");
case R_PREV: return ("R_PREV");
case R_SETCURSOR: return ("R_SETCURSOR");
}
return ("UNKNOWN!");
}
DBTYPE
dbtype(s)
char *s;
{
if (!strcmp(s, "btree"))
return (DB_BTREE);
if (!strcmp(s, "hash"))
return (DB_HASH);
if (!strcmp(s, "recno"))
return (DB_RECNO);
err("%s: unknown type (use btree, hash or recno)", s);
/* NOTREACHED */
}
void *
setinfo(type, s)
DBTYPE type;
char *s;
{
static BTREEINFO ib;
static HASHINFO ih;
static RECNOINFO rh;
char *eq, *index();
if ((eq = index(s, '=')) == NULL)
err("%s: illegal structure set statement", s);
*eq++ = '\0';
if (!isdigit(*eq))
err("%s: structure set statement must be a number", s);
switch (type) {
case DB_BTREE:
if (!strcmp("flags", s)) {
ib.flags = atoi(eq);
return (&ib);
}
if (!strcmp("cachesize", s)) {
ib.cachesize = atoi(eq);
return (&ib);
}
if (!strcmp("maxkeypage", s)) {
ib.maxkeypage = atoi(eq);
return (&ib);
}
if (!strcmp("minkeypage", s)) {
ib.minkeypage = atoi(eq);
return (&ib);
}
if (!strcmp("lorder", s)) {
ib.lorder = atoi(eq);
return (&ib);
}
if (!strcmp("psize", s)) {
ib.psize = atoi(eq);
return (&ib);
}
break;
case DB_HASH:
if (!strcmp("bsize", s)) {
ih.bsize = atoi(eq);
return (&ih);
}
if (!strcmp("ffactor", s)) {
ih.ffactor = atoi(eq);
return (&ih);
}
if (!strcmp("nelem", s)) {
ih.nelem = atoi(eq);
return (&ih);
}
if (!strcmp("cachesize", s)) {
ih.cachesize = atoi(eq);
return (&ih);
}
if (!strcmp("lorder", s)) {
ih.lorder = atoi(eq);
return (&ih);
}
break;
case DB_RECNO:
if (!strcmp("flags", s)) {
rh.flags = atoi(eq);
return (&rh);
}
if (!strcmp("cachesize", s)) {
rh.cachesize = atoi(eq);
return (&rh);
}
if (!strcmp("lorder", s)) {
rh.lorder = atoi(eq);
return (&rh);
}
if (!strcmp("reclen", s)) {
rh.reclen = atoi(eq);
return (&rh);
}
if (!strcmp("bval", s)) {
rh.bval = atoi(eq);
return (&rh);
}
if (!strcmp("psize", s)) {
rh.psize = atoi(eq);
return (&rh);
}
break;
}
err("%s: unknown structure value", s);
/* NOTREACHED */
}
void *
rfile(name, lenp)
char *name;
size_t *lenp;
{
struct stat sb;
void *p;
int fd;
char *np, *index();
for (; isspace(*name); ++name);
if ((np = index(name, '\n')) != NULL)
*np = '\0';
if ((fd = open(name, O_RDONLY, 0)) < 0 ||
fstat(fd, &sb))
err("%s: %s\n", name, strerror(errno));
#ifdef NOT_PORTABLE
if (sb.st_size > (off_t)SIZE_T_MAX)
err("%s: %s\n", name, strerror(E2BIG));
#endif
if ((p = (void *)malloc((u_int)sb.st_size)) == NULL)
err("%s", strerror(errno));
(void)read(fd, p, (int)sb.st_size);
*lenp = sb.st_size;
(void)close(fd);
return (p);
}
void *
xmalloc(text, len)
char *text;
size_t len;
{
void *p;
if ((p = (void *)malloc(len)) == NULL)
err("%s", strerror(errno));
memmove(p, text, len);
return (p);
}
void
usage()
{
(void)fprintf(stderr,
"usage: dbtest [-l] [-f file] [-i info] [-o file] type script\n");
exit(1);
}
#include <stdarg.h>
void
err(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
(void)fprintf(stderr, "dbtest: ");
(void)vfprintf(stderr, fmt, ap);
va_end(ap);
(void)fprintf(stderr, "\n");
exit(1);
/* NOTREACHED */
}
diff --git a/lib/libc/db/test/hash.tests/driver2.c b/lib/libc/db/test/hash.tests/driver2.c
index 05f2d57a7533..06e801661a8e 100644
--- a/lib/libc/db/test/hash.tests/driver2.c
+++ b/lib/libc/db/test/hash.tests/driver2.c
@@ -1,112 +1,111 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)driver2.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* Test driver, to try to tackle the large ugly-split problem.
*/
#include <sys/file.h>
#include <stdio.h>
#include "ndbm.h"
int my_hash(key, len)
char *key;
int len;
{
return(17); /* So I'm cruel... */
}
main(argc, argv)
int argc;
{
DB *db;
DBT key, content;
char keybuf[2049];
char contentbuf[2049];
char buf[256];
int i;
HASHINFO info;
info.bsize = 1024;
info.ffactor = 5;
info.nelem = 1;
info.cachesize = NULL;
#ifdef HASH_ID_PROGRAM_SPECIFIED
info.hash_id = HASH_ID_PROGRAM_SPECIFIED;
info.hash_func = my_hash;
#else
info.hash = my_hash;
#endif
info.lorder = 0;
if (!(db = dbopen("bigtest", O_RDWR | O_CREAT, 0644, DB_HASH, &info))) {
sprintf(buf, "dbopen: failed on file bigtest");
perror(buf);
exit(1);
}
srandom(17);
key.data = keybuf;
content.data = contentbuf;
bzero(keybuf, sizeof(keybuf));
bzero(contentbuf, sizeof(contentbuf));
for (i=1; i <= 500; i++) {
key.size = 128 + (random()&1023);
content.size = 128 + (random()&1023);
/* printf("%d: Key size %d, data size %d\n", i, key.size,
content.size); */
sprintf(keybuf, "Key #%d", i);
sprintf(contentbuf, "Contents #%d", i);
if ((db->put)(db, &key, &content, R_NOOVERWRITE)) {
sprintf(buf, "dbm_store #%d", i);
perror(buf);
}
}
if ((db->close)(db)) {
perror("closing hash file");
exit(1);
}
exit(0);
}
diff --git a/lib/libc/db/test/hash.tests/tcreat3.c b/lib/libc/db/test/hash.tests/tcreat3.c
index 68be11143c55..b1928f572110 100644
--- a/lib/libc/db/test/hash.tests/tcreat3.c
+++ b/lib/libc/db/test/hash.tests/tcreat3.c
@@ -1,103 +1,102 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tcreat3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT item, key;
DB *dbp;
HASHINFO ctl;
FILE *fp;
int trash;
int i = 0;
argv++;
ctl.hash = NULL;
ctl.bsize = atoi(*argv++);
ctl.ffactor = atoi(*argv++);
ctl.nelem = atoi(*argv++);
ctl.lorder = 0;
if (!(dbp = dbopen( "hashtest",
O_CREAT|O_TRUNC|O_RDWR, 0600, DB_HASH, &ctl))){
/* create table */
fprintf(stderr, "cannot create: hash table (size %d)\n",
INITIAL);
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
/*
* enter key/data pair into the table
*/
if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
fprintf(stderr, "cannot enter: key %s\n",
item.data);
exit(1);
}
}
(dbp->close)(dbp);
exit(0);
}
diff --git a/lib/libc/db/test/hash.tests/tdel.c b/lib/libc/db/test/hash.tests/tdel.c
index 9760e271808c..1d3ebdac390d 100644
--- a/lib/libc/db/test/hash.tests/tdel.c
+++ b/lib/libc/db/test/hash.tests/tdel.c
@@ -1,120 +1,119 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tdel.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <db.h>
#include <stdio.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
/* Usage: thash pagesize fillfactor file */
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT item, key;
DB *dbp;
HASHINFO ctl;
FILE *fp;
int stat;
int i = 0;
argv++;
ctl.nelem = INITIAL;
ctl.hash = NULL;
ctl.bsize = atoi(*argv++);
ctl.ffactor = atoi(*argv++);
ctl.cachesize = 1024 * 1024; /* 1 MEG */
ctl.lorder = 0;
argc -= 2;
if (!(dbp = dbopen( NULL, O_CREAT|O_RDWR, 0400, DB_HASH, &ctl))) {
/* create table */
fprintf(stderr, "cannot create: hash table size %d)\n",
INITIAL);
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
/*
* enter key/data pair into the table
*/
if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
fprintf(stderr, "cannot enter: key %s\n",
item.data);
exit(1);
}
}
if ( --argc ) {
fp = fopen ( argv[0], "r");
i = 0;
while ( fgets(wp1, 8192, fp) &&
fgets(wp2, 8192, fp) &&
i++ < MAXWORDS) {
key.size = strlen(wp1);
stat = (dbp->del)(dbp, &key, 0);
if (stat) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
exit(1);
}
}
fclose(fp);
}
(dbp->close)(dbp);
exit(0);
}
diff --git a/lib/libc/db/test/hash.tests/thash4.c b/lib/libc/db/test/hash.tests/thash4.c
index 641534a92730..2b59569487cf 100644
--- a/lib/libc/db/test/hash.tests/thash4.c
+++ b/lib/libc/db/test/hash.tests/thash4.c
@@ -1,130 +1,129 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)thash4.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/timeb.h>
#include <stdio.h>
#include <errno.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
/* Usage: thash pagesize fillfactor file */
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT item, key, res;
DB *dbp;
HASHINFO ctl;
FILE *fp;
int stat;
time_t t;
int i = 0;
argv++;
ctl.hash = NULL;
ctl.bsize = atoi(*argv++);
ctl.ffactor = atoi(*argv++);
ctl.nelem = atoi(*argv++);
ctl.cachesize = atoi(*argv++);
ctl.lorder = 0;
if (!(dbp = dbopen( NULL, O_CREAT|O_RDWR, 0400, DB_HASH, &ctl))) {
/* create table */
fprintf(stderr, "cannot create: hash table size %d)\n",
INITIAL);
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
/*
* enter key/data pair into the table
*/
if ((dbp->put)(dbp, &key, &item, R_NOOVERWRITE) != NULL) {
fprintf(stderr, "cannot enter: key %s\n",
item.data);
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
}
}
if ( --argc ) {
fp = fopen ( argv[0], "r");
i = 0;
while ( fgets(wp1, 256, fp) &&
fgets(wp2, 8192, fp) &&
i++ < MAXWORDS) {
key.size = strlen(wp1);
stat = (dbp->get)(dbp, &key, &res, 0);
if (stat < 0 ) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
} else if ( stat > 0 ) {
fprintf ( stderr, "%s not found\n", key.data );
fprintf(stderr, "\terrno: %d\n", errno);
exit(1);
}
}
fclose(fp);
}
dbp->close(dbp);
exit(0);
}
diff --git a/lib/libc/db/test/hash.tests/tread2.c b/lib/libc/db/test/hash.tests/tread2.c
index 4962d163a24c..691f972defb8 100644
--- a/lib/libc/db/test/hash.tests/tread2.c
+++ b/lib/libc/db/test/hash.tests/tread2.c
@@ -1,103 +1,102 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tread2.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
typedef struct { /* info to be stored */
int num, siz;
} info;
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT item, key, res;
DB *dbp;
HASHINFO ctl;
int stat;
int i = 0;
ctl.nelem = INITIAL;
ctl.hash = NULL;
ctl.bsize = 64;
ctl.ffactor = 1;
ctl.cachesize = atoi(*argv++);
ctl.lorder = 0;
if (!(dbp = dbopen( "hashtest", O_RDONLY, 0400, DB_HASH, &ctl))) {
/* create table */
fprintf(stderr, "cannot open: hash table\n" );
exit(1);
}
key.data = wp1;
item.data = wp2;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
item.size = strlen(wp2);
stat = (dbp->get)(dbp, &key, &res,0);
if (stat < 0) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
exit(1);
} else if ( stat > 0 ) {
fprintf ( stderr, "%s not found\n", key.data );
exit(1);
}
}
(dbp->close)(dbp);
exit(0);
}
diff --git a/lib/libc/db/test/hash.tests/tseq.c b/lib/libc/db/test/hash.tests/tseq.c
index c9569cbbe6d4..46cc2634a028 100644
--- a/lib/libc/db/test/hash.tests/tseq.c
+++ b/lib/libc/db/test/hash.tests/tseq.c
@@ -1,86 +1,85 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tseq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
char wp[8192];
char cp[8192];
main(argc, argv)
char **argv;
{
DBT item, key, res;
DB *dbp;
FILE *fp;
int stat;
if (!(dbp = dbopen( "hashtest", O_RDONLY, 0400, DB_HASH, NULL))) {
/* create table */
fprintf(stderr, "cannot open: hash table\n" );
exit(1);
}
/*
* put info in structure, and structure in the item
*/
for ( stat = (dbp->seq) (dbp, &res, &item, 1 );
stat == 0;
stat = (dbp->seq) (dbp, &res, &item, 0 ) ) {
bcopy ( res.data, wp, res.size );
wp[res.size] = 0;
bcopy ( item.data, cp, item.size );
cp[item.size] = 0;
printf ( "%s %s\n", wp, cp );
}
(dbp->close)(dbp);
exit(0);
}
diff --git a/lib/libc/db/test/hash.tests/tverify.c b/lib/libc/db/test/hash.tests/tverify.c
index 2e8209e42117..74641b5c2cfe 100644
--- a/lib/libc/db/test/hash.tests/tverify.c
+++ b/lib/libc/db/test/hash.tests/tverify.c
@@ -1,105 +1,104 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Margo Seltzer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1991, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tverify.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <db.h>
#define INITIAL 25000
#define MAXWORDS 25000 /* # of elements in search table */
typedef struct { /* info to be stored */
int num, siz;
} info;
char wp1[8192];
char wp2[8192];
main(argc, argv)
char **argv;
{
DBT key, res;
DB *dbp;
HASHINFO ctl;
int trash;
int stat;
int i = 0;
ctl.nelem = INITIAL;
ctl.hash = NULL;
ctl.bsize = 64;
ctl.ffactor = 1;
ctl.cachesize = 1024 * 1024; /* 1 MEG */
ctl.lorder = 0;
if (!(dbp = dbopen( "hashtest", O_RDONLY, 0400, DB_HASH, &ctl))) {
/* create table */
fprintf(stderr, "cannot open: hash table\n" );
exit(1);
}
key.data = wp1;
while ( fgets(wp1, 8192, stdin) &&
fgets(wp2, 8192, stdin) &&
i++ < MAXWORDS) {
/*
* put info in structure, and structure in the item
*/
key.size = strlen(wp1);
stat = (dbp->get)(dbp, &key, &res,0);
if (stat < 0) {
fprintf ( stderr, "Error retrieving %s\n", key.data );
exit(1);
} else if ( stat > 0 ) {
fprintf ( stderr, "%s not found\n", key.data );
exit(1);
}
if ( memcmp ( res.data, wp2, res.size ) ) {
fprintf ( stderr, "data for %s is incorrect. Data was %s. Should have been %s\n", key.data, res.data, wp2 );
}
}
(dbp->close)(dbp);
exit(0);
}
diff --git a/lib/libc/gdtoa/_hdtoa.c b/lib/libc/gdtoa/_hdtoa.c
index c5f2238d7a7b..8ae739acf0db 100644
--- a/lib/libc/gdtoa/_hdtoa.c
+++ b/lib/libc/gdtoa/_hdtoa.c
@@ -1,144 +1,143 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include "../stdio/floatio.h"
#include "fpmath.h"
#include "gdtoaimp.h"
/* Strings values used by dtoa() */
#define INFSTR "Infinity"
#define NANSTR "NaN"
#define DBL_ADJ (DBL_MAX_EXP - 2)
#define SIGFIGS ((DBL_MANT_DIG + 3) / 4 + 1)
static const float one[] = { 1.0f, -1.0f };
/*
* This procedure converts a double-precision number in IEEE format
* into a string of hexadecimal digits and an exponent of 2. Its
* behavior is bug-for-bug compatible with dtoa() in mode 2, with the
* following exceptions:
*
* - An ndigits < 0 causes it to use as many digits as necessary to
* represent the number exactly.
* - The additional xdigs argument should point to either the string
* "0123456789ABCDEF" or the string "0123456789abcdef", depending on
* which case is desired.
* - This routine does not repeat dtoa's mistake of setting decpt
* to 9999 in the case of an infinity or NaN. INT_MAX is used
* for this purpose instead.
*
* Note that the C99 standard does not specify what the leading digit
* should be for non-zero numbers. For instance, 0x1.3p3 is the same
* as 0x2.6p2 is the same as 0x4.cp3. This implementation always makes
* the leading digit a 1. This ensures that the exponent printed is the
* actual base-2 exponent, i.e., ilogb(d).
*
* Inputs: d, xdigs, ndigits
* Outputs: decpt, sign, rve
*/
char *
__hdtoa(double d, const char *xdigs, int ndigits, int *decpt, int *sign,
char **rve)
{
union IEEEd2bits u;
char *s, *s0;
int bufsize;
uint32_t manh, manl;
u.d = d;
*sign = u.bits.sign;
switch (fpclassify(d)) {
case FP_NORMAL:
*decpt = u.bits.exp - DBL_ADJ;
break;
case FP_ZERO:
*decpt = 1;
return (nrv_alloc("0", rve, 1));
case FP_SUBNORMAL:
u.d *= 0x1p514;
*decpt = u.bits.exp - (514 + DBL_ADJ);
break;
case FP_INFINITE:
*decpt = INT_MAX;
return (nrv_alloc(INFSTR, rve, sizeof(INFSTR) - 1));
default: /* FP_NAN or unrecognized */
*decpt = INT_MAX;
return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1));
}
/* FP_NORMAL or FP_SUBNORMAL */
if (ndigits == 0) /* dtoa() compatibility */
ndigits = 1;
/*
* If ndigits < 0, we are expected to auto-size, so we allocate
* enough space for all the digits.
*/
bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
s0 = rv_alloc(bufsize);
/* Round to the desired number of digits. */
if (SIGFIGS > ndigits && ndigits > 0) {
float redux = one[u.bits.sign];
int offset = 4 * ndigits + DBL_MAX_EXP - 4 - DBL_MANT_DIG;
u.bits.exp = offset;
u.d += redux;
u.d -= redux;
*decpt += u.bits.exp - offset;
}
manh = u.bits.manh;
manl = u.bits.manl;
*s0 = '1';
for (s = s0 + 1; s < s0 + bufsize; s++) {
*s = xdigs[(manh >> (DBL_MANH_SIZE - 4)) & 0xf];
manh = (manh << 4) | (manl >> (DBL_MANL_SIZE - 4));
manl <<= 4;
}
/* If ndigits < 0, we are expected to auto-size the precision. */
if (ndigits < 0) {
for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--)
;
}
s = s0 + ndigits;
*s = '\0';
if (rve != NULL)
*rve = s;
return (s0);
}
diff --git a/lib/libc/gdtoa/_hldtoa.c b/lib/libc/gdtoa/_hldtoa.c
index 698038fd8de4..965d2349d103 100644
--- a/lib/libc/gdtoa/_hldtoa.c
+++ b/lib/libc/gdtoa/_hldtoa.c
@@ -1,177 +1,176 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004-2008 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <stdint.h>
#ifdef __i386__
#include <ieeefp.h>
#endif
#include "../stdio/floatio.h"
#include "fpmath.h"
#include "gdtoaimp.h"
#if (LDBL_MANT_DIG > DBL_MANT_DIG)
/* Strings values used by dtoa() */
#define INFSTR "Infinity"
#define NANSTR "NaN"
#ifdef LDBL_IMPLICIT_NBIT
#define MANH_SIZE LDBL_MANH_SIZE
#else
#define MANH_SIZE (LDBL_MANH_SIZE - 1)
#endif
#if MANH_SIZE > 32
typedef uint64_t manh_t;
#else
typedef uint32_t manh_t;
#endif
#if LDBL_MANL_SIZE > 32
typedef uint64_t manl_t;
#else
typedef uint32_t manl_t;
#endif
#define LDBL_ADJ (LDBL_MAX_EXP - 2)
#define SIGFIGS ((LDBL_MANT_DIG + 3) / 4 + 1)
static const float one[] = { 1.0f, -1.0f };
/*
* This is the long double version of __hdtoa().
*/
char *
__hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign,
char **rve)
{
union IEEEl2bits u;
char *s, *s0;
manh_t manh;
manl_t manl;
int bufsize;
#ifdef __i386__
fp_prec_t oldprec;
#endif
u.e = e;
*sign = u.bits.sign;
switch (fpclassify(e)) {
case FP_NORMAL:
*decpt = u.bits.exp - LDBL_ADJ;
break;
case FP_ZERO:
*decpt = 1;
return (nrv_alloc("0", rve, 1));
case FP_SUBNORMAL:
#ifdef __i386__
oldprec = fpsetprec(FP_PE);
#endif
u.e *= 0x1p514L;
*decpt = u.bits.exp - (514 + LDBL_ADJ);
#ifdef __i386__
fpsetprec(oldprec);
#endif
break;
case FP_INFINITE:
*decpt = INT_MAX;
return (nrv_alloc(INFSTR, rve, sizeof(INFSTR) - 1));
default: /* FP_NAN or unrecognized */
*decpt = INT_MAX;
return (nrv_alloc(NANSTR, rve, sizeof(NANSTR) - 1));
}
/* FP_NORMAL or FP_SUBNORMAL */
if (ndigits == 0) /* dtoa() compatibility */
ndigits = 1;
/*
* If ndigits < 0, we are expected to auto-size, so we allocate
* enough space for all the digits.
*/
bufsize = (ndigits > 0) ? ndigits : SIGFIGS;
s0 = rv_alloc(bufsize);
/* Round to the desired number of digits. */
if (SIGFIGS > ndigits && ndigits > 0) {
float redux = one[u.bits.sign];
int offset = 4 * ndigits + LDBL_MAX_EXP - 4 - LDBL_MANT_DIG;
#ifdef __i386__
oldprec = fpsetprec(FP_PE);
#endif
u.bits.exp = offset;
u.e += redux;
u.e -= redux;
*decpt += u.bits.exp - offset;
#ifdef __i386__
fpsetprec(oldprec);
#endif
}
mask_nbit_l(u);
manh = u.bits.manh;
manl = u.bits.manl;
*s0 = '1';
for (s = s0 + 1; s < s0 + bufsize; s++) {
*s = xdigs[(manh >> (MANH_SIZE - 4)) & 0xf];
manh = (manh << 4) | (manl >> (LDBL_MANL_SIZE - 4));
manl <<= 4;
}
/* If ndigits < 0, we are expected to auto-size the precision. */
if (ndigits < 0) {
for (ndigits = SIGFIGS; s0[ndigits - 1] == '0'; ndigits--)
;
}
s = s0 + ndigits;
*s = '\0';
if (rve != NULL)
*rve = s;
return (s0);
}
#else /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
char *
__hldtoa(long double e, const char *xdigs, int ndigits, int *decpt, int *sign,
char **rve)
{
return (__hdtoa((double)e, xdigs, ndigits, decpt, sign, rve));
}
#endif /* (LDBL_MANT_DIG == DBL_MANT_DIG) */
diff --git a/lib/libc/gdtoa/_ldtoa.c b/lib/libc/gdtoa/_ldtoa.c
index 3787b7dd653d..81da06013855 100644
--- a/lib/libc/gdtoa/_ldtoa.c
+++ b/lib/libc/gdtoa/_ldtoa.c
@@ -1,108 +1,107 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <float.h>
#include <inttypes.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include "../stdio/floatio.h"
#include "fpmath.h"
#include "gdtoaimp.h"
/*
* ldtoa() is a wrapper for gdtoa() that makes it smell like dtoa(),
* except that the floating point argument is passed by reference.
* When dtoa() is passed a NaN or infinity, it sets expt to 9999.
* However, a long double could have a valid exponent of 9999, so we
* use INT_MAX in ldtoa() instead.
*/
char *
__ldtoa(long double *ld, int mode, int ndigits, int *decpt, int *sign,
char **rve)
{
FPI fpi = {
LDBL_MANT_DIG, /* nbits */
LDBL_MIN_EXP - LDBL_MANT_DIG, /* emin */
LDBL_MAX_EXP - LDBL_MANT_DIG, /* emax */
FLT_ROUNDS, /* rounding */
#ifdef Sudden_Underflow /* unused, but correct anyway */
1
#else
0
#endif
};
int be, kind;
char *ret;
union IEEEl2bits u;
uint32_t bits[(LDBL_MANT_DIG + 31) / 32];
void *vbits = bits;
u.e = *ld;
/*
* gdtoa doesn't know anything about the sign of the number, so
* if the number is negative, we need to swap rounding modes of
* 2 (upwards) and 3 (downwards).
*/
*sign = u.bits.sign;
fpi.rounding ^= (fpi.rounding >> 1) & u.bits.sign;
be = u.bits.exp - (LDBL_MAX_EXP - 1) - (LDBL_MANT_DIG - 1);
LDBL_TO_ARRAY32(u, bits);
switch (fpclassify(u.e)) {
case FP_NORMAL:
kind = STRTOG_Normal;
#ifdef LDBL_IMPLICIT_NBIT
bits[LDBL_MANT_DIG / 32] |= 1 << ((LDBL_MANT_DIG - 1) % 32);
#endif /* LDBL_IMPLICIT_NBIT */
break;
case FP_ZERO:
kind = STRTOG_Zero;
break;
case FP_SUBNORMAL:
kind = STRTOG_Denormal;
be++;
break;
case FP_INFINITE:
kind = STRTOG_Infinite;
break;
case FP_NAN:
kind = STRTOG_NaN;
break;
default:
abort();
}
ret = gdtoa(&fpi, be, vbits, &kind, mode, ndigits, decpt, rve);
if (*decpt == -32768)
*decpt = INT_MAX;
return ret;
}
diff --git a/lib/libc/gdtoa/machdep_ldisQ.c b/lib/libc/gdtoa/machdep_ldisQ.c
index d39d57e9d292..abd9f4288884 100644
--- a/lib/libc/gdtoa/machdep_ldisQ.c
+++ b/lib/libc/gdtoa/machdep_ldisQ.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Machine-dependent glue to integrate David Gay's gdtoa
* package into libc for architectures where a long double
* uses quad precision, such as aarch64 or riscv.
*/
-#include <sys/cdefs.h>
#include <float.h>
#include "gdtoaimp.h"
long double
strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
{
long double result;
strtorQ_l(s, sp, FLT_ROUNDS, &result, locale);
return result;
}
diff --git a/lib/libc/gdtoa/machdep_ldisd.c b/lib/libc/gdtoa/machdep_ldisd.c
index 79370e05c604..061c67f0bb5a 100644
--- a/lib/libc/gdtoa/machdep_ldisd.c
+++ b/lib/libc/gdtoa/machdep_ldisd.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Machine-dependent glue to integrate David Gay's gdtoa
* package into libc for architectures where a long double
* is the same as a double, such as the Alpha.
*/
-#include <sys/cdefs.h>
#include "gdtoaimp.h"
#undef strtold_l
long double
strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
{
return strtod_l(s, sp, locale);
}
diff --git a/lib/libc/gdtoa/machdep_ldisx.c b/lib/libc/gdtoa/machdep_ldisx.c
index 7c7c0d9e5d28..e3cd4899452d 100644
--- a/lib/libc/gdtoa/machdep_ldisx.c
+++ b/lib/libc/gdtoa/machdep_ldisx.c
@@ -1,53 +1,52 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Machine-dependent glue to integrate David Gay's gdtoa
* package into libc for architectures where a long double
* is an IEEE extended precision number.
*/
-#include <sys/cdefs.h>
#include <float.h>
#include "gdtoaimp.h"
long double
strtold_l(const char * __restrict s, char ** __restrict sp, locale_t locale)
{
long double result;
FIX_LOCALE(locale);
strtorx_l(s, sp, FLT_ROUNDS, &result, locale);
return result;
}
diff --git a/lib/libc/gen/__getosreldate.c b/lib/libc/gen/__getosreldate.c
index 81e7382caac6..053ec4c94a9b 100644
--- a/lib/libc/gen/__getosreldate.c
+++ b/lib/libc/gen/__getosreldate.c
@@ -1,67 +1,66 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2007 Peter Wemm
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <link.h>
#include "libc_private.h"
/*
* This is private to libc. It is intended for wrapping syscall stubs in order
* to avoid having to put SIGSYS signal handlers in place to test for presence
* of new syscalls. This caches the result in order to be as quick as possible.
*
* Use getosreldate(3) for public use as it respects the $OSVERSION environment
* variable.
*/
int
__getosreldate(void)
{
static int osreldate;
size_t len;
int oid[2];
int error, osrel;
if (osreldate != 0)
return (osreldate);
error = _elf_aux_info(AT_OSRELDATE, &osreldate, sizeof(osreldate));
if (error == 0 && osreldate != 0)
return (osreldate);
oid[0] = CTL_KERN;
oid[1] = KERN_OSRELDATE;
osrel = 0;
len = sizeof(osrel);
error = sysctl(oid, 2, &osrel, &len, NULL, 0);
if (error == 0 && osrel > 0 && len == sizeof(osrel))
osreldate = osrel;
return (osreldate);
}
diff --git a/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c b/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c
index 1f0a8f7a944d..3a81ace8a0f4 100644
--- a/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c
+++ b/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c
@@ -1,42 +1,41 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <pthread.h>
#include "libc_private.h"
int
_pthread_mutex_init_calloc_cb_stub(pthread_mutex_t *mutex,
void *(calloc_cb)(size_t, size_t))
{
return (0);
}
diff --git a/lib/libc/gen/__xuname.c b/lib/libc/gen/__xuname.c
index f6e1372dc76a..8b55304f005e 100644
--- a/lib/libc/gen/__xuname.c
+++ b/lib/libc/gen/__xuname.c
@@ -1,145 +1,144 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)uname.c 8.1 (Berkeley) 1/4/94
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/utsname.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
int
__xuname(int namesize, void *namebuf)
{
int mib[2], rval;
size_t len;
char *p, *q;
int oerrno;
rval = 0;
q = (char *)namebuf;
mib[0] = CTL_KERN;
if ((p = getenv("UNAME_s")))
strlcpy(q, p, namesize);
else {
mib[1] = KERN_OSTYPE;
len = namesize;
oerrno = errno;
if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
if (errno == ENOMEM)
errno = oerrno;
else
rval = -1;
}
q[namesize - 1] = '\0';
}
q += namesize;
mib[1] = KERN_HOSTNAME;
len = namesize;
oerrno = errno;
if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
if (errno == ENOMEM)
errno = oerrno;
else
rval = -1;
}
q[namesize - 1] = '\0';
q += namesize;
if ((p = getenv("UNAME_r")))
strlcpy(q, p, namesize);
else {
mib[1] = KERN_OSRELEASE;
len = namesize;
oerrno = errno;
if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
if (errno == ENOMEM)
errno = oerrno;
else
rval = -1;
}
q[namesize - 1] = '\0';
}
q += namesize;
if ((p = getenv("UNAME_v")))
strlcpy(q, p, namesize);
else {
/*
* The version may have newlines in it, turn them into
* spaces.
*/
mib[1] = KERN_VERSION;
len = namesize;
oerrno = errno;
if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
if (errno == ENOMEM)
errno = oerrno;
else
rval = -1;
}
q[namesize - 1] = '\0';
for (p = q; len--; ++p) {
if (*p == '\n' || *p == '\t') {
if (len > 1)
*p = ' ';
else
*p = '\0';
}
}
}
q += namesize;
if ((p = getenv("UNAME_m")))
strlcpy(q, p, namesize);
else {
mib[0] = CTL_HW;
mib[1] = HW_MACHINE;
len = namesize;
oerrno = errno;
if (sysctl(mib, 2, q, &len, NULL, 0) == -1) {
if (errno == ENOMEM)
errno = oerrno;
else
rval = -1;
}
q[namesize - 1] = '\0';
}
return (rval);
}
diff --git a/lib/libc/gen/_once_stub.c b/lib/libc/gen/_once_stub.c
index 27de031108af..518072cbd28f 100644
--- a/lib/libc/gen/_once_stub.c
+++ b/lib/libc/gen/_once_stub.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <pthread.h>
#include "un-namespace.h"
#include "libc_private.h"
/* This implements pthread_once() for the single-threaded case. */
static int
_libc_once(pthread_once_t *once_control, void (*init_routine)(void))
{
if (once_control->state == PTHREAD_DONE_INIT)
return (0);
init_routine();
once_control->state = PTHREAD_DONE_INIT;
return (0);
}
/*
* This is the internal interface provided to libc. It will use
* pthread_once() from the threading library in a multi-threaded
* process and _libc_once() for a single-threaded library. Because
* _libc_once() uses the same ABI for the values in the pthread_once_t
* structure as the threading library, it is safe for a process to
* switch from _libc_once() to pthread_once() when threading is
* enabled.
*/
int
_once(pthread_once_t *once_control, void (*init_routine)(void))
{
if (__isthreaded)
return (_pthread_once(once_control, init_routine));
return (_libc_once(once_control, init_routine));
}
diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c
index 34e420ec11f5..a8723bbe72be 100644
--- a/lib/libc/gen/_pthread_stubs.c
+++ b/lib/libc/gen/_pthread_stubs.c
@@ -1,352 +1,351 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <signal.h>
#include <pthread.h>
#include <stdlib.h>
#include <errno.h>
#include "libc_private.h"
/*
* Weak symbols: All libc internal usage of these functions should
* use the weak symbol versions (_pthread_XXX). If libpthread is
* linked, it will override these functions with (non-weak) routines.
* The _pthread_XXX functions are provided solely for internal libc
* usage to avoid unwanted cancellation points and to differentiate
* between application locks and libc locks (threads holding the
* latter can't be allowed to exit/terminate).
*/
/* Define a null pthread structure just to satisfy _pthread_self. */
struct pthread {
};
static struct pthread main_thread;
static int stub_main(void);
static void *stub_null(void);
static struct pthread *stub_self(void);
static int stub_zero(void);
static int stub_fail(void);
static int stub_true(void);
static void stub_exit(void);
static int stub_esrch(void);
static int stub_getname_np(pthread_t, char *, size_t);
#define PJT_DUAL_ENTRY(entry) \
(pthread_func_t)entry, (pthread_func_t)entry
pthread_func_entry_t __thr_jtable[PJT_MAX] = {
[PJT_ATFORK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETDETACHSTATE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETGUARDSIZE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETINHERITSCHED] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETSCHEDPARAM] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETSCHEDPOLICY] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETSCOPE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETSTACKADDR] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GETSTACKSIZE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_INIT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETDETACHSTATE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETGUARDSIZE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETINHERITSCHED] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETSCHEDPARAM] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETSCHEDPOLICY] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETSCOPE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETSTACKADDR] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_SETSTACKSIZE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_CANCEL] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_CLEANUP_POP] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_CLEANUP_PUSH] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_COND_BROADCAST] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_COND_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_COND_INIT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_COND_SIGNAL] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_COND_TIMEDWAIT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_COND_WAIT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_DETACH] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_EQUAL] = {PJT_DUAL_ENTRY(stub_true)},
[PJT_EXIT] = {PJT_DUAL_ENTRY(stub_exit)},
[PJT_GETSPECIFIC] = {PJT_DUAL_ENTRY(stub_null)},
[PJT_JOIN] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_KEY_CREATE] = {PJT_DUAL_ENTRY(stub_fail)},
[PJT_KEY_DELETE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_KILL] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MAIN_NP] = {PJT_DUAL_ENTRY(stub_main)},
[PJT_MUTEXATTR_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEXATTR_INIT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEXATTR_SETTYPE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEX_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEX_INIT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEX_LOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEX_TRYLOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEX_UNLOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ONCE] = {PJT_DUAL_ENTRY(stub_fail)},
[PJT_RWLOCK_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_RWLOCK_INIT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_RWLOCK_RDLOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_RWLOCK_TRYRDLOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_RWLOCK_TRYWRLOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_RWLOCK_UNLOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_RWLOCK_WRLOCK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_SELF] = {PJT_DUAL_ENTRY(stub_self)},
[PJT_SETCANCELSTATE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_SETCANCELTYPE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_SETSPECIFIC] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_SIGMASK] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_TESTCANCEL] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_CLEANUP_POP_IMP] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_CLEANUP_PUSH_IMP] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_CANCEL_ENTER] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_CANCEL_LEAVE] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEX_CONSISTENT] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEXATTR_GETROBUST] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_MUTEXATTR_SETROBUST] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_GETTHREADID_NP] = {PJT_DUAL_ENTRY(stub_zero)},
[PJT_ATTR_GET_NP] = {PJT_DUAL_ENTRY(stub_esrch)},
[PJT_GETNAME_NP] = {PJT_DUAL_ENTRY(stub_getname_np)},
};
/*
* Weak aliases for exported (pthread_*) and internal (_pthread_*) routines.
*/
#define WEAK_REF(sym, alias) __weak_reference(sym, alias)
#define FUNC_TYPE(name) __CONCAT(name, _func_t)
#define FUNC_INT(name) __CONCAT(name, _int)
#define FUNC_EXP(name) __CONCAT(name, _exp)
#define STUB_FUNC(name, idx, ret) \
static ret FUNC_EXP(name)(void) __used; \
static ret FUNC_INT(name)(void) __used; \
WEAK_REF(FUNC_EXP(name), name); \
WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
typedef ret (*FUNC_TYPE(name))(void); \
static ret FUNC_EXP(name)(void) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
return (func()); \
} \
static ret FUNC_INT(name)(void) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
return (func()); \
}
#define STUB_FUNC1(name, idx, ret, p0_type) \
static ret FUNC_EXP(name)(p0_type) __used; \
static ret FUNC_INT(name)(p0_type) __used; \
WEAK_REF(FUNC_EXP(name), name); \
WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
typedef ret (*FUNC_TYPE(name))(p0_type); \
static ret FUNC_EXP(name)(p0_type p0) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
return (func(p0)); \
} \
static ret FUNC_INT(name)(p0_type p0) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
return (func(p0)); \
}
#define STUB_FUNC2(name, idx, ret, p0_type, p1_type) \
static ret FUNC_EXP(name)(p0_type, p1_type) __used; \
static ret FUNC_INT(name)(p0_type, p1_type) __used; \
WEAK_REF(FUNC_EXP(name), name); \
WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
typedef ret (*FUNC_TYPE(name))(p0_type, p1_type); \
static ret FUNC_EXP(name)(p0_type p0, p1_type p1) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
return (func(p0, p1)); \
} \
static ret FUNC_INT(name)(p0_type p0, p1_type p1) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
return (func(p0, p1)); \
}
#define STUB_FUNC3(name, idx, ret, p0_type, p1_type, p2_type) \
static ret FUNC_EXP(name)(p0_type, p1_type, p2_type) __used; \
static ret FUNC_INT(name)(p0_type, p1_type, p2_type) __used; \
WEAK_REF(FUNC_EXP(name), name); \
WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \
typedef ret (*FUNC_TYPE(name))(p0_type, p1_type, p2_type); \
static ret FUNC_EXP(name)(p0_type p0, p1_type p1, p2_type p2) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \
return (func(p0, p1, p2)); \
} \
static ret FUNC_INT(name)(p0_type p0, p1_type p1, p2_type p2) \
{ \
FUNC_TYPE(name) func; \
func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \
return (func(p0, p1, p2)); \
}
STUB_FUNC1(pthread_cond_broadcast, PJT_COND_BROADCAST, int, void *)
STUB_FUNC1(pthread_cond_destroy, PJT_COND_DESTROY, int, void *)
STUB_FUNC2(pthread_cond_init, PJT_COND_INIT, int, void *, void *)
STUB_FUNC1(pthread_cond_signal, PJT_COND_SIGNAL, int, void *)
STUB_FUNC2(pthread_cond_wait, PJT_COND_WAIT, int, void *, void *)
STUB_FUNC1(pthread_getspecific, PJT_GETSPECIFIC, void *, pthread_key_t)
STUB_FUNC2(pthread_key_create, PJT_KEY_CREATE, int, void *, void *)
STUB_FUNC1(pthread_key_delete, PJT_KEY_DELETE, int, pthread_key_t)
STUB_FUNC(pthread_main_np, PJT_MAIN_NP, int)
STUB_FUNC1(pthread_mutex_destroy, PJT_MUTEX_DESTROY, int, void *)
STUB_FUNC2(pthread_mutex_init, PJT_MUTEX_INIT, int, void *, void *)
STUB_FUNC1(pthread_mutex_lock, PJT_MUTEX_LOCK, int, void *)
STUB_FUNC1(pthread_mutex_trylock, PJT_MUTEX_TRYLOCK, int, void *)
STUB_FUNC1(pthread_mutex_unlock, PJT_MUTEX_UNLOCK, int, void *)
STUB_FUNC1(pthread_mutex_consistent, PJT_MUTEX_CONSISTENT, int, void *)
STUB_FUNC1(pthread_mutexattr_destroy, PJT_MUTEXATTR_DESTROY, int, void *)
STUB_FUNC1(pthread_mutexattr_init, PJT_MUTEXATTR_INIT, int, void *)
STUB_FUNC2(pthread_mutexattr_settype, PJT_MUTEXATTR_SETTYPE, int, void *, int)
STUB_FUNC2(pthread_mutexattr_getrobust, PJT_MUTEXATTR_GETROBUST, int, void *,
int *)
STUB_FUNC2(pthread_mutexattr_setrobust, PJT_MUTEXATTR_SETROBUST, int, void *,
int)
STUB_FUNC2(pthread_once, PJT_ONCE, int, void *, void *)
STUB_FUNC1(pthread_rwlock_destroy, PJT_RWLOCK_DESTROY, int, void *)
STUB_FUNC2(pthread_rwlock_init, PJT_RWLOCK_INIT, int, void *, void *)
STUB_FUNC1(pthread_rwlock_rdlock, PJT_RWLOCK_RDLOCK, int, void *)
STUB_FUNC1(pthread_rwlock_tryrdlock, PJT_RWLOCK_TRYRDLOCK, int, void *)
STUB_FUNC1(pthread_rwlock_trywrlock, PJT_RWLOCK_TRYWRLOCK, int, void *)
STUB_FUNC1(pthread_rwlock_unlock, PJT_RWLOCK_UNLOCK, int, void *)
STUB_FUNC1(pthread_rwlock_wrlock, PJT_RWLOCK_WRLOCK, int, void *)
STUB_FUNC(pthread_self, PJT_SELF, pthread_t)
STUB_FUNC(pthread_getthreadid_np, PJT_GETTHREADID_NP, int)
STUB_FUNC2(pthread_setspecific, PJT_SETSPECIFIC, int, pthread_key_t, void *)
STUB_FUNC3(pthread_sigmask, PJT_SIGMASK, int, int, void *, void *)
STUB_FUNC3(pthread_atfork, PJT_ATFORK, int, void *, void *, void*)
STUB_FUNC1(pthread_attr_destroy, PJT_ATTR_DESTROY, int, void *);
STUB_FUNC2(pthread_attr_getdetachstate, PJT_ATTR_GETDETACHSTATE, int, void *, void *)
STUB_FUNC2(pthread_attr_getguardsize, PJT_ATTR_GETGUARDSIZE, int, void *, void *)
STUB_FUNC2(pthread_attr_getstackaddr, PJT_ATTR_GETSTACKADDR, int, void *, void *)
STUB_FUNC2(pthread_attr_getstacksize, PJT_ATTR_GETSTACKSIZE, int, void *, void *)
STUB_FUNC2(pthread_attr_getinheritsched, PJT_ATTR_GETINHERITSCHED, int, void *, void *)
STUB_FUNC2(pthread_attr_getschedparam, PJT_ATTR_GETSCHEDPARAM, int, void *, void *)
STUB_FUNC2(pthread_attr_getschedpolicy, PJT_ATTR_GETSCHEDPOLICY, int, void *, void *)
STUB_FUNC2(pthread_attr_getscope, PJT_ATTR_GETSCOPE, int, void *, void *)
STUB_FUNC1(pthread_attr_init, PJT_ATTR_INIT, int, void *)
STUB_FUNC2(pthread_attr_setdetachstate, PJT_ATTR_SETDETACHSTATE, int, void *, int)
STUB_FUNC2(pthread_attr_setguardsize, PJT_ATTR_SETGUARDSIZE, int, void *, size_t)
STUB_FUNC2(pthread_attr_setstackaddr, PJT_ATTR_SETSTACKADDR, int, void *, void *)
STUB_FUNC2(pthread_attr_setstacksize, PJT_ATTR_SETSTACKSIZE, int, void *, size_t)
STUB_FUNC2(pthread_attr_setinheritsched, PJT_ATTR_SETINHERITSCHED, int, void *, int)
STUB_FUNC2(pthread_attr_setschedparam, PJT_ATTR_SETSCHEDPARAM, int, void *, void *)
STUB_FUNC2(pthread_attr_setschedpolicy, PJT_ATTR_SETSCHEDPOLICY, int, void *, int)
STUB_FUNC2(pthread_attr_setscope, PJT_ATTR_SETSCOPE, int, void *, int)
STUB_FUNC1(pthread_cancel, PJT_CANCEL, int, void *)
STUB_FUNC1(pthread_cleanup_pop, PJT_CLEANUP_POP, int, int)
STUB_FUNC2(pthread_cleanup_push, PJT_CLEANUP_PUSH, void, void *, void *)
STUB_FUNC3(pthread_cond_timedwait, PJT_COND_TIMEDWAIT, int, void *, void *, void *)
STUB_FUNC1(pthread_detach, PJT_DETACH, int, void *)
STUB_FUNC2(pthread_equal, PJT_EQUAL, int, void *, void *)
STUB_FUNC1(pthread_exit, PJT_EXIT, void, void *)
STUB_FUNC2(pthread_join, PJT_JOIN, int, void *, void *)
STUB_FUNC2(pthread_kill, PJT_KILL, int, void *, int)
STUB_FUNC2(pthread_setcancelstate, PJT_SETCANCELSTATE, int, int, void *)
STUB_FUNC2(pthread_setcanceltype, PJT_SETCANCELTYPE, int, int, void *)
STUB_FUNC(pthread_testcancel, PJT_TESTCANCEL, void)
STUB_FUNC1(__pthread_cleanup_pop_imp, PJT_CLEANUP_POP_IMP, void, int)
STUB_FUNC3(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, void *,
void *, void *)
STUB_FUNC1(_pthread_cancel_enter, PJT_CANCEL_ENTER, void, int)
STUB_FUNC1(_pthread_cancel_leave, PJT_CANCEL_LEAVE, void, int)
STUB_FUNC2(pthread_attr_get_np, PJT_ATTR_GET_NP, int, pthread_t, pthread_attr_t *)
STUB_FUNC3(pthread_getname_np, PJT_GETNAME_NP, int, pthread_t, char *, size_t)
static int
stub_zero(void)
{
return (0);
}
static void *
stub_null(void)
{
return (NULL);
}
static struct pthread *
stub_self(void)
{
return (&main_thread);
}
static int
stub_fail(void)
{
return (ENOSYS);
}
static int
stub_main(void)
{
return (-1);
}
static int
stub_true(void)
{
return (1);
}
static void
stub_exit(void)
{
exit(0);
}
static int
stub_esrch(void)
{
return (ESRCH);
}
static int
stub_getname_np(pthread_t thread, char *buf, size_t len)
{
if (thread != &main_thread)
return (ESRCH);
if (len >= 1)
buf[0] = '\0';
return (0);
}
diff --git a/lib/libc/gen/_rand48.c b/lib/libc/gen/_rand48.c
index e422781e44d3..990e2c86949b 100644
--- a/lib/libc/gen/_rand48.c
+++ b/lib/libc/gen/_rand48.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include "rand48.h"
unsigned short _rand48_seed[3] = {
RAND48_SEED_0,
RAND48_SEED_1,
RAND48_SEED_2
};
unsigned short _rand48_mult[3] = {
RAND48_MULT_0,
RAND48_MULT_1,
RAND48_MULT_2
};
unsigned short _rand48_add = RAND48_ADD;
void
_dorand48(unsigned short xseed[3])
{
unsigned long accu;
unsigned short temp[2];
accu = (unsigned long) _rand48_mult[0] * (unsigned long) xseed[0] +
(unsigned long) _rand48_add;
temp[0] = (unsigned short) accu; /* lower 16 bits */
accu >>= sizeof(unsigned short) * 8;
accu += (unsigned long) _rand48_mult[0] * (unsigned long) xseed[1] +
(unsigned long) _rand48_mult[1] * (unsigned long) xseed[0];
temp[1] = (unsigned short) accu; /* middle 16 bits */
accu >>= sizeof(unsigned short) * 8;
accu += _rand48_mult[0] * xseed[2] + _rand48_mult[1] * xseed[1] + _rand48_mult[2] * xseed[0];
xseed[0] = temp[0];
xseed[1] = temp[1];
xseed[2] = (unsigned short) accu;
}
diff --git a/lib/libc/gen/_spinlock_stub.c b/lib/libc/gen/_spinlock_stub.c
index b220d90ea193..30e5c61f5f74 100644
--- a/lib/libc/gen/_spinlock_stub.c
+++ b/lib/libc/gen/_spinlock_stub.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include "spinlock.h"
#include "libc_private.h"
long _atomic_lock_stub(volatile long *);
void _spinlock_stub(spinlock_t *);
void _spinunlock_stub(spinlock_t *);
__weak_reference(_atomic_lock_stub, _atomic_lock);
long
_atomic_lock_stub(volatile long *lck __unused)
{
return (0L);
}
#pragma weak _spinlock
void
_spinlock(spinlock_t *lck)
{
((void (*)(spinlock_t *lck))__libc_interposing[INTERPOS_spinlock])
(lck);
}
#pragma weak _spinunlock
void
_spinunlock(spinlock_t *lck)
{
((void (*)(spinlock_t *lck))__libc_interposing[INTERPOS_spinunlock])
(lck);
}
void
__libc_spinlock_stub(spinlock_t *lck __unused)
{
}
void
__libc_spinunlock_stub(spinlock_t *lck __unused)
{
}
diff --git a/lib/libc/gen/_thread_init.c b/lib/libc/gen/_thread_init.c
index b285654cc863..66fa8b8c2e96 100644
--- a/lib/libc/gen/_thread_init.c
+++ b/lib/libc/gen/_thread_init.c
@@ -1,44 +1,43 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
void _thread_init_stub(void);
__weak_reference(_thread_init_stub, _thread_init);
__weak_reference(_thread_autoinit_dummy_decl_stub,
_thread_autoinit_dummy_decl);
int _thread_autoinit_dummy_decl_stub = 0;
void
_thread_init_stub(void)
{
/* This is just a stub; there is nothing to do. */
}
diff --git a/lib/libc/gen/arc4random-compat.c b/lib/libc/gen/arc4random-compat.c
index 014273b1a76d..beeb4d75964a 100644
--- a/lib/libc/gen/arc4random-compat.c
+++ b/lib/libc/gen/arc4random-compat.c
@@ -1,68 +1,67 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 Google LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdbool.h>
#include <syslog.h>
/*
* The following functions were removed from OpenBSD for good reasons:
*
* - arc4random_stir()
* - arc4random_addrandom()
*
* On FreeBSD, for backward ABI compatibility, we provide two wrapper which
* logs this event and returns.
*/
void __arc4random_stir_fbsd11(void);
void __arc4random_addrandom_fbsd11(u_char *, int);
void
__arc4random_stir_fbsd11(void)
{
static bool warned = false;
if (!warned)
syslog(LOG_DEBUG, "Deprecated function arc4random_stir() called");
warned = true;
}
void
__arc4random_addrandom_fbsd11(u_char * dummy1 __unused, int dummy2 __unused)
{
static bool warned = false;
if (!warned)
syslog(LOG_DEBUG, "Deprecated function arc4random_addrandom() called");
warned = true;
}
__sym_compat(arc4random_stir, __arc4random_stir_fbsd11, FBSD_1.0);
__sym_compat(arc4random_addrandom, __arc4random_addrandom_fbsd11, FBSD_1.0);
diff --git a/lib/libc/gen/arc4random.c b/lib/libc/gen/arc4random.c
index 621af03a57a7..fdb1688cfe9c 100644
--- a/lib/libc/gen/arc4random.c
+++ b/lib/libc/gen/arc4random.c
@@ -1,252 +1,251 @@
/* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */
/*
* Copyright (c) 1996, David Mazieres <dm@uun.org>
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
* Copyright (c) 2013, Markus Friedl <markus@openbsd.org>
* Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org>
*
* 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.
*/
/*
* ChaCha based random number generator for OpenBSD.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#if defined(__FreeBSD__)
#include <assert.h>
#endif
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/time.h>
#include "libc_private.h"
#include "un-namespace.h"
#define CHACHA_EMBED
#define KEYSTREAM_ONLY
#if defined(__FreeBSD__)
#define ARC4RANDOM_FXRNG 1
#else
#define ARC4RANDOM_FXRNG 0
#endif
#include "chacha.c"
#define minimum(a, b) ((a) < (b) ? (a) : (b))
#if defined(__GNUC__) || defined(_MSC_VER)
#define inline __inline
#else /* __GNUC__ || _MSC_VER */
#define inline
#endif /* !__GNUC__ && !_MSC_VER */
#define KEYSZ 32
#define IVSZ 8
#define BLOCKSZ 64
#define RSBUFSZ (16*BLOCKSZ)
#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */
/* Marked INHERIT_ZERO, so zero'd out in fork children. */
static struct _rs {
size_t rs_have; /* valid bytes at end of rs_buf */
size_t rs_count; /* bytes till reseed */
} *rs;
/* Maybe be preserved in fork children, if _rs_allocate() decides. */
static struct _rsx {
chacha_ctx rs_chacha; /* chacha context for random keystream */
u_char rs_buf[RSBUFSZ]; /* keystream blocks */
#ifdef __FreeBSD__
uint32_t rs_seed_generation; /* 32-bit userspace RNG version */
#endif
} *rsx;
static inline int _rs_allocate(struct _rs **, struct _rsx **);
static inline void _rs_forkdetect(void);
#include "arc4random.h"
static inline void _rs_rekey(u_char *dat, size_t datlen);
static inline void
_rs_init(u_char *buf, size_t n)
{
if (n < KEYSZ + IVSZ)
return;
if (rs == NULL) {
if (_rs_allocate(&rs, &rsx) == -1)
_exit(1);
}
chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8);
chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL);
}
static void
_rs_stir(void)
{
u_char rnd[KEYSZ + IVSZ];
uint32_t rekey_fuzz = 0;
#if defined(__FreeBSD__)
bool need_init;
/*
* De-couple allocation (which locates the vdso_fxrngp pointer in
* auxinfo) from initialization. This allows us to read the root seed
* version before we fetch system entropy, maintaining the invariant
* that the PRF was seeded with entropy from rs_seed_generation or a
* later generation. But never seeded from an earlier generation.
* This invariant prevents us from missing a root reseed event.
*/
need_init = false;
if (rs == NULL) {
if (_rs_allocate(&rs, &rsx) == -1)
abort();
need_init = true;
}
/*
* Transition period: new userspace on old kernel. This should become
* a hard error at some point, if the scheme is adopted.
*/
if (vdso_fxrngp != NULL)
rsx->rs_seed_generation =
fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32);
#endif
if (getentropy(rnd, sizeof rnd) == -1)
_getentropy_fail();
#if !defined(__FreeBSD__)
if (!rs)
_rs_init(rnd, sizeof(rnd));
#else /* __FreeBSD__ */
assert(rs != NULL);
if (need_init)
_rs_init(rnd, sizeof(rnd));
#endif
else
_rs_rekey(rnd, sizeof(rnd));
explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */
/* invalidate rs_buf */
rs->rs_have = 0;
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
/* rekey interval should not be predictable */
chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz,
(uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz));
rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE);
}
static inline void
_rs_stir_if_needed(size_t len)
{
_rs_forkdetect();
if (!rs || rs->rs_count <= len)
_rs_stir();
if (rs->rs_count <= len)
rs->rs_count = 0;
else
rs->rs_count -= len;
}
static inline void
_rs_rekey(u_char *dat, size_t datlen)
{
#ifndef KEYSTREAM_ONLY
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
#endif
/* fill rs_buf with the keystream */
chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf,
rsx->rs_buf, sizeof(rsx->rs_buf));
/* mix in optional user provided data */
if (dat) {
size_t i, m;
m = minimum(datlen, KEYSZ + IVSZ);
for (i = 0; i < m; i++)
rsx->rs_buf[i] ^= dat[i];
}
/* immediately reinit for backtracking resistance */
_rs_init(rsx->rs_buf, KEYSZ + IVSZ);
memset(rsx->rs_buf, 0, KEYSZ + IVSZ);
rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ;
}
static inline void
_rs_random_buf(void *_buf, size_t n)
{
u_char *buf = (u_char *)_buf;
u_char *keystream;
size_t m;
_rs_stir_if_needed(n);
while (n > 0) {
if (rs->rs_have > 0) {
m = minimum(n, rs->rs_have);
keystream = rsx->rs_buf + sizeof(rsx->rs_buf)
- rs->rs_have;
memcpy(buf, keystream, m);
memset(keystream, 0, m);
buf += m;
n -= m;
rs->rs_have -= m;
}
if (rs->rs_have == 0)
_rs_rekey(NULL, 0);
}
}
static inline void
_rs_random_u32(uint32_t *val)
{
u_char *keystream;
_rs_stir_if_needed(sizeof(*val));
if (rs->rs_have < sizeof(*val))
_rs_rekey(NULL, 0);
keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have;
memcpy(val, keystream, sizeof(*val));
memset(keystream, 0, sizeof(*val));
rs->rs_have -= sizeof(*val);
}
uint32_t
arc4random(void)
{
uint32_t val;
_ARC4_LOCK();
_rs_random_u32(&val);
_ARC4_UNLOCK();
return val;
}
void
arc4random_buf(void *buf, size_t n)
{
_ARC4_LOCK();
_rs_random_buf(buf, n);
_ARC4_UNLOCK();
}
diff --git a/lib/libc/gen/auxv.c b/lib/libc/gen/auxv.c
index 1b0d886030b2..b0b3a8ed708b 100644
--- a/lib/libc/gen/auxv.c
+++ b/lib/libc/gen/auxv.c
@@ -1,404 +1,403 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2010, 2012 Konstantin Belousov <kib@FreeBSD.ORG>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <elf.h>
#include <errno.h>
#include <link.h>
#include <pthread.h>
#include <string.h>
#include <sys/auxv.h>
#include "un-namespace.h"
#include "libc_private.h"
extern int _DYNAMIC;
#pragma weak _DYNAMIC
void *__elf_aux_vector;
static pthread_once_t aux_vector_once = PTHREAD_ONCE_INIT;
static void
init_aux_vector_once(void)
{
Elf_Addr *sp;
sp = (Elf_Addr *)environ;
while (*sp++ != 0)
;
__elf_aux_vector = (Elf_Auxinfo *)sp;
}
void
__init_elf_aux_vector(void)
{
if (&_DYNAMIC != NULL)
return;
_once(&aux_vector_once, init_aux_vector_once);
}
static pthread_once_t aux_once = PTHREAD_ONCE_INIT;
static int pagesize, osreldate, canary_len, ncpus, pagesizes_len, bsdflags;
static int hwcap_present, hwcap2_present;
static char *canary, *pagesizes, *execpath;
static void *ps_strings, *timekeep;
static u_long hwcap, hwcap2;
static void *fxrng_seed_version;
static u_long usrstackbase, usrstacklim;
#ifdef __powerpc__
static int powerpc_new_auxv_format = 0;
static void _init_aux_powerpc_fixup(void);
int _powerpc_elf_aux_info(int, void *, int);
#endif
static void
init_aux(void)
{
Elf_Auxinfo *aux;
for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
switch (aux->a_type) {
case AT_BSDFLAGS:
bsdflags = aux->a_un.a_val;
break;
case AT_CANARY:
canary = (char *)(aux->a_un.a_ptr);
break;
case AT_CANARYLEN:
canary_len = aux->a_un.a_val;
break;
case AT_EXECPATH:
execpath = (char *)(aux->a_un.a_ptr);
break;
case AT_HWCAP:
hwcap_present = 1;
hwcap = (u_long)(aux->a_un.a_val);
break;
case AT_HWCAP2:
hwcap2_present = 1;
hwcap2 = (u_long)(aux->a_un.a_val);
break;
case AT_PAGESIZES:
pagesizes = (char *)(aux->a_un.a_ptr);
break;
case AT_PAGESIZESLEN:
pagesizes_len = aux->a_un.a_val;
break;
case AT_PAGESZ:
pagesize = aux->a_un.a_val;
break;
case AT_OSRELDATE:
osreldate = aux->a_un.a_val;
break;
case AT_NCPUS:
ncpus = aux->a_un.a_val;
break;
case AT_TIMEKEEP:
timekeep = aux->a_un.a_ptr;
break;
case AT_PS_STRINGS:
ps_strings = aux->a_un.a_ptr;
break;
case AT_FXRNG:
fxrng_seed_version = aux->a_un.a_ptr;
break;
case AT_USRSTACKBASE:
usrstackbase = aux->a_un.a_val;
break;
case AT_USRSTACKLIM:
usrstacklim = aux->a_un.a_val;
break;
#ifdef __powerpc__
/*
* Since AT_STACKPROT is always set, and the common
* value 23 is mutually exclusive with the legacy powerpc
* value 21, the existence of AT_STACKPROT proves we are
* on the common format.
*/
case AT_STACKPROT: /* 23 */
powerpc_new_auxv_format = 1;
break;
#endif
}
}
#ifdef __powerpc__
if (!powerpc_new_auxv_format)
_init_aux_powerpc_fixup();
#endif
}
#ifdef __powerpc__
static void
_init_aux_powerpc_fixup(void)
{
Elf_Auxinfo *aux;
/*
* Before 1300070, PowerPC platforms had nonstandard numbering for
* the aux vector. When running old binaries, the kernel will pass
* the vector using the old numbering. Reload affected variables.
*/
for (aux = __elf_aux_vector; aux->a_type != AT_NULL; aux++) {
switch (aux->a_type) {
case AT_OLD_CANARY:
canary = (char *)(aux->a_un.a_ptr);
break;
case AT_OLD_CANARYLEN:
canary_len = aux->a_un.a_val;
break;
case AT_OLD_EXECPATH:
execpath = (char *)(aux->a_un.a_ptr);
break;
case AT_OLD_PAGESIZES:
pagesizes = (char *)(aux->a_un.a_ptr);
break;
case AT_OLD_PAGESIZESLEN:
pagesizes_len = aux->a_un.a_val;
break;
case AT_OLD_OSRELDATE:
osreldate = aux->a_un.a_val;
break;
case AT_OLD_NCPUS:
ncpus = aux->a_un.a_val;
break;
}
}
}
int
_powerpc_elf_aux_info(int aux, void *buf, int buflen)
{
/*
* If we are in the old auxv format, we need to translate the aux
* parameter of elf_aux_info() calls into the common auxv format.
* Internal libc calls always use the common format, and they
* directly call _elf_aux_info instead of using the weak symbol.
*/
if (!powerpc_new_auxv_format) {
switch (aux) {
case AT_OLD_EXECPATH:
aux = AT_EXECPATH;
break;
case AT_OLD_CANARY:
aux = AT_CANARY;
break;
case AT_OLD_CANARYLEN:
aux = AT_CANARYLEN;
break;
case AT_OLD_OSRELDATE:
aux = AT_OSRELDATE;
break;
case AT_OLD_NCPUS:
aux = AT_NCPUS;
break;
case AT_OLD_PAGESIZES:
aux = AT_PAGESIZES;
break;
case AT_OLD_PAGESIZESLEN:
aux = AT_PAGESIZESLEN;
break;
case AT_OLD_STACKPROT:
aux = AT_STACKPROT;
break;
}
}
return _elf_aux_info(aux, buf, buflen);
}
__weak_reference(_powerpc_elf_aux_info, elf_aux_info);
#else
__weak_reference(_elf_aux_info, elf_aux_info);
#endif
int
_elf_aux_info(int aux, void *buf, int buflen)
{
int res;
__init_elf_aux_vector();
if (__elf_aux_vector == NULL)
return (ENOSYS);
_once(&aux_once, init_aux);
if (buflen < 0)
return (EINVAL);
switch (aux) {
case AT_CANARY:
if (canary != NULL && canary_len >= buflen) {
memcpy(buf, canary, buflen);
memset(canary, 0, canary_len);
canary = NULL;
res = 0;
} else
res = ENOENT;
break;
case AT_EXECPATH:
if (execpath == NULL)
res = ENOENT;
else if (buf == NULL)
res = EINVAL;
else {
if (strlcpy(buf, execpath, buflen) >=
(unsigned int)buflen)
res = EINVAL;
else
res = 0;
}
break;
case AT_HWCAP:
if (hwcap_present && buflen == sizeof(u_long)) {
*(u_long *)buf = hwcap;
res = 0;
} else
res = ENOENT;
break;
case AT_HWCAP2:
if (hwcap2_present && buflen == sizeof(u_long)) {
*(u_long *)buf = hwcap2;
res = 0;
} else
res = ENOENT;
break;
case AT_PAGESIZES:
if (pagesizes != NULL && pagesizes_len >= buflen) {
memcpy(buf, pagesizes, buflen);
res = 0;
} else
res = ENOENT;
break;
case AT_PAGESZ:
if (buflen == sizeof(int)) {
if (pagesize != 0) {
*(int *)buf = pagesize;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
case AT_OSRELDATE:
if (buflen == sizeof(int)) {
if (osreldate != 0) {
*(int *)buf = osreldate;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
case AT_NCPUS:
if (buflen == sizeof(int)) {
if (ncpus != 0) {
*(int *)buf = ncpus;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
case AT_TIMEKEEP:
if (buflen == sizeof(void *)) {
if (timekeep != NULL) {
*(void **)buf = timekeep;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
case AT_BSDFLAGS:
if (buflen == sizeof(int)) {
*(int *)buf = bsdflags;
res = 0;
} else
res = EINVAL;
break;
case AT_PS_STRINGS:
if (buflen == sizeof(void *)) {
if (ps_strings != NULL) {
*(void **)buf = ps_strings;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
case AT_FXRNG:
if (buflen == sizeof(void *)) {
if (fxrng_seed_version != NULL) {
*(void **)buf = fxrng_seed_version;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
case AT_USRSTACKBASE:
if (buflen == sizeof(u_long)) {
if (usrstackbase != 0) {
*(u_long *)buf = usrstackbase;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
case AT_USRSTACKLIM:
if (buflen == sizeof(u_long)) {
if (usrstacklim != 0) {
*(u_long *)buf = usrstacklim;
res = 0;
} else
res = ENOENT;
} else
res = EINVAL;
break;
default:
res = ENOENT;
break;
}
return (res);
}
diff --git a/lib/libc/gen/basename.c b/lib/libc/gen/basename.c
index 46fea9a630cf..d0ba1bd9229c 100644
--- a/lib/libc/gen/basename.c
+++ b/lib/libc/gen/basename.c
@@ -1,52 +1,51 @@
/*-
* Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <libgen.h>
#include <string.h>
char *
(basename)(char *path)
{
char *ptr;
/*
* If path is a null pointer or points to an empty string,
* basename() shall return a pointer to the string ".".
*/
if (path == NULL || *path == '\0')
return (__DECONST(char *, "."));
/* Find end of last pathname component and null terminate it. */
ptr = path + strlen(path);
while (ptr > path + 1 && *(ptr - 1) == '/')
--ptr;
*ptr-- = '\0';
/* Find beginning of last pathname component. */
while (ptr > path && *(ptr - 1) != '/')
--ptr;
return (ptr);
}
diff --git a/lib/libc/gen/basename_compat.c b/lib/libc/gen/basename_compat.c
index 217c4582e857..19a4bd6c03eb 100644
--- a/lib/libc/gen/basename_compat.c
+++ b/lib/libc/gen/basename_compat.c
@@ -1,83 +1,82 @@
/* $OpenBSD: basename.c,v 1.14 2005/08/08 08:05:33 espie Exp $ */
/*
* Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 <sys/cdefs.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
char * __freebsd11_basename_r(const char *path, char *bname);
char * __freebsd11_basename(char *path);
char *
__freebsd11_basename_r(const char *path, char *bname)
{
const char *endp, *startp;
size_t len;
/* Empty or NULL string gets treated as "." */
if (path == NULL || *path == '\0') {
bname[0] = '.';
bname[1] = '\0';
return (bname);
}
/* Strip any trailing slashes */
endp = path + strlen(path) - 1;
while (endp > path && *endp == '/')
endp--;
/* All slashes becomes "/" */
if (endp == path && *endp == '/') {
bname[0] = '/';
bname[1] = '\0';
return (bname);
}
/* Find the start of the base */
startp = endp;
while (startp > path && *(startp - 1) != '/')
startp--;
len = endp - startp + 1;
if (len >= MAXPATHLEN) {
errno = ENAMETOOLONG;
return (NULL);
}
memcpy(bname, startp, len);
bname[len] = '\0';
return (bname);
}
char *
__freebsd11_basename(char *path)
{
static char *bname = NULL;
if (bname == NULL) {
bname = (char *)malloc(MAXPATHLEN);
if (bname == NULL)
return (NULL);
}
return (__freebsd11_basename_r(path, bname));
}
__sym_compat(basename_r, __freebsd11_basename_r, FBSD_1.2);
__sym_compat(basename, __freebsd11_basename, FBSD_1.0);
diff --git a/lib/libc/gen/cap_sandboxed.c b/lib/libc/gen/cap_sandboxed.c
index d01d94735bec..63c2439382a6 100644
--- a/lib/libc/gen/cap_sandboxed.c
+++ b/lib/libc/gen/cap_sandboxed.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 The FreeBSD Foundation
*
* This software was developed by Pawel Jakub Dawidek under sponsorship from
* the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/capsicum.h>
#include <assert.h>
#include <errno.h>
#include <stdbool.h>
bool
cap_sandboxed(void)
{
u_int mode;
if (cap_getmode(&mode) != 0) {
assert(errno == ENOSYS);
return (false);
}
assert(mode == 0 || mode == 1);
return (mode == 1);
}
diff --git a/lib/libc/gen/check_utility_compat.c b/lib/libc/gen/check_utility_compat.c
index 6b1b487945f2..63a268896daa 100644
--- a/lib/libc/gen/check_utility_compat.c
+++ b/lib/libc/gen/check_utility_compat.c
@@ -1,69 +1,68 @@
/*
* Copyright 2002 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
/*
* I din't use "namespace.h" here because none of the relevant utilities
* are threaded, so I'm not concerned about cancellation points or other
* niceties.
*/
#include <sys/limits.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define _PATH_UTIL_COMPAT "/etc/compat-FreeBSD-4-util"
#define _ENV_UTIL_COMPAT "_COMPAT_FreeBSD_4"
int
check_utility_compat(const char *utility)
{
char buf[PATH_MAX];
char *p, *bp;
int len;
if ((p = getenv(_ENV_UTIL_COMPAT)) != NULL) {
strlcpy(buf, p, sizeof buf);
} else {
if ((len = readlink(_PATH_UTIL_COMPAT, buf, sizeof(buf) - 1)) < 0)
return 0;
buf[len] = '\0';
}
if (buf[0] == '\0')
return 1;
bp = buf;
while ((p = strsep(&bp, ",")) != NULL) {
if (strcmp(p, utility) == 0)
return 1;
}
return 0;
}
diff --git a/lib/libc/gen/clock_getcpuclockid.c b/lib/libc/gen/clock_getcpuclockid.c
index fdfe3b614d69..77d6c3423301 100644
--- a/lib/libc/gen/clock_getcpuclockid.c
+++ b/lib/libc/gen/clock_getcpuclockid.c
@@ -1,41 +1,40 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 David Xu <davidxu@FreeBSD.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <time.h>
#include <unistd.h>
#include <sys/time.h>
int
clock_getcpuclockid(pid_t pid, clockid_t *clock_id)
{
if (clock_getcpuclockid2(pid, CPUCLOCK_WHICH_PID, clock_id))
return (errno);
return (0);
}
diff --git a/lib/libc/gen/ctermid.c b/lib/libc/gen/ctermid.c
index 35be197742a7..9265d402930c 100644
--- a/lib/libc/gen/ctermid.c
+++ b/lib/libc/gen/ctermid.c
@@ -1,70 +1,69 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <paths.h>
#include <stdio.h>
#include <string.h>
#define LEN_PATH_DEV (sizeof(_PATH_DEV) - 1)
char *
ctermid(char *s)
{
static char def[sizeof(_PATH_DEV) + SPECNAMELEN];
struct stat sb;
size_t dlen;
int sverrno;
if (s == NULL) {
s = def;
dlen = sizeof(def) - LEN_PATH_DEV;
} else
dlen = L_ctermid - LEN_PATH_DEV;
strcpy(s, _PATH_TTY);
/* Attempt to perform a lookup of the actual TTY pathname. */
sverrno = errno;
if (stat(_PATH_TTY, &sb) == 0 && S_ISCHR(sb.st_mode))
(void)sysctlbyname("kern.devname", s + LEN_PATH_DEV,
&dlen, &sb.st_rdev, sizeof(sb.st_rdev));
errno = sverrno;
return (s);
}
char *
ctermid_r(char *s)
{
return (s != NULL ? ctermid(s) : NULL);
}
diff --git a/lib/libc/gen/devname-compat11.c b/lib/libc/gen/devname-compat11.c
index 37886b6c8aaa..b01b0845e261 100644
--- a/lib/libc/gen/devname-compat11.c
+++ b/lib/libc/gen/devname-compat11.c
@@ -1,48 +1,47 @@
/*-
* Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include "gen-compat.h"
char *
freebsd11_devname(uint32_t dev, mode_t type)
{
return (devname(dev, type));
}
char *
freebsd11_devname_r(uint32_t dev, mode_t type, char *buf, int len)
{
return (devname_r(dev, type, buf, len));
}
__sym_compat(devname, freebsd11_devname, FBSD_1.0);
__sym_compat(devname_r, freebsd11_devname_r, FBSD_1.0);
diff --git a/lib/libc/gen/dirfd.c b/lib/libc/gen/dirfd.c
index 123d856eba47..85090bd4da6c 100644
--- a/lib/libc/gen/dirfd.c
+++ b/lib/libc/gen/dirfd.c
@@ -1,43 +1,42 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <dirent.h>
#include "un-namespace.h"
#include "gen-private.h"
int
dirfd(DIR *dirp)
{
return (_dirfd(dirp));
}
diff --git a/lib/libc/gen/dirname.c b/lib/libc/gen/dirname.c
index ab36ac66dea1..7157fec23630 100644
--- a/lib/libc/gen/dirname.c
+++ b/lib/libc/gen/dirname.c
@@ -1,71 +1,70 @@
/*-
* Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <libgen.h>
#include <string.h>
char *
(dirname)(char *path)
{
char *end;
/*
* If path is a null pointer or points to an empty string,
* dirname() shall return a pointer to the string ".".
*/
if (path == NULL || *path == '\0')
return (__DECONST(char *, "."));
/* Find end of last pathname component. */
end = path + strlen(path);
while (end > path + 1 && *(end - 1) == '/')
--end;
/* Strip off the last pathname component. */
while (end > path && *(end - 1) != '/')
--end;
/*
* If path does not contain a '/', then dirname() shall return a
* pointer to the string ".".
*/
if (end == path) {
path[0] = '.';
path[1] = '\0';
return (path);
}
/*
* Remove trailing slashes from the resulting directory name. Ensure
* that at least one character remains.
*/
while (end > path + 1 && *(end - 1) == '/')
--end;
/* Null terminate directory name and return it. */
*end = '\0';
return (path);
}
diff --git a/lib/libc/gen/dirname_compat.c b/lib/libc/gen/dirname_compat.c
index 6423984b1877..7eca7eb03f83 100644
--- a/lib/libc/gen/dirname_compat.c
+++ b/lib/libc/gen/dirname_compat.c
@@ -1,79 +1,78 @@
/* $OpenBSD: dirname.c,v 1.13 2005/08/08 08:05:33 espie Exp $ */
/*
* Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 <sys/cdefs.h>
#include <errno.h>
#include <libgen.h>
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
char * __freebsd11_dirname(char *path);
char *
__freebsd11_dirname(char *path)
{
static char *dname = NULL;
size_t len;
const char *endp;
if (dname == NULL) {
dname = (char *)malloc(MAXPATHLEN);
if (dname == NULL)
return(NULL);
}
/* Empty or NULL string gets treated as "." */
if (path == NULL || *path == '\0') {
dname[0] = '.';
dname[1] = '\0';
return (dname);
}
/* Strip any trailing slashes */
endp = path + strlen(path) - 1;
while (endp > path && *endp == '/')
endp--;
/* Find the start of the dir */
while (endp > path && *endp != '/')
endp--;
/* Either the dir is "/" or there are no slashes */
if (endp == path) {
dname[0] = *endp == '/' ? '/' : '.';
dname[1] = '\0';
return (dname);
} else {
/* Move forward past the separating slashes */
do {
endp--;
} while (endp > path && *endp == '/');
}
len = endp - path + 1;
if (len >= MAXPATHLEN) {
errno = ENAMETOOLONG;
return (NULL);
}
memcpy(dname, path, len);
dname[len] = '\0';
return (dname);
}
__sym_compat(dirname, __freebsd11_dirname, FBSD_1.0);
diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c
index b6dab041bac3..b678df9eef47 100644
--- a/lib/libc/gen/dlfcn.c
+++ b/lib/libc/gen/dlfcn.c
@@ -1,341 +1,340 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998 John D. Polstra
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#if !defined(IN_LIBDL) || defined(PIC)
/*
* Linkage to services provided by the dynamic linker.
*/
#include <sys/types.h>
#include <sys/mman.h>
#include <machine/atomic.h>
#include <dlfcn.h>
#include <link.h>
#include <stddef.h>
#include <string.h>
#include "namespace.h"
#include <pthread.h>
#include "un-namespace.h"
#include "rtld.h"
#include "libc_private.h"
#include "reentrant.h"
static const char sorry[] = "Service unavailable";
void _rtld_thread_init(void *);
void _rtld_atfork_pre(int *);
void _rtld_atfork_post(int *);
/*
* For ELF, the dynamic linker directly resolves references to its
* services to functions inside the dynamic linker itself. These
* weak-symbol stubs are necessary so that "ld" won't complain about
* undefined symbols. The stubs are executed only when the program is
* linked statically, or when a given service isn't implemented in the
* dynamic linker. They must return an error if called, and they must
* be weak symbols so that the dynamic linker can override them.
*/
#pragma weak _rtld_error
void
_rtld_error(const char *fmt __unused, ...)
{
}
#pragma weak dladdr
int
dladdr(const void *addr __unused, Dl_info *dlip __unused)
{
_rtld_error(sorry);
return (0);
}
#pragma weak dlclose
int
dlclose(void *handle __unused)
{
_rtld_error(sorry);
return (-1);
}
#pragma weak dlerror
char *
dlerror(void)
{
return (__DECONST(char *, sorry));
}
#pragma weak dllockinit
void
dllockinit(void *context,
void *(*lock_create)(void *context) __unused,
void (*rlock_acquire)(void *lock) __unused,
void (*wlock_acquire)(void *lock) __unused,
void (*lock_release)(void *lock) __unused,
void (*lock_destroy)(void *lock) __unused,
void (*context_destroy)(void *context) __unused)
{
if (context_destroy != NULL)
context_destroy(context);
}
#pragma weak dlopen
void *
dlopen(const char *name __unused, int mode __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlsym
void *
dlsym(void * __restrict handle __unused, const char * __restrict name __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlfunc
dlfunc_t
dlfunc(void * __restrict handle __unused, const char * __restrict name __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlvsym
void *
dlvsym(void * __restrict handle __unused, const char * __restrict name __unused,
const char * __restrict version __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak dlinfo
int
dlinfo(void * __restrict handle __unused, int request __unused,
void * __restrict p __unused)
{
_rtld_error(sorry);
return (0);
}
#pragma weak _rtld_thread_init
void
_rtld_thread_init(void *li __unused)
{
_rtld_error(sorry);
}
#ifndef IN_LIBDL
static pthread_once_t dl_phdr_info_once = PTHREAD_ONCE_INIT;
static struct dl_phdr_info phdr_info;
#ifndef PIC
static mutex_t dl_phdr_info_lock = MUTEX_INITIALIZER;
#endif
static void
dl_init_phdr_info(void)
{
Elf_Auxinfo *auxp;
unsigned int i;
for (auxp = __elf_aux_vector; auxp->a_type != AT_NULL; auxp++) {
switch (auxp->a_type) {
case AT_BASE:
phdr_info.dlpi_addr = (Elf_Addr)auxp->a_un.a_ptr;
break;
case AT_EXECPATH:
phdr_info.dlpi_name = (const char *)auxp->a_un.a_ptr;
break;
case AT_PHDR:
phdr_info.dlpi_phdr =
(const Elf_Phdr *)auxp->a_un.a_ptr;
break;
case AT_PHNUM:
phdr_info.dlpi_phnum = (Elf_Half)auxp->a_un.a_val;
break;
}
}
for (i = 0; i < phdr_info.dlpi_phnum; i++) {
if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) {
phdr_info.dlpi_tls_modid = 1;
}
}
phdr_info.dlpi_adds = 1;
}
#endif
#pragma weak dl_iterate_phdr
int
dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused,
void *data __unused)
{
#if defined IN_LIBDL
return (0);
#elif defined PIC
int (*r)(int (*)(struct dl_phdr_info *, size_t, void *), void *);
r = dlsym(RTLD_DEFAULT, "dl_iterate_phdr");
if (r == NULL)
return (0);
return (r(callback, data));
#else
tls_index ti;
int ret;
__init_elf_aux_vector();
if (__elf_aux_vector == NULL)
return (1);
_once(&dl_phdr_info_once, dl_init_phdr_info);
ti.ti_module = 1;
ti.ti_offset = 0;
mutex_lock(&dl_phdr_info_lock);
phdr_info.dlpi_tls_data = __tls_get_addr(&ti);
ret = callback(&phdr_info, sizeof(phdr_info), data);
mutex_unlock(&dl_phdr_info_lock);
return (ret);
#endif
}
#pragma weak fdlopen
void *
fdlopen(int fd __unused, int mode __unused)
{
_rtld_error(sorry);
return (NULL);
}
#pragma weak _rtld_atfork_pre
void
_rtld_atfork_pre(int *locks __unused)
{
}
#pragma weak _rtld_atfork_post
void
_rtld_atfork_post(int *locks __unused)
{
}
#ifndef IN_LIBDL
struct _rtld_addr_phdr_cb_data {
const void *addr;
struct dl_phdr_info *dli;
};
static int
_rtld_addr_phdr_cb(struct dl_phdr_info *dli, size_t sz, void *arg)
{
struct _rtld_addr_phdr_cb_data *rd;
const Elf_Phdr *ph;
unsigned i;
rd = arg;
for (i = 0; i < dli->dlpi_phnum; i++) {
ph = &dli->dlpi_phdr[i];
if (ph->p_type == PT_LOAD &&
dli->dlpi_addr + ph->p_vaddr <= (uintptr_t)rd->addr &&
(uintptr_t)rd->addr < dli->dlpi_addr + ph->p_vaddr +
ph->p_memsz) {
memcpy(rd->dli, dli, sz);
return (1);
}
}
return (0);
}
#endif
#pragma weak _rtld_addr_phdr
int
_rtld_addr_phdr(const void *addr __unused,
struct dl_phdr_info *phdr_info_a __unused)
{
#ifndef IN_LIBDL
struct _rtld_addr_phdr_cb_data rd;
rd.addr = addr;
rd.dli = phdr_info_a;
return (dl_iterate_phdr(_rtld_addr_phdr_cb, &rd));
#else
return (0);
#endif
}
#pragma weak _rtld_get_stack_prot
int
_rtld_get_stack_prot(void)
{
#ifndef IN_LIBDL
unsigned i;
int r;
static int ret;
r = atomic_load_int(&ret);
if (r != 0)
return (r);
_once(&dl_phdr_info_once, dl_init_phdr_info);
r = PROT_EXEC | PROT_READ | PROT_WRITE;
for (i = 0; i < phdr_info.dlpi_phnum; i++) {
if (phdr_info.dlpi_phdr[i].p_type != PT_GNU_STACK)
continue;
r = PROT_READ | PROT_WRITE;
if ((phdr_info.dlpi_phdr[i].p_flags & PF_X) != 0)
r |= PROT_EXEC;
break;
}
atomic_store_int(&ret, r);
return (r);
#else
return (0);
#endif
}
#pragma weak _rtld_is_dlopened
int
_rtld_is_dlopened(void *arg __unused)
{
return (0);
}
#endif /* !defined(IN_LIBDL) || defined(PIC) */
diff --git a/lib/libc/gen/drand48.c b/lib/libc/gen/drand48.c
index e24b974ae84f..cec04a6a2425 100644
--- a/lib/libc/gen/drand48.c
+++ b/lib/libc/gen/drand48.c
@@ -1,23 +1,22 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include "rand48.h"
extern unsigned short _rand48_seed[3];
double
drand48(void)
{
return erand48(_rand48_seed);
}
diff --git a/lib/libc/gen/dup3.c b/lib/libc/gen/dup3.c
index e0298c821148..fca1e99fb47b 100644
--- a/lib/libc/gen/dup3.c
+++ b/lib/libc/gen/dup3.c
@@ -1,61 +1,60 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Jukka A. Ukkonen
* All rights reserved.
*
* This software was developed by Jukka Ukkonen for FreeBSD.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include "un-namespace.h"
int __dup3(int, int, int);
int
__dup3(int oldfd, int newfd, int flags)
{
int how;
if (oldfd == newfd) {
errno = EINVAL;
return (-1);
}
if (flags & ~O_CLOEXEC) {
errno = EINVAL;
return (-1);
}
how = (flags & O_CLOEXEC) ? F_DUP2FD_CLOEXEC : F_DUP2FD;
return (_fcntl(oldfd, how, newfd));
}
__weak_reference(__dup3, dup3);
__weak_reference(__dup3, _dup3);
diff --git a/lib/libc/gen/erand48.c b/lib/libc/gen/erand48.c
index fb0b1aef8cf1..286904c27839 100644
--- a/lib/libc/gen/erand48.c
+++ b/lib/libc/gen/erand48.c
@@ -1,24 +1,23 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include "rand48.h"
double
erand48(unsigned short xseed[3])
{
_dorand48(xseed);
return ldexp((double) xseed[0], -48) +
ldexp((double) xseed[1], -32) +
ldexp((double) xseed[2], -16);
}
diff --git a/lib/libc/gen/errno.c b/lib/libc/gen/errno.c
index aae8300a34b2..d35a481dff3f 100644
--- a/lib/libc/gen/errno.c
+++ b/lib/libc/gen/errno.c
@@ -1,30 +1,29 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Peter Wemm <peter@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
int errno;
diff --git a/lib/libc/gen/eventfd.c b/lib/libc/gen/eventfd.c
index e05218cf90e4..44a33915c2fb 100644
--- a/lib/libc/gen/eventfd.c
+++ b/lib/libc/gen/eventfd.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2005-2020 Rich Felker, et al.
* Copyright (c) 2020 Val Packett
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/eventfd.h>
#include <sys/specialfd.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
int eventfd(unsigned int initval, int flags)
{
struct specialfd_eventfd args;
args.initval = initval;
args.flags = flags;
return (__sys___specialfd(SPECIALFD_EVENTFD, &args, sizeof(args)));
}
int eventfd_read(int fd, eventfd_t *value)
{
return (sizeof(*value) == _read(fd, value, sizeof(*value)) ? 0 : -1);
}
int eventfd_write(int fd, eventfd_t value)
{
return (sizeof(value) == _write(fd, &value, sizeof(value)) ? 0 : -1);
}
diff --git a/lib/libc/gen/exect.c b/lib/libc/gen/exect.c
index b40c95c93fe3..e5be7a4d8755 100644
--- a/lib/libc/gen/exect.c
+++ b/lib/libc/gen/exect.c
@@ -1,43 +1,42 @@
/*-
* Copyright (c) 2018 Ali Mashtizadeh <ali@mashtizadeh.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/ptrace.h>
#include <errno.h>
#include <unistd.h>
int
exect(const char *path, char *const argv[], char *const envp[])
{
if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) {
if (errno != EBUSY)
return (-1);
}
return (execve(path, argv, envp));
}
diff --git a/lib/libc/gen/fdevname.c b/lib/libc/gen/fdevname.c
index 585724e53fc9..62e71e98af63 100644
--- a/lib/libc/gen/fdevname.c
+++ b/lib/libc/gen/fdevname.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include "un-namespace.h"
char *
fdevname_r(int fd, char *buf, int len)
{
struct fiodgname_arg fgn;
fgn.buf = buf;
fgn.len = len;
if (_ioctl(fd, FIODGNAME, &fgn) == -1)
return (NULL);
return (buf);
}
char *
fdevname(int fd)
{
static char buf[SPECNAMELEN + 1];
return (fdevname_r(fd, buf, sizeof(buf)));
}
diff --git a/lib/libc/gen/feature_present.c b/lib/libc/gen/feature_present.c
index bbf8fcc2eb47..4c0b41cfb23e 100644
--- a/lib/libc/gen/feature_present.c
+++ b/lib/libc/gen/feature_present.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2008 Yahoo!, Inc.
* All rights reserved.
* Written by: John Baldwin <jhb@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
/*
* Returns true if the named feature is present in the currently
* running kernel. A feature's presence is indicated by an integer
* sysctl node called kern.feature.<feature> that is non-zero.
*/
int
feature_present(const char *feature)
{
char *mib;
size_t len;
int i;
if (asprintf(&mib, "kern.features.%s", feature) < 0)
return (0);
len = sizeof(i);
if (sysctlbyname(mib, &i, &len, NULL, 0) < 0) {
free(mib);
return (0);
}
free(mib);
if (len != sizeof(i))
return (0);
return (i != 0);
}
diff --git a/lib/libc/gen/fmtcheck.c b/lib/libc/gen/fmtcheck.c
index 8a3ea16b88cf..de889ad3421c 100644
--- a/lib/libc/gen/fmtcheck.c
+++ b/lib/libc/gen/fmtcheck.c
@@ -1,326 +1,325 @@
/* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code was contributed to The NetBSD Foundation by Allen Briggs.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
__weak_reference(__fmtcheck, fmtcheck);
const char * __fmtcheck(const char *, const char *);
enum __e_fmtcheck_types {
FMTCHECK_START,
FMTCHECK_SHORT,
FMTCHECK_INT,
FMTCHECK_WINTT,
FMTCHECK_LONG,
FMTCHECK_QUAD,
FMTCHECK_INTMAXT,
FMTCHECK_PTRDIFFT,
FMTCHECK_SIZET,
FMTCHECK_CHARPOINTER,
FMTCHECK_SHORTPOINTER,
FMTCHECK_INTPOINTER,
FMTCHECK_LONGPOINTER,
FMTCHECK_QUADPOINTER,
FMTCHECK_INTMAXTPOINTER,
FMTCHECK_PTRDIFFTPOINTER,
FMTCHECK_SIZETPOINTER,
#ifndef NO_FLOATING_POINT
FMTCHECK_DOUBLE,
FMTCHECK_LONGDOUBLE,
#endif
FMTCHECK_STRING,
FMTCHECK_WSTRING,
FMTCHECK_WIDTH,
FMTCHECK_PRECISION,
FMTCHECK_DONE,
FMTCHECK_UNKNOWN
};
typedef enum __e_fmtcheck_types EFT;
enum e_modifier {
MOD_NONE,
MOD_CHAR,
MOD_SHORT,
MOD_LONG,
MOD_QUAD,
MOD_INTMAXT,
MOD_LONGDOUBLE,
MOD_PTRDIFFT,
MOD_SIZET,
};
#define RETURN(pf,f,r) do { \
*(pf) = (f); \
return r; \
} /*NOTREACHED*/ /*CONSTCOND*/ while (0)
static EFT
get_next_format_from_precision(const char **pf)
{
enum e_modifier modifier;
const char *f;
f = *pf;
switch (*f) {
case 'h':
f++;
if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
if (*f == 'h') {
f++;
modifier = MOD_CHAR;
} else {
modifier = MOD_SHORT;
}
break;
case 'j':
f++;
modifier = MOD_INTMAXT;
break;
case 'l':
f++;
if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
if (*f == 'l') {
f++;
modifier = MOD_QUAD;
} else {
modifier = MOD_LONG;
}
break;
case 'q':
f++;
modifier = MOD_QUAD;
break;
case 't':
f++;
modifier = MOD_PTRDIFFT;
break;
case 'z':
f++;
modifier = MOD_SIZET;
break;
case 'L':
f++;
modifier = MOD_LONGDOUBLE;
break;
default:
modifier = MOD_NONE;
break;
}
if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
if (strchr("diouxX", *f)) {
switch (modifier) {
case MOD_LONG:
RETURN(pf,f,FMTCHECK_LONG);
case MOD_QUAD:
RETURN(pf,f,FMTCHECK_QUAD);
case MOD_INTMAXT:
RETURN(pf,f,FMTCHECK_INTMAXT);
case MOD_PTRDIFFT:
RETURN(pf,f,FMTCHECK_PTRDIFFT);
case MOD_SIZET:
RETURN(pf,f,FMTCHECK_SIZET);
case MOD_CHAR:
case MOD_SHORT:
case MOD_NONE:
RETURN(pf,f,FMTCHECK_INT);
default:
RETURN(pf,f,FMTCHECK_UNKNOWN);
}
}
if (*f == 'n') {
switch (modifier) {
case MOD_CHAR:
RETURN(pf,f,FMTCHECK_CHARPOINTER);
case MOD_SHORT:
RETURN(pf,f,FMTCHECK_SHORTPOINTER);
case MOD_LONG:
RETURN(pf,f,FMTCHECK_LONGPOINTER);
case MOD_QUAD:
RETURN(pf,f,FMTCHECK_QUADPOINTER);
case MOD_INTMAXT:
RETURN(pf,f,FMTCHECK_INTMAXTPOINTER);
case MOD_PTRDIFFT:
RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER);
case MOD_SIZET:
RETURN(pf,f,FMTCHECK_SIZETPOINTER);
case MOD_NONE:
RETURN(pf,f,FMTCHECK_INTPOINTER);
default:
RETURN(pf,f,FMTCHECK_UNKNOWN);
}
}
if (strchr("DOU", *f)) {
if (modifier != MOD_NONE)
RETURN(pf,f,FMTCHECK_UNKNOWN);
RETURN(pf,f,FMTCHECK_LONG);
}
#ifndef NO_FLOATING_POINT
if (strchr("aAeEfFgG", *f)) {
switch (modifier) {
case MOD_LONGDOUBLE:
RETURN(pf,f,FMTCHECK_LONGDOUBLE);
case MOD_LONG:
case MOD_NONE:
RETURN(pf,f,FMTCHECK_DOUBLE);
default:
RETURN(pf,f,FMTCHECK_UNKNOWN);
}
}
#endif
if (*f == 'c') {
switch (modifier) {
case MOD_LONG:
RETURN(pf,f,FMTCHECK_WINTT);
case MOD_NONE:
RETURN(pf,f,FMTCHECK_INT);
default:
RETURN(pf,f,FMTCHECK_UNKNOWN);
}
}
if (*f == 'C') {
if (modifier != MOD_NONE)
RETURN(pf,f,FMTCHECK_UNKNOWN);
RETURN(pf,f,FMTCHECK_WINTT);
}
if (*f == 's') {
switch (modifier) {
case MOD_LONG:
RETURN(pf,f,FMTCHECK_WSTRING);
case MOD_NONE:
RETURN(pf,f,FMTCHECK_STRING);
default:
RETURN(pf,f,FMTCHECK_UNKNOWN);
}
}
if (*f == 'S') {
if (modifier != MOD_NONE)
RETURN(pf,f,FMTCHECK_UNKNOWN);
RETURN(pf,f,FMTCHECK_WSTRING);
}
if (*f == 'p') {
if (modifier != MOD_NONE)
RETURN(pf,f,FMTCHECK_UNKNOWN);
RETURN(pf,f,FMTCHECK_LONG);
}
RETURN(pf,f,FMTCHECK_UNKNOWN);
/*NOTREACHED*/
}
static EFT
get_next_format_from_width(const char **pf)
{
const char *f;
f = *pf;
if (*f == '.') {
f++;
if (*f == '*') {
RETURN(pf,f,FMTCHECK_PRECISION);
}
/* eat any precision (empty is allowed) */
while (isdigit(*f)) f++;
if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN);
}
RETURN(pf,f,get_next_format_from_precision(pf));
/*NOTREACHED*/
}
static EFT
get_next_format(const char **pf, EFT eft)
{
int infmt;
const char *f;
if (eft == FMTCHECK_WIDTH) {
(*pf)++;
return get_next_format_from_width(pf);
} else if (eft == FMTCHECK_PRECISION) {
(*pf)++;
return get_next_format_from_precision(pf);
}
f = *pf;
infmt = 0;
while (!infmt) {
f = strchr(f, '%');
if (f == NULL)
RETURN(pf,f,FMTCHECK_DONE);
f++;
if (!*f)
RETURN(pf,f,FMTCHECK_UNKNOWN);
if (*f != '%')
infmt = 1;
else
f++;
}
/* Eat any of the flags */
while (*f && (strchr("#'0- +", *f)))
f++;
if (*f == '*') {
RETURN(pf,f,FMTCHECK_WIDTH);
}
/* eat any width */
while (isdigit(*f)) f++;
if (!*f) {
RETURN(pf,f,FMTCHECK_UNKNOWN);
}
RETURN(pf,f,get_next_format_from_width(pf));
/*NOTREACHED*/
}
const char *
__fmtcheck(const char *f1, const char *f2)
{
const char *f1p, *f2p;
EFT f1t, f2t;
if (!f1) return f2;
f1p = f1;
f1t = FMTCHECK_START;
f2p = f2;
f2t = FMTCHECK_START;
while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) {
if (f1t == FMTCHECK_UNKNOWN)
return f2;
f2t = get_next_format(&f2p, f2t);
if (f1t != f2t)
return f2;
}
return f1;
}
diff --git a/lib/libc/gen/fmtmsg.c b/lib/libc/gen/fmtmsg.c
index 9a62c90f4d96..9edeee4405ce 100644
--- a/lib/libc/gen/fmtmsg.c
+++ b/lib/libc/gen/fmtmsg.c
@@ -1,220 +1,219 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <fmtmsg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Default value for MSGVERB. */
#define DFLT_MSGVERB "label:severity:text:action:tag"
/* Maximum valid size for a MSGVERB. */
#define MAX_MSGVERB sizeof(DFLT_MSGVERB)
static char *printfmt(char *, long, const char *, int, const char *,
const char *, const char *);
static char *nextcomp(const char *);
static const char
*sevinfo(int);
static int validmsgverb(const char *);
int
fmtmsg(long class, const char *label, int sev, const char *text,
const char *action, const char *tag)
{
FILE *fp;
char *env, *msgverb, *output;
if (class & MM_PRINT) {
if ((env = getenv("MSGVERB")) != NULL && *env != '\0' &&
strlen(env) <= strlen(DFLT_MSGVERB)) {
if ((msgverb = strdup(env)) == NULL)
return (MM_NOTOK);
else if (validmsgverb(msgverb) == 0) {
free(msgverb);
goto def;
}
} else {
def:
if ((msgverb = strdup(DFLT_MSGVERB)) == NULL)
return (MM_NOTOK);
}
output = printfmt(msgverb, class, label, sev, text, action,
tag);
if (output == NULL) {
free(msgverb);
return (MM_NOTOK);
}
if (*output != '\0')
fprintf(stderr, "%s", output);
free(msgverb);
free(output);
}
if (class & MM_CONSOLE) {
output = printfmt(DFLT_MSGVERB, class, label, sev, text,
action, tag);
if (output == NULL)
return (MM_NOCON);
if (*output != '\0') {
if ((fp = fopen("/dev/console", "ae")) == NULL) {
free(output);
return (MM_NOCON);
}
fprintf(fp, "%s", output);
fclose(fp);
}
free(output);
}
return (MM_OK);
}
#define INSERT_COLON \
if (*output != '\0') \
strlcat(output, ": ", size)
#define INSERT_NEWLINE \
if (*output != '\0') \
strlcat(output, "\n", size)
#define INSERT_SPACE \
if (*output != '\0') \
strlcat(output, " ", size)
/*
* Returns NULL on memory allocation failure, otherwise returns a pointer to
* a newly malloc()'d output buffer.
*/
static char *
printfmt(char *msgverb, long class, const char *label, int sev,
const char *text, const char *act, const char *tag)
{
size_t size;
char *comp, *output;
const char *sevname;
size = 32;
if (label != MM_NULLLBL)
size += strlen(label);
if ((sevname = sevinfo(sev)) != NULL)
size += strlen(sevname);
if (text != MM_NULLTXT)
size += strlen(text);
if (act != MM_NULLACT)
size += strlen(act);
if (tag != MM_NULLTAG)
size += strlen(tag);
if ((output = malloc(size)) == NULL)
return (NULL);
*output = '\0';
while ((comp = nextcomp(msgverb)) != NULL) {
if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) {
INSERT_COLON;
strlcat(output, label, size);
} else if (strcmp(comp, "severity") == 0 && sevname != NULL) {
INSERT_COLON;
strlcat(output, sevinfo(sev), size);
} else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) {
INSERT_COLON;
strlcat(output, text, size);
} else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) {
INSERT_NEWLINE;
strlcat(output, "TO FIX: ", size);
strlcat(output, act, size);
} else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) {
INSERT_SPACE;
strlcat(output, tag, size);
}
}
INSERT_NEWLINE;
return (output);
}
/*
* Returns a component of a colon delimited string. NULL is returned to
* indicate that there are no remaining components. This function must be
* called until it returns NULL in order for the local state to be cleared.
*/
static char *
nextcomp(const char *msgverb)
{
static char lmsgverb[MAX_MSGVERB], *state;
char *retval;
if (*lmsgverb == '\0') {
strlcpy(lmsgverb, msgverb, sizeof(lmsgverb));
retval = strtok_r(lmsgverb, ":", &state);
} else {
retval = strtok_r(NULL, ":", &state);
}
if (retval == NULL)
*lmsgverb = '\0';
return (retval);
}
static const char *
sevinfo(int sev)
{
switch (sev) {
case MM_HALT:
return ("HALT");
case MM_ERROR:
return ("ERROR");
case MM_WARNING:
return ("WARNING");
case MM_INFO:
return ("INFO");
default:
return (NULL);
}
}
/*
* Returns 1 if the msgverb list is valid, otherwise 0.
*/
static int
validmsgverb(const char *msgverb)
{
const char *validlist = "label\0severity\0text\0action\0tag\0";
char *msgcomp;
size_t len1, len2;
const char *p;
int equality;
equality = 0;
while ((msgcomp = nextcomp(msgverb)) != NULL) {
equality--;
len1 = strlen(msgcomp);
for (p = validlist; (len2 = strlen(p)) != 0; p += len2 + 1) {
if (len1 == len2 && memcmp(msgcomp, p, len1) == 0)
equality++;
}
}
return (!equality);
}
diff --git a/lib/libc/gen/ftok.c b/lib/libc/gen/ftok.c
index 1465fe5c7e47..04fa5d464fb0 100644
--- a/lib/libc/gen/ftok.c
+++ b/lib/libc/gen/ftok.c
@@ -1,45 +1,44 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ipc.h>
key_t
ftok(const char *path, int id)
{
struct stat st;
if (stat(path, &st) < 0)
return (key_t)-1;
return ((key_t)((unsigned int)id << 24 | (st.st_dev & 0xff) << 16 |
(st.st_ino & 0xffff)));
}
diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c
index e692e1f9e271..d56a0c85d0fd 100644
--- a/lib/libc/gen/fts-compat.c
+++ b/lib/libc/gen/fts-compat.c
@@ -1,1238 +1,1237 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)fts.c 8.6 (Berkeley) 8/14/94
* From: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#define _WANT_FREEBSD11_STATFS
#include <sys/mount.h>
#define _WANT_FREEBSD11_STAT
#include <sys/stat.h>
#define _WANT_FREEBSD11_DIRENT
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "gen-compat.h"
#include "fts-compat.h"
#include "un-namespace.h"
#include "gen-private.h"
FTSENT *__fts_children_44bsd(FTS *, int);
int __fts_close_44bsd(FTS *);
void *__fts_get_clientptr_44bsd(FTS *);
FTS *__fts_get_stream_44bsd(FTSENT *);
FTS *__fts_open_44bsd(char * const *, int,
int (*)(const FTSENT * const *, const FTSENT * const *));
FTSENT *__fts_read_44bsd(FTS *);
int __fts_set_44bsd(FTS *, FTSENT *, int);
void __fts_set_clientptr_44bsd(FTS *, void *);
static FTSENT *fts_alloc(FTS *, char *, int);
static FTSENT *fts_build(FTS *, int);
static void fts_lfree(FTSENT *);
static void fts_load(FTS *, FTSENT *);
static size_t fts_maxarglen(char * const *);
static void fts_padjust(FTS *, FTSENT *);
static int fts_palloc(FTS *, size_t);
static FTSENT *fts_sort(FTS *, FTSENT *, int);
static u_short fts_stat(FTS *, FTSENT *, int);
static int fts_safe_changedir(FTS *, FTSENT *, int, char *);
static int fts_ufslinks(FTS *, const FTSENT *);
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
#define CLR(opt) (sp->fts_options &= ~(opt))
#define ISSET(opt) (sp->fts_options & (opt))
#define SET(opt) (sp->fts_options |= (opt))
#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
/* fts_build flags */
#define BCHILD 1 /* fts_children */
#define BNAMES 2 /* fts_children, names only */
#define BREAD 3 /* fts_read */
/*
* Internal representation of an FTS, including extra implementation
* details. The FTS returned from fts_open points to this structure's
* ftsp_fts member (and can be cast to an _fts_private as required)
*/
struct _fts_private {
FTS ftsp_fts;
struct freebsd11_statfs ftsp_statfs;
uint32_t ftsp_dev;
int ftsp_linksreliable;
};
/*
* The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
* knows that a directory could not possibly have subdirectories. This
* is decided by looking at the link count: a subdirectory would
* increment its parent's link count by virtue of its own ".." entry.
* This assumption only holds for UFS-like filesystems that implement
* links and directories this way, so we must punt for others.
*/
static const char *ufslike_filesystems[] = {
"ufs",
"zfs",
"nfs",
"ext2fs",
0
};
FTS *
__fts_open_44bsd(char * const *argv, int options,
int (*compar)(const FTSENT * const *, const FTSENT * const *))
{
struct _fts_private *priv;
FTS *sp;
FTSENT *p, *root;
int nitems;
FTSENT *parent, *tmp;
int len;
/* Options check. */
if (options & ~FTS_OPTIONMASK) {
errno = EINVAL;
return (NULL);
}
/* Allocate/initialize the stream. */
if ((priv = calloc(1, sizeof(*priv))) == NULL)
return (NULL);
sp = &priv->ftsp_fts;
sp->fts_compar = compar;
sp->fts_options = options;
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
if (ISSET(FTS_LOGICAL))
SET(FTS_NOCHDIR);
/*
* Start out with 1K of path space, and enough, in any case,
* to hold the user's paths.
*/
if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
goto mem1;
/* Allocate/initialize root's parent. */
if ((parent = fts_alloc(sp, "", 0)) == NULL)
goto mem2;
parent->fts_level = FTS_ROOTPARENTLEVEL;
/* Shush, GCC. */
tmp = NULL;
/* Allocate/initialize root(s). */
for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
/* Don't allow zero-length paths. */
if ((len = strlen(*argv)) == 0) {
errno = ENOENT;
goto mem3;
}
p = fts_alloc(sp, *argv, len);
p->fts_level = FTS_ROOTLEVEL;
p->fts_parent = parent;
p->fts_accpath = p->fts_name;
p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW));
/* Command-line "." and ".." are real directories. */
if (p->fts_info == FTS_DOT)
p->fts_info = FTS_D;
/*
* If comparison routine supplied, traverse in sorted
* order; otherwise traverse in the order specified.
*/
if (compar) {
p->fts_link = root;
root = p;
} else {
p->fts_link = NULL;
if (root == NULL)
tmp = root = p;
else {
tmp->fts_link = p;
tmp = p;
}
}
}
if (compar && nitems > 1)
root = fts_sort(sp, root, nitems);
/*
* Allocate a dummy pointer and make fts_read think that we've just
* finished the node before the root(s); set p->fts_info to FTS_INIT
* so that everything about the "current" node is ignored.
*/
if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
goto mem3;
sp->fts_cur->fts_link = root;
sp->fts_cur->fts_info = FTS_INIT;
/*
* If using chdir(2), grab a file descriptor pointing to dot to ensure
* that we can get back here; this could be avoided for some paths,
* but almost certainly not worth the effort. Slashes, symbolic links,
* and ".." are all fairly nasty problems. Note, if we can't get the
* descriptor we run anyway, just more slowly.
*/
if (!ISSET(FTS_NOCHDIR) &&
(sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
SET(FTS_NOCHDIR);
return (sp);
mem3: fts_lfree(root);
free(parent);
mem2: free(sp->fts_path);
mem1: free(sp);
return (NULL);
}
static void
fts_load(FTS *sp, FTSENT *p)
{
int len;
char *cp;
/*
* Load the stream structure for the next traversal. Since we don't
* actually enter the directory until after the preorder visit, set
* the fts_accpath field specially so the chdir gets done to the right
* place and the user can access the first node. From fts_open it's
* known that the path will fit.
*/
len = p->fts_pathlen = p->fts_namelen;
memmove(sp->fts_path, p->fts_name, len + 1);
if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
len = strlen(++cp);
memmove(p->fts_name, cp, len + 1);
p->fts_namelen = len;
}
p->fts_accpath = p->fts_path = sp->fts_path;
sp->fts_dev = p->fts_dev;
}
int
__fts_close_44bsd(FTS *sp)
{
FTSENT *freep, *p;
int saved_errno;
/*
* This still works if we haven't read anything -- the dummy structure
* points to the root list, so we step through to the end of the root
* list which has a valid parent pointer.
*/
if (sp->fts_cur) {
for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
freep = p;
p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
free(freep);
}
free(p);
}
/* Free up child linked list, sort array, path buffer. */
if (sp->fts_child)
fts_lfree(sp->fts_child);
if (sp->fts_array)
free(sp->fts_array);
free(sp->fts_path);
/* Return to original directory, save errno if necessary. */
if (!ISSET(FTS_NOCHDIR)) {
saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
(void)_close(sp->fts_rfd);
/* Set errno and return. */
if (saved_errno != 0) {
/* Free up the stream pointer. */
free(sp);
errno = saved_errno;
return (-1);
}
}
/* Free up the stream pointer. */
free(sp);
return (0);
}
/*
* Special case of "/" at the end of the path so that slashes aren't
* appended which would cause paths to be written as "....//foo".
*/
#define NAPPEND(p) \
(p->fts_path[p->fts_pathlen - 1] == '/' \
? p->fts_pathlen - 1 : p->fts_pathlen)
FTSENT *
__fts_read_44bsd(FTS *sp)
{
FTSENT *p, *tmp;
int instr;
char *t;
int saved_errno;
/* If finished or unrecoverable error, return NULL. */
if (sp->fts_cur == NULL || ISSET(FTS_STOP))
return (NULL);
/* Set current node pointer. */
p = sp->fts_cur;
/* Save and zero out user instructions. */
instr = p->fts_instr;
p->fts_instr = FTS_NOINSTR;
/* Any type of file may be re-visited; re-stat and re-turn. */
if (instr == FTS_AGAIN) {
p->fts_info = fts_stat(sp, p, 0);
return (p);
}
/*
* Following a symlink -- SLNONE test allows application to see
* SLNONE and recover. If indirecting through a symlink, have
* keep a pointer to current location. If unable to get that
* pointer, follow fails.
*/
if (instr == FTS_FOLLOW &&
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
p->fts_info = fts_stat(sp, p, 1);
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC,
0)) < 0) {
p->fts_errno = errno;
p->fts_info = FTS_ERR;
} else
p->fts_flags |= FTS_SYMFOLLOW;
}
return (p);
}
/* Directory in pre-order. */
if (p->fts_info == FTS_D) {
/* If skipped or crossed mount point, do post-order visit. */
if (instr == FTS_SKIP ||
(ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
if (p->fts_flags & FTS_SYMFOLLOW)
(void)_close(p->fts_symfd);
if (sp->fts_child) {
fts_lfree(sp->fts_child);
sp->fts_child = NULL;
}
p->fts_info = FTS_DP;
return (p);
}
/* Rebuild if only read the names and now traversing. */
if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
CLR(FTS_NAMEONLY);
fts_lfree(sp->fts_child);
sp->fts_child = NULL;
}
/*
* Cd to the subdirectory.
*
* If have already read and now fail to chdir, whack the list
* to make the names come out right, and set the parent errno
* so the application will eventually get an error condition.
* Set the FTS_DONTCHDIR flag so that when we logically change
* directories back to the parent we don't do a chdir.
*
* If haven't read do so. If the read fails, fts_build sets
* FTS_STOP or the fts_info field of the node.
*/
if (sp->fts_child != NULL) {
if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
p->fts_errno = errno;
p->fts_flags |= FTS_DONTCHDIR;
for (p = sp->fts_child; p != NULL;
p = p->fts_link)
p->fts_accpath =
p->fts_parent->fts_accpath;
}
} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
if (ISSET(FTS_STOP))
return (NULL);
return (p);
}
p = sp->fts_child;
sp->fts_child = NULL;
goto name;
}
/* Move to the next node on this level. */
next: tmp = p;
if ((p = p->fts_link) != NULL) {
free(tmp);
/*
* If reached the top, return to the original directory (or
* the root of the tree), and load the paths for the next root.
*/
if (p->fts_level == FTS_ROOTLEVEL) {
if (FCHDIR(sp, sp->fts_rfd)) {
SET(FTS_STOP);
return (NULL);
}
fts_load(sp, p);
return (sp->fts_cur = p);
}
/*
* User may have called fts_set on the node. If skipped,
* ignore. If followed, get a file descriptor so we can
* get back if necessary.
*/
if (p->fts_instr == FTS_SKIP)
goto next;
if (p->fts_instr == FTS_FOLLOW) {
p->fts_info = fts_stat(sp, p, 1);
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
if ((p->fts_symfd =
_open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
p->fts_errno = errno;
p->fts_info = FTS_ERR;
} else
p->fts_flags |= FTS_SYMFOLLOW;
}
p->fts_instr = FTS_NOINSTR;
}
name: t = sp->fts_path + NAPPEND(p->fts_parent);
*t++ = '/';
memmove(t, p->fts_name, p->fts_namelen + 1);
return (sp->fts_cur = p);
}
/* Move up to the parent node. */
p = tmp->fts_parent;
free(tmp);
if (p->fts_level == FTS_ROOTPARENTLEVEL) {
/*
* Done; free everything up and set errno to 0 so the user
* can distinguish between error and EOF.
*/
free(p);
errno = 0;
return (sp->fts_cur = NULL);
}
/* NUL terminate the pathname. */
sp->fts_path[p->fts_pathlen] = '\0';
/*
* Return to the parent directory. If at a root node or came through
* a symlink, go back through the file descriptor. Otherwise, cd up
* one directory.
*/
if (p->fts_level == FTS_ROOTLEVEL) {
if (FCHDIR(sp, sp->fts_rfd)) {
SET(FTS_STOP);
return (NULL);
}
} else if (p->fts_flags & FTS_SYMFOLLOW) {
if (FCHDIR(sp, p->fts_symfd)) {
saved_errno = errno;
(void)_close(p->fts_symfd);
errno = saved_errno;
SET(FTS_STOP);
return (NULL);
}
(void)_close(p->fts_symfd);
} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
SET(FTS_STOP);
return (NULL);
}
p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
return (sp->fts_cur = p);
}
/*
* Fts_set takes the stream as an argument although it's not used in this
* implementation; it would be necessary if anyone wanted to add global
* semantics to fts using fts_set. An error return is allowed for similar
* reasons.
*/
/* ARGSUSED */
int
__fts_set_44bsd(FTS *sp, FTSENT *p, int instr)
{
if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
instr != FTS_NOINSTR && instr != FTS_SKIP) {
errno = EINVAL;
return (1);
}
p->fts_instr = instr;
return (0);
}
FTSENT *
__fts_children_44bsd(FTS *sp, int instr)
{
FTSENT *p;
int fd;
if (instr != 0 && instr != FTS_NAMEONLY) {
errno = EINVAL;
return (NULL);
}
/* Set current node pointer. */
p = sp->fts_cur;
/*
* Errno set to 0 so user can distinguish empty directory from
* an error.
*/
errno = 0;
/* Fatal errors stop here. */
if (ISSET(FTS_STOP))
return (NULL);
/* Return logical hierarchy of user's arguments. */
if (p->fts_info == FTS_INIT)
return (p->fts_link);
/*
* If not a directory being visited in pre-order, stop here. Could
* allow FTS_DNR, assuming the user has fixed the problem, but the
* same effect is available with FTS_AGAIN.
*/
if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
return (NULL);
/* Free up any previous child list. */
if (sp->fts_child != NULL)
fts_lfree(sp->fts_child);
if (instr == FTS_NAMEONLY) {
SET(FTS_NAMEONLY);
instr = BNAMES;
} else
instr = BCHILD;
/*
* If using chdir on a relative path and called BEFORE fts_read does
* its chdir to the root of a traversal, we can lose -- we need to
* chdir into the subdirectory, and we don't know where the current
* directory is, so we can't get back so that the upcoming chdir by
* fts_read will work.
*/
if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
ISSET(FTS_NOCHDIR))
return (sp->fts_child = fts_build(sp, instr));
if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
return (NULL);
sp->fts_child = fts_build(sp, instr);
if (fchdir(fd)) {
(void)_close(fd);
return (NULL);
}
(void)_close(fd);
return (sp->fts_child);
}
#ifndef fts_get_clientptr
#error "fts_get_clientptr not defined"
#endif
void *
(__fts_get_clientptr_44bsd)(FTS *sp)
{
return (fts_get_clientptr(sp));
}
#ifndef fts_get_stream
#error "fts_get_stream not defined"
#endif
FTS *
(__fts_get_stream_44bsd)(FTSENT *p)
{
return (fts_get_stream(p));
}
void
__fts_set_clientptr_44bsd(FTS *sp, void *clientptr)
{
sp->fts_clientptr = clientptr;
}
static struct freebsd11_dirent *
fts_safe_readdir(DIR *dirp, int *readdir_errno)
{
struct freebsd11_dirent *ret;
errno = 0;
if (!dirp)
return (NULL);
ret = freebsd11_readdir(dirp);
*readdir_errno = errno;
return (ret);
}
/*
* This is the tricky part -- do not casually change *anything* in here. The
* idea is to build the linked list of entries that are used by fts_children
* and fts_read. There are lots of special cases.
*
* The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
* set and it's a physical walk (so that symbolic links can't be directories),
* we can do things quickly. First, if it's a 4.4BSD file system, the type
* of the file is in the directory entry. Otherwise, we assume that the number
* of subdirectories in a node is equal to the number of links to the parent.
* The former skips all stat calls. The latter skips stat calls in any leaf
* directories and for any files after the subdirectories in the directory have
* been found, cutting the stat calls by about 2/3.
*/
static FTSENT *
fts_build(FTS *sp, int type)
{
struct freebsd11_dirent *dp;
FTSENT *p, *head;
int nitems;
FTSENT *cur, *tail;
DIR *dirp;
void *oldaddr;
int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno,
nostat, doadjust, dnamlen, readdir_errno;
char *cp;
/* Set current node pointer. */
cur = sp->fts_cur;
/*
* Open the directory for reading. If this fails, we're done.
* If being called from fts_read, set the fts_info field.
*/
#ifdef FTS_WHITEOUT
if (ISSET(FTS_WHITEOUT))
oflag = DTF_NODUP;
else
oflag = DTF_HIDEW | DTF_NODUP;
#else
#define __opendir2(path, flag) opendir(path)
#endif
if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
if (type == BREAD) {
cur->fts_info = FTS_DNR;
cur->fts_errno = errno;
}
return (NULL);
}
/*
* Nlinks is the number of possible entries of type directory in the
* directory if we're cheating on stat calls, 0 if we're not doing
* any stat calls at all, -1 if we're doing stats on everything.
*/
if (type == BNAMES) {
nlinks = 0;
/* Be quiet about nostat, GCC. */
nostat = 0;
} else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
if (fts_ufslinks(sp, cur))
nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
else
nlinks = -1;
nostat = 1;
} else {
nlinks = -1;
nostat = 0;
}
#ifdef notdef
(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
#endif
/*
* If we're going to need to stat anything or we want to descend
* and stay in the directory, chdir. If this fails we keep going,
* but set a flag so we don't chdir after the post-order visit.
* We won't be able to stat anything, but we can still return the
* names themselves. Note, that since fts_read won't be able to
* chdir into the directory, it will have to return different path
* names than before, i.e. "a/b" instead of "b". Since the node
* has already been visited in pre-order, have to wait until the
* post-order visit to return the error. There is a special case
* here, if there was nothing to stat then it's not an error to
* not be able to stat. This is all fairly nasty. If a program
* needed sorted entries or stat information, they had better be
* checking FTS_NS on the returned nodes.
*/
cderrno = 0;
if (nlinks || type == BREAD) {
if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) {
if (nlinks && type == BREAD)
cur->fts_errno = errno;
cur->fts_flags |= FTS_DONTCHDIR;
descend = 0;
cderrno = errno;
} else
descend = 1;
} else
descend = 0;
/*
* Figure out the max file name length that can be stored in the
* current path -- the inner loop allocates more path as necessary.
* We really wouldn't have to do the maxlen calculations here, we
* could do them in fts_read before returning the path, but it's a
* lot easier here since the length is part of the dirent structure.
*
* If not changing directories set a pointer so that can just append
* each new name into the path.
*/
len = NAPPEND(cur);
if (ISSET(FTS_NOCHDIR)) {
cp = sp->fts_path + len;
*cp++ = '/';
} else {
/* GCC, you're too verbose. */
cp = NULL;
}
len++;
maxlen = sp->fts_pathlen - len;
level = cur->fts_level + 1;
/* Read the directory, attaching each entry to the `link' pointer. */
doadjust = 0;
readdir_errno = 0;
for (head = tail = NULL, nitems = 0;
(dp = fts_safe_readdir(dirp, &readdir_errno));) {
dnamlen = dp->d_namlen;
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
continue;
if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL)
goto mem1;
if (dnamlen >= maxlen) { /* include space for NUL */
oldaddr = sp->fts_path;
if (fts_palloc(sp, dnamlen + len + 1)) {
/*
* No more memory for path or structures. Save
* errno, free up the current structure and the
* structures already allocated.
*/
mem1: saved_errno = errno;
if (p)
free(p);
fts_lfree(head);
(void)closedir(dirp);
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
errno = saved_errno;
return (NULL);
}
/* Did realloc() change the pointer? */
if (oldaddr != sp->fts_path) {
doadjust = 1;
if (ISSET(FTS_NOCHDIR))
cp = sp->fts_path + len;
}
maxlen = sp->fts_pathlen - len;
}
if (len + dnamlen >= USHRT_MAX) {
/*
* In an FTSENT, fts_pathlen is a u_short so it is
* possible to wraparound here. If we do, free up
* the current structure and the structures already
* allocated, then error out with ENAMETOOLONG.
*/
free(p);
fts_lfree(head);
(void)closedir(dirp);
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
errno = ENAMETOOLONG;
return (NULL);
}
p->fts_level = level;
p->fts_parent = sp->fts_cur;
p->fts_pathlen = len + dnamlen;
#ifdef FTS_WHITEOUT
if (dp->d_type == DT_WHT)
p->fts_flags |= FTS_ISW;
#endif
if (cderrno) {
if (nlinks) {
p->fts_info = FTS_NS;
p->fts_errno = cderrno;
} else
p->fts_info = FTS_NSOK;
p->fts_accpath = cur->fts_accpath;
} else if (nlinks == 0
#ifdef DT_DIR
|| (nostat &&
dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
#endif
) {
p->fts_accpath =
ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
p->fts_info = FTS_NSOK;
} else {
/* Build a file name for fts_stat to stat. */
if (ISSET(FTS_NOCHDIR)) {
p->fts_accpath = p->fts_path;
memmove(cp, p->fts_name, p->fts_namelen + 1);
} else
p->fts_accpath = p->fts_name;
/* Stat it. */
p->fts_info = fts_stat(sp, p, 0);
/* Decrement link count if applicable. */
if (nlinks > 0 && (p->fts_info == FTS_D ||
p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
--nlinks;
}
/* We walk in directory order so "ls -f" doesn't get upset. */
p->fts_link = NULL;
if (head == NULL)
head = tail = p;
else {
tail->fts_link = p;
tail = p;
}
++nitems;
}
if (readdir_errno) {
cur->fts_errno = readdir_errno;
/*
* If we've not read any items yet, treat
* the error as if we can't access the dir.
*/
cur->fts_info = nitems ? FTS_ERR : FTS_DNR;
}
if (dirp)
(void)closedir(dirp);
/*
* If realloc() changed the address of the path, adjust the
* addresses for the rest of the tree and the dir list.
*/
if (doadjust)
fts_padjust(sp, head);
/*
* If not changing directories, reset the path back to original
* state.
*/
if (ISSET(FTS_NOCHDIR)) {
if (len == sp->fts_pathlen || nitems == 0)
--cp;
*cp = '\0';
}
/*
* If descended after called from fts_children or after called from
* fts_read and nothing found, get back. At the root level we use
* the saved fd; if one of fts_open()'s arguments is a relative path
* to an empty directory, we wind up here with no other way back. If
* can't get back, we're done.
*/
if (descend && (type == BCHILD || !nitems) &&
(cur->fts_level == FTS_ROOTLEVEL ?
FCHDIR(sp, sp->fts_rfd) :
fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
return (NULL);
}
/* If didn't find anything, return NULL. */
if (!nitems) {
if (type == BREAD &&
cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR)
cur->fts_info = FTS_DP;
return (NULL);
}
/* Sort the entries. */
if (sp->fts_compar && nitems > 1)
head = fts_sort(sp, head, nitems);
return (head);
}
static u_short
fts_stat(FTS *sp, FTSENT *p, int follow)
{
FTSENT *t;
uint32_t dev;
uint32_t ino;
struct freebsd11_stat *sbp, sb;
int saved_errno;
/* If user needs stat info, stat buffer already allocated. */
sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
#ifdef FTS_WHITEOUT
/* Check for whiteout. */
if (p->fts_flags & FTS_ISW) {
if (sbp != &sb) {
memset(sbp, '\0', sizeof(*sbp));
sbp->st_mode = S_IFWHT;
}
return (FTS_W);
}
#endif
/*
* If doing a logical walk, or application requested FTS_FOLLOW, do
* a stat(2). If that fails, check for a non-existent symlink. If
* fail, set the errno from the stat call.
*/
if (ISSET(FTS_LOGICAL) || follow) {
if (freebsd11_stat(p->fts_accpath, sbp)) {
saved_errno = errno;
if (!freebsd11_lstat(p->fts_accpath, sbp)) {
errno = 0;
return (FTS_SLNONE);
}
p->fts_errno = saved_errno;
goto err;
}
} else if (freebsd11_lstat(p->fts_accpath, sbp)) {
p->fts_errno = errno;
err: memset(sbp, 0, sizeof(*sbp));
return (FTS_NS);
}
if (S_ISDIR(sbp->st_mode)) {
/*
* Set the device/inode. Used to find cycles and check for
* crossing mount points. Also remember the link count, used
* in fts_build to limit the number of stat calls. It is
* understood that these fields are only referenced if fts_info
* is set to FTS_D.
*/
dev = p->fts_dev = sbp->st_dev;
ino = p->fts_ino = sbp->st_ino;
p->fts_nlink = sbp->st_nlink;
if (ISDOT(p->fts_name))
return (FTS_DOT);
/*
* Cycle detection is done by brute force when the directory
* is first encountered. If the tree gets deep enough or the
* number of symbolic links to directories is high enough,
* something faster might be worthwhile.
*/
for (t = p->fts_parent;
t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
if (ino == t->fts_ino && dev == t->fts_dev) {
p->fts_cycle = t;
return (FTS_DC);
}
return (FTS_D);
}
if (S_ISLNK(sbp->st_mode))
return (FTS_SL);
if (S_ISREG(sbp->st_mode))
return (FTS_F);
return (FTS_DEFAULT);
}
/*
* The comparison function takes pointers to pointers to FTSENT structures.
* Qsort wants a comparison function that takes pointers to void.
* (Both with appropriate levels of const-poisoning, of course!)
* Use a trampoline function to deal with the difference.
*/
static int
fts_compar(const void *a, const void *b)
{
FTS *parent;
parent = (*(const FTSENT * const *)a)->fts_fts;
return (*parent->fts_compar)(a, b);
}
static FTSENT *
fts_sort(FTS *sp, FTSENT *head, int nitems)
{
FTSENT **ap, *p;
/*
* Construct an array of pointers to the structures and call qsort(3).
* Reassemble the array in the order returned by qsort. If unable to
* sort for memory reasons, return the directory entries in their
* current order. Allocate enough space for the current needs plus
* 40 so don't realloc one entry at a time.
*/
if (nitems > sp->fts_nitems) {
sp->fts_nitems = nitems + 40;
if ((sp->fts_array = reallocf(sp->fts_array,
sp->fts_nitems * sizeof(FTSENT *))) == NULL) {
sp->fts_nitems = 0;
return (head);
}
}
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
*ap++ = p;
qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar);
for (head = *(ap = sp->fts_array); --nitems; ++ap)
ap[0]->fts_link = ap[1];
ap[0]->fts_link = NULL;
return (head);
}
static FTSENT *
fts_alloc(FTS *sp, char *name, int namelen)
{
FTSENT *p;
size_t len;
struct ftsent_withstat {
FTSENT ent;
struct freebsd11_stat statbuf;
};
/*
* The file name is a variable length array and no stat structure is
* necessary if the user has set the nostat bit. Allocate the FTSENT
* structure, the file name and the stat structure in one chunk, but
* be careful that the stat structure is reasonably aligned.
*/
if (ISSET(FTS_NOSTAT))
len = sizeof(FTSENT) + namelen + 1;
else
len = sizeof(struct ftsent_withstat) + namelen + 1;
if ((p = malloc(len)) == NULL)
return (NULL);
if (ISSET(FTS_NOSTAT)) {
p->fts_name = (char *)(p + 1);
p->fts_statp = NULL;
} else {
p->fts_name = (char *)((struct ftsent_withstat *)p + 1);
p->fts_statp = &((struct ftsent_withstat *)p)->statbuf;
}
/* Copy the name and guarantee NUL termination. */
memcpy(p->fts_name, name, namelen);
p->fts_name[namelen] = '\0';
p->fts_namelen = namelen;
p->fts_path = sp->fts_path;
p->fts_errno = 0;
p->fts_flags = 0;
p->fts_instr = FTS_NOINSTR;
p->fts_number = 0;
p->fts_pointer = NULL;
p->fts_fts = sp;
return (p);
}
static void
fts_lfree(FTSENT *head)
{
FTSENT *p;
/* Free a linked list of structures. */
while ((p = head)) {
head = head->fts_link;
free(p);
}
}
/*
* Allow essentially unlimited paths; find, rm, ls should all work on any tree.
* Most systems will allow creation of paths much longer than MAXPATHLEN, even
* though the kernel won't resolve them. Add the size (not just what's needed)
* plus 256 bytes so don't realloc the path 2 bytes at a time.
*/
static int
fts_palloc(FTS *sp, size_t more)
{
sp->fts_pathlen += more + 256;
/*
* Check for possible wraparound. In an FTS, fts_pathlen is
* a signed int but in an FTSENT it is an unsigned short.
* We limit fts_pathlen to USHRT_MAX to be safe in both cases.
*/
if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) {
if (sp->fts_path)
free(sp->fts_path);
sp->fts_path = NULL;
errno = ENAMETOOLONG;
return (1);
}
sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
return (sp->fts_path == NULL);
}
/*
* When the path is realloc'd, have to fix all of the pointers in structures
* already returned.
*/
static void
fts_padjust(FTS *sp, FTSENT *head)
{
FTSENT *p;
char *addr = sp->fts_path;
#define ADJUST(p) do { \
if ((p)->fts_accpath != (p)->fts_name) { \
(p)->fts_accpath = \
(char *)addr + ((p)->fts_accpath - (p)->fts_path); \
} \
(p)->fts_path = addr; \
} while (0)
/* Adjust the current set of children. */
for (p = sp->fts_child; p; p = p->fts_link)
ADJUST(p);
/* Adjust the rest of the tree, including the current level. */
for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
ADJUST(p);
p = p->fts_link ? p->fts_link : p->fts_parent;
}
}
static size_t
fts_maxarglen(char * const *argv)
{
size_t len, max;
for (max = 0; *argv; ++argv)
if ((len = strlen(*argv)) > max)
max = len;
return (max + 1);
}
/*
* Change to dir specified by fd or p->fts_accpath without getting
* tricked by someone changing the world out from underneath us.
* Assumes p->fts_dev and p->fts_ino are filled in.
*/
static int
fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path)
{
int ret, oerrno, newfd;
struct freebsd11_stat sb;
newfd = fd;
if (ISSET(FTS_NOCHDIR))
return (0);
if (fd < 0 && (newfd = _open(path, O_RDONLY | O_CLOEXEC, 0)) < 0)
return (-1);
if (freebsd11_fstat(newfd, &sb)) {
ret = -1;
goto bail;
}
if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
errno = ENOENT; /* disinformation */
ret = -1;
goto bail;
}
ret = fchdir(newfd);
bail:
oerrno = errno;
if (fd < 0)
(void)_close(newfd);
errno = oerrno;
return (ret);
}
/*
* Check if the filesystem for "ent" has UFS-style links.
*/
static int
fts_ufslinks(FTS *sp, const FTSENT *ent)
{
struct _fts_private *priv;
const char **cpp;
priv = (struct _fts_private *)sp;
/*
* If this node's device is different from the previous, grab
* the filesystem information, and decide on the reliability
* of the link information from this filesystem for stat(2)
* avoidance.
*/
if (priv->ftsp_dev != ent->fts_dev) {
if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
priv->ftsp_dev = ent->fts_dev;
priv->ftsp_linksreliable = 0;
for (cpp = ufslike_filesystems; *cpp; cpp++) {
if (strcmp(priv->ftsp_statfs.f_fstypename,
*cpp) == 0) {
priv->ftsp_linksreliable = 1;
break;
}
}
} else {
priv->ftsp_linksreliable = 0;
}
}
return (priv->ftsp_linksreliable);
}
__sym_compat(fts_open, __fts_open_44bsd, FBSD_1.0);
__sym_compat(fts_close, __fts_close_44bsd, FBSD_1.0);
__sym_compat(fts_read, __fts_read_44bsd, FBSD_1.0);
__sym_compat(fts_set, __fts_set_44bsd, FBSD_1.0);
__sym_compat(fts_children, __fts_children_44bsd, FBSD_1.0);
__sym_compat(fts_get_clientptr, __fts_get_clientptr_44bsd, FBSD_1.0);
__sym_compat(fts_get_stream, __fts_get_stream_44bsd, FBSD_1.0);
__sym_compat(fts_set_clientptr, __fts_set_clientptr_44bsd, FBSD_1.0);
diff --git a/lib/libc/gen/fts-compat11.c b/lib/libc/gen/fts-compat11.c
index 2739e10a77de..d71388d0a043 100644
--- a/lib/libc/gen/fts-compat11.c
+++ b/lib/libc/gen/fts-compat11.c
@@ -1,1218 +1,1217 @@
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)fts.c 8.6 (Berkeley) 8/14/94
* From: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#define _WANT_FREEBSD11_STATFS
#include <sys/mount.h>
#define _WANT_FREEBSD11_STAT
#include <sys/stat.h>
#define _WANT_FREEBSD11_DIRENT
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fts.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "gen-compat.h"
#include "fts-compat11.h"
#include "un-namespace.h"
#include "gen-private.h"
static FTSENT11 *fts_alloc(FTS11 *, char *, size_t);
static FTSENT11 *fts_build(FTS11 *, int);
static void fts_lfree(FTSENT11 *);
static void fts_load(FTS11 *, FTSENT11 *);
static size_t fts_maxarglen(char * const *);
static void fts_padjust(FTS11 *, FTSENT11 *);
static int fts_palloc(FTS11 *, size_t);
static FTSENT11 *fts_sort(FTS11 *, FTSENT11 *, size_t);
static int fts_stat(FTS11 *, FTSENT11 *, int, int);
static int fts_safe_changedir(FTS11 *, FTSENT11 *, int, char *);
static int fts_ufslinks(FTS11 *, const FTSENT11 *);
#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2])))
#define CLR(opt) (sp->fts_options &= ~(opt))
#define ISSET(opt) (sp->fts_options & (opt))
#define SET(opt) (sp->fts_options |= (opt))
#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd))
/* fts_build flags */
#define BCHILD 1 /* fts_children */
#define BNAMES 2 /* fts_children, names only */
#define BREAD 3 /* fts_read */
/*
* Internal representation of an FTS, including extra implementation
* details. The FTS returned from fts_open points to this structure's
* ftsp_fts member (and can be cast to an _fts_private as required)
*/
struct _fts_private11 {
FTS11 ftsp_fts;
struct freebsd11_statfs ftsp_statfs;
uint32_t ftsp_dev;
int ftsp_linksreliable;
};
/*
* The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it
* knows that a directory could not possibly have subdirectories. This
* is decided by looking at the link count: a subdirectory would
* increment its parent's link count by virtue of its own ".." entry.
* This assumption only holds for UFS-like filesystems that implement
* links and directories this way, so we must punt for others.
*/
static const char *ufslike_filesystems[] = {
"ufs",
"zfs",
"nfs",
"ext2fs",
0
};
FTS11 *
freebsd11_fts_open(char * const *argv, int options,
int (*compar)(const FTSENT11 * const *, const FTSENT11 * const *))
{
struct _fts_private11 *priv;
FTS11 *sp;
FTSENT11 *p, *root;
FTSENT11 *parent, *tmp;
size_t len, nitems;
/* Options check. */
if (options & ~FTS_OPTIONMASK) {
errno = EINVAL;
return (NULL);
}
/* fts_open() requires at least one path */
if (*argv == NULL) {
errno = EINVAL;
return (NULL);
}
/* Allocate/initialize the stream. */
if ((priv = calloc(1, sizeof(*priv))) == NULL)
return (NULL);
sp = &priv->ftsp_fts;
sp->fts_compar = compar;
sp->fts_options = options;
/* Logical walks turn on NOCHDIR; symbolic links are too hard. */
if (ISSET(FTS_LOGICAL))
SET(FTS_NOCHDIR);
/*
* Start out with 1K of path space, and enough, in any case,
* to hold the user's paths.
*/
if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
goto mem1;
/* Allocate/initialize root's parent. */
if ((parent = fts_alloc(sp, "", 0)) == NULL)
goto mem2;
parent->fts_level = FTS_ROOTPARENTLEVEL;
/* Shush, GCC. */
tmp = NULL;
/* Allocate/initialize root(s). */
for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) {
len = strlen(*argv);
p = fts_alloc(sp, *argv, len);
p->fts_level = FTS_ROOTLEVEL;
p->fts_parent = parent;
p->fts_accpath = p->fts_name;
p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1);
/* Command-line "." and ".." are real directories. */
if (p->fts_info == FTS_DOT)
p->fts_info = FTS_D;
/*
* If comparison routine supplied, traverse in sorted
* order; otherwise traverse in the order specified.
*/
if (compar) {
p->fts_link = root;
root = p;
} else {
p->fts_link = NULL;
if (root == NULL)
tmp = root = p;
else {
tmp->fts_link = p;
tmp = p;
}
}
}
if (compar && nitems > 1)
root = fts_sort(sp, root, nitems);
/*
* Allocate a dummy pointer and make fts_read think that we've just
* finished the node before the root(s); set p->fts_info to FTS_INIT
* so that everything about the "current" node is ignored.
*/
if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL)
goto mem3;
sp->fts_cur->fts_link = root;
sp->fts_cur->fts_info = FTS_INIT;
/*
* If using chdir(2), grab a file descriptor pointing to dot to ensure
* that we can get back here; this could be avoided for some paths,
* but almost certainly not worth the effort. Slashes, symbolic links,
* and ".." are all fairly nasty problems. Note, if we can't get the
* descriptor we run anyway, just more slowly.
*/
if (!ISSET(FTS_NOCHDIR) &&
(sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
SET(FTS_NOCHDIR);
return (sp);
mem3: fts_lfree(root);
free(parent);
mem2: free(sp->fts_path);
mem1: free(sp);
return (NULL);
}
static void
fts_load(FTS11 *sp, FTSENT11 *p)
{
size_t len;
char *cp;
/*
* Load the stream structure for the next traversal. Since we don't
* actually enter the directory until after the preorder visit, set
* the fts_accpath field specially so the chdir gets done to the right
* place and the user can access the first node. From fts_open it's
* known that the path will fit.
*/
len = p->fts_pathlen = p->fts_namelen;
memmove(sp->fts_path, p->fts_name, len + 1);
if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) {
len = strlen(++cp);
memmove(p->fts_name, cp, len + 1);
p->fts_namelen = len;
}
p->fts_accpath = p->fts_path = sp->fts_path;
sp->fts_dev = p->fts_dev;
}
int
freebsd11_fts_close(FTS11 *sp)
{
FTSENT11 *freep, *p;
int saved_errno;
/*
* This still works if we haven't read anything -- the dummy structure
* points to the root list, so we step through to the end of the root
* list which has a valid parent pointer.
*/
if (sp->fts_cur) {
for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) {
freep = p;
p = p->fts_link != NULL ? p->fts_link : p->fts_parent;
free(freep);
}
free(p);
}
/* Free up child linked list, sort array, path buffer. */
if (sp->fts_child)
fts_lfree(sp->fts_child);
if (sp->fts_array)
free(sp->fts_array);
free(sp->fts_path);
/* Return to original directory, save errno if necessary. */
if (!ISSET(FTS_NOCHDIR)) {
saved_errno = fchdir(sp->fts_rfd) ? errno : 0;
(void)_close(sp->fts_rfd);
/* Set errno and return. */
if (saved_errno != 0) {
/* Free up the stream pointer. */
free(sp);
errno = saved_errno;
return (-1);
}
}
/* Free up the stream pointer. */
free(sp);
return (0);
}
/*
* Special case of "/" at the end of the path so that slashes aren't
* appended which would cause paths to be written as "....//foo".
*/
#define NAPPEND(p) \
(p->fts_path[p->fts_pathlen - 1] == '/' \
? p->fts_pathlen - 1 : p->fts_pathlen)
FTSENT11 *
freebsd11_fts_read(FTS11 *sp)
{
FTSENT11 *p, *tmp;
int instr;
char *t;
int saved_errno;
/* If finished or unrecoverable error, return NULL. */
if (sp->fts_cur == NULL || ISSET(FTS_STOP))
return (NULL);
/* Set current node pointer. */
p = sp->fts_cur;
/* Save and zero out user instructions. */
instr = p->fts_instr;
p->fts_instr = FTS_NOINSTR;
/* Any type of file may be re-visited; re-stat and re-turn. */
if (instr == FTS_AGAIN) {
p->fts_info = fts_stat(sp, p, 0, -1);
return (p);
}
/*
* Following a symlink -- SLNONE test allows application to see
* SLNONE and recover. If indirecting through a symlink, have
* keep a pointer to current location. If unable to get that
* pointer, follow fails.
*/
if (instr == FTS_FOLLOW &&
(p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) {
p->fts_info = fts_stat(sp, p, 1, -1);
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC,
0)) < 0) {
p->fts_errno = errno;
p->fts_info = FTS_ERR;
} else
p->fts_flags |= FTS_SYMFOLLOW;
}
return (p);
}
/* Directory in pre-order. */
if (p->fts_info == FTS_D) {
/* If skipped or crossed mount point, do post-order visit. */
if (instr == FTS_SKIP ||
(ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) {
if (p->fts_flags & FTS_SYMFOLLOW)
(void)_close(p->fts_symfd);
if (sp->fts_child) {
fts_lfree(sp->fts_child);
sp->fts_child = NULL;
}
p->fts_info = FTS_DP;
return (p);
}
/* Rebuild if only read the names and now traversing. */
if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) {
CLR(FTS_NAMEONLY);
fts_lfree(sp->fts_child);
sp->fts_child = NULL;
}
/*
* Cd to the subdirectory.
*
* If have already read and now fail to chdir, whack the list
* to make the names come out right, and set the parent errno
* so the application will eventually get an error condition.
* Set the FTS_DONTCHDIR flag so that when we logically change
* directories back to the parent we don't do a chdir.
*
* If haven't read do so. If the read fails, fts_build sets
* FTS_STOP or the fts_info field of the node.
*/
if (sp->fts_child != NULL) {
if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) {
p->fts_errno = errno;
p->fts_flags |= FTS_DONTCHDIR;
for (p = sp->fts_child; p != NULL;
p = p->fts_link)
p->fts_accpath =
p->fts_parent->fts_accpath;
}
} else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) {
if (ISSET(FTS_STOP))
return (NULL);
return (p);
}
p = sp->fts_child;
sp->fts_child = NULL;
goto name;
}
/* Move to the next node on this level. */
next: tmp = p;
if ((p = p->fts_link) != NULL) {
/*
* If reached the top, return to the original directory (or
* the root of the tree), and load the paths for the next root.
*/
if (p->fts_level == FTS_ROOTLEVEL) {
if (FCHDIR(sp, sp->fts_rfd)) {
SET(FTS_STOP);
return (NULL);
}
free(tmp);
fts_load(sp, p);
return (sp->fts_cur = p);
}
/*
* User may have called fts_set on the node. If skipped,
* ignore. If followed, get a file descriptor so we can
* get back if necessary.
*/
if (p->fts_instr == FTS_SKIP) {
free(tmp);
goto next;
}
if (p->fts_instr == FTS_FOLLOW) {
p->fts_info = fts_stat(sp, p, 1, -1);
if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) {
if ((p->fts_symfd =
_open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) {
p->fts_errno = errno;
p->fts_info = FTS_ERR;
} else
p->fts_flags |= FTS_SYMFOLLOW;
}
p->fts_instr = FTS_NOINSTR;
}
free(tmp);
name: t = sp->fts_path + NAPPEND(p->fts_parent);
*t++ = '/';
memmove(t, p->fts_name, p->fts_namelen + 1);
return (sp->fts_cur = p);
}
/* Move up to the parent node. */
p = tmp->fts_parent;
if (p->fts_level == FTS_ROOTPARENTLEVEL) {
/*
* Done; free everything up and set errno to 0 so the user
* can distinguish between error and EOF.
*/
free(tmp);
free(p);
errno = 0;
return (sp->fts_cur = NULL);
}
/* NUL terminate the pathname. */
sp->fts_path[p->fts_pathlen] = '\0';
/*
* Return to the parent directory. If at a root node or came through
* a symlink, go back through the file descriptor. Otherwise, cd up
* one directory.
*/
if (p->fts_level == FTS_ROOTLEVEL) {
if (FCHDIR(sp, sp->fts_rfd)) {
SET(FTS_STOP);
return (NULL);
}
} else if (p->fts_flags & FTS_SYMFOLLOW) {
if (FCHDIR(sp, p->fts_symfd)) {
saved_errno = errno;
(void)_close(p->fts_symfd);
errno = saved_errno;
SET(FTS_STOP);
return (NULL);
}
(void)_close(p->fts_symfd);
} else if (!(p->fts_flags & FTS_DONTCHDIR) &&
fts_safe_changedir(sp, p->fts_parent, -1, "..")) {
SET(FTS_STOP);
return (NULL);
}
free(tmp);
p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP;
return (sp->fts_cur = p);
}
/*
* Fts_set takes the stream as an argument although it's not used in this
* implementation; it would be necessary if anyone wanted to add global
* semantics to fts using fts_set. An error return is allowed for similar
* reasons.
*/
/* ARGSUSED */
int
freebsd11_fts_set(FTS11 *sp, FTSENT11 *p, int instr)
{
if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW &&
instr != FTS_NOINSTR && instr != FTS_SKIP) {
errno = EINVAL;
return (1);
}
p->fts_instr = instr;
return (0);
}
FTSENT11 *
freebsd11_fts_children(FTS11 *sp, int instr)
{
FTSENT11 *p;
int fd, rc, serrno;
if (instr != 0 && instr != FTS_NAMEONLY) {
errno = EINVAL;
return (NULL);
}
/* Set current node pointer. */
p = sp->fts_cur;
/*
* Errno set to 0 so user can distinguish empty directory from
* an error.
*/
errno = 0;
/* Fatal errors stop here. */
if (ISSET(FTS_STOP))
return (NULL);
/* Return logical hierarchy of user's arguments. */
if (p->fts_info == FTS_INIT)
return (p->fts_link);
/*
* If not a directory being visited in pre-order, stop here. Could
* allow FTS_DNR, assuming the user has fixed the problem, but the
* same effect is available with FTS_AGAIN.
*/
if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */)
return (NULL);
/* Free up any previous child list. */
if (sp->fts_child != NULL)
fts_lfree(sp->fts_child);
if (instr == FTS_NAMEONLY) {
SET(FTS_NAMEONLY);
instr = BNAMES;
} else
instr = BCHILD;
/*
* If using chdir on a relative path and called BEFORE fts_read does
* its chdir to the root of a traversal, we can lose -- we need to
* chdir into the subdirectory, and we don't know where the current
* directory is, so we can't get back so that the upcoming chdir by
* fts_read will work.
*/
if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' ||
ISSET(FTS_NOCHDIR))
return (sp->fts_child = fts_build(sp, instr));
if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0)
return (NULL);
sp->fts_child = fts_build(sp, instr);
serrno = (sp->fts_child == NULL) ? errno : 0;
rc = fchdir(fd);
if (rc < 0 && serrno == 0)
serrno = errno;
(void)_close(fd);
errno = serrno;
if (rc < 0)
return (NULL);
return (sp->fts_child);
}
#ifndef freebsd11_fts_get_clientptr
#error "freebsd11_fts_get_clientptr not defined"
#endif
void *
(freebsd11_fts_get_clientptr)(FTS11 *sp)
{
return (freebsd11_fts_get_clientptr(sp));
}
#ifndef freebsd11_fts_get_stream
#error "freebsd11_fts_get_stream not defined"
#endif
FTS11 *
(freebsd11_fts_get_stream)(FTSENT11 *p)
{
return (freebsd11_fts_get_stream(p));
}
void
freebsd11_fts_set_clientptr(FTS11 *sp, void *clientptr)
{
sp->fts_clientptr = clientptr;
}
static struct freebsd11_dirent *
fts_safe_readdir(DIR *dirp, int *readdir_errno)
{
struct freebsd11_dirent *ret;
errno = 0;
if (!dirp)
return (NULL);
ret = freebsd11_readdir(dirp);
*readdir_errno = errno;
return (ret);
}
/*
* This is the tricky part -- do not casually change *anything* in here. The
* idea is to build the linked list of entries that are used by fts_children
* and fts_read. There are lots of special cases.
*
* The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is
* set and it's a physical walk (so that symbolic links can't be directories),
* we can do things quickly. First, if it's a 4.4BSD file system, the type
* of the file is in the directory entry. Otherwise, we assume that the number
* of subdirectories in a node is equal to the number of links to the parent.
* The former skips all stat calls. The latter skips stat calls in any leaf
* directories and for any files after the subdirectories in the directory have
* been found, cutting the stat calls by about 2/3.
*/
static FTSENT11 *
fts_build(FTS11 *sp, int type)
{
struct freebsd11_dirent *dp;
FTSENT11 *p, *head;
FTSENT11 *cur, *tail;
DIR *dirp;
void *oldaddr;
char *cp;
int cderrno, descend, oflag, saved_errno, nostat, doadjust,
readdir_errno;
long level;
long nlinks; /* has to be signed because -1 is a magic value */
size_t dnamlen, len, maxlen, nitems;
/* Set current node pointer. */
cur = sp->fts_cur;
/*
* Open the directory for reading. If this fails, we're done.
* If being called from fts_read, set the fts_info field.
*/
#ifdef FTS_WHITEOUT
if (ISSET(FTS_WHITEOUT))
oflag = DTF_NODUP;
else
oflag = DTF_HIDEW | DTF_NODUP;
#else
#define __opendir2(path, flag) opendir(path)
#endif
if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) {
if (type == BREAD) {
cur->fts_info = FTS_DNR;
cur->fts_errno = errno;
}
return (NULL);
}
/*
* Nlinks is the number of possible entries of type directory in the
* directory if we're cheating on stat calls, 0 if we're not doing
* any stat calls at all, -1 if we're doing stats on everything.
*/
if (type == BNAMES) {
nlinks = 0;
/* Be quiet about nostat, GCC. */
nostat = 0;
} else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) {
if (fts_ufslinks(sp, cur))
nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2);
else
nlinks = -1;
nostat = 1;
} else {
nlinks = -1;
nostat = 0;
}
#ifdef notdef
(void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink);
(void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n",
ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT));
#endif
/*
* If we're going to need to stat anything or we want to descend
* and stay in the directory, chdir. If this fails we keep going,
* but set a flag so we don't chdir after the post-order visit.
* We won't be able to stat anything, but we can still return the
* names themselves. Note, that since fts_read won't be able to
* chdir into the directory, it will have to return different path
* names than before, i.e. "a/b" instead of "b". Since the node
* has already been visited in pre-order, have to wait until the
* post-order visit to return the error. There is a special case
* here, if there was nothing to stat then it's not an error to
* not be able to stat. This is all fairly nasty. If a program
* needed sorted entries or stat information, they had better be
* checking FTS_NS on the returned nodes.
*/
cderrno = 0;
if (nlinks || type == BREAD) {
if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) {
if (nlinks && type == BREAD)
cur->fts_errno = errno;
cur->fts_flags |= FTS_DONTCHDIR;
descend = 0;
cderrno = errno;
} else
descend = 1;
} else
descend = 0;
/*
* Figure out the max file name length that can be stored in the
* current path -- the inner loop allocates more path as necessary.
* We really wouldn't have to do the maxlen calculations here, we
* could do them in fts_read before returning the path, but it's a
* lot easier here since the length is part of the dirent structure.
*
* If not changing directories set a pointer so that can just append
* each new name into the path.
*/
len = NAPPEND(cur);
if (ISSET(FTS_NOCHDIR)) {
cp = sp->fts_path + len;
*cp++ = '/';
} else {
/* GCC, you're too verbose. */
cp = NULL;
}
len++;
maxlen = sp->fts_pathlen - len;
level = cur->fts_level + 1;
/* Read the directory, attaching each entry to the `link' pointer. */
doadjust = 0;
readdir_errno = 0;
for (head = tail = NULL, nitems = 0;
(dp = fts_safe_readdir(dirp, &readdir_errno));) {
dnamlen = dp->d_namlen;
if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name))
continue;
if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL)
goto mem1;
if (dnamlen >= maxlen) { /* include space for NUL */
oldaddr = sp->fts_path;
if (fts_palloc(sp, dnamlen + len + 1)) {
/*
* No more memory for path or structures. Save
* errno, free up the current structure and the
* structures already allocated.
*/
mem1: saved_errno = errno;
if (p)
free(p);
fts_lfree(head);
(void)closedir(dirp);
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
errno = saved_errno;
return (NULL);
}
/* Did realloc() change the pointer? */
if (oldaddr != sp->fts_path) {
doadjust = 1;
if (ISSET(FTS_NOCHDIR))
cp = sp->fts_path + len;
}
maxlen = sp->fts_pathlen - len;
}
p->fts_level = level;
p->fts_parent = sp->fts_cur;
p->fts_pathlen = len + dnamlen;
#ifdef FTS_WHITEOUT
if (dp->d_type == DT_WHT)
p->fts_flags |= FTS_ISW;
#endif
if (cderrno) {
if (nlinks) {
p->fts_info = FTS_NS;
p->fts_errno = cderrno;
} else
p->fts_info = FTS_NSOK;
p->fts_accpath = cur->fts_accpath;
} else if (nlinks == 0
#ifdef DT_DIR
|| (nostat &&
dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)
#endif
) {
p->fts_accpath =
ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name;
p->fts_info = FTS_NSOK;
} else {
/* Build a file name for fts_stat to stat. */
if (ISSET(FTS_NOCHDIR)) {
p->fts_accpath = p->fts_path;
memmove(cp, p->fts_name, p->fts_namelen + 1);
p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp));
} else {
p->fts_accpath = p->fts_name;
p->fts_info = fts_stat(sp, p, 0, -1);
}
/* Decrement link count if applicable. */
if (nlinks > 0 && (p->fts_info == FTS_D ||
p->fts_info == FTS_DC || p->fts_info == FTS_DOT))
--nlinks;
}
/* We walk in directory order so "ls -f" doesn't get upset. */
p->fts_link = NULL;
if (head == NULL)
head = tail = p;
else {
tail->fts_link = p;
tail = p;
}
++nitems;
}
if (readdir_errno) {
cur->fts_errno = readdir_errno;
/*
* If we've not read any items yet, treat
* the error as if we can't access the dir.
*/
cur->fts_info = nitems ? FTS_ERR : FTS_DNR;
}
if (dirp)
(void)closedir(dirp);
/*
* If realloc() changed the address of the path, adjust the
* addresses for the rest of the tree and the dir list.
*/
if (doadjust)
fts_padjust(sp, head);
/*
* If not changing directories, reset the path back to original
* state.
*/
if (ISSET(FTS_NOCHDIR))
sp->fts_path[cur->fts_pathlen] = '\0';
/*
* If descended after called from fts_children or after called from
* fts_read and nothing found, get back. At the root level we use
* the saved fd; if one of fts_open()'s arguments is a relative path
* to an empty directory, we wind up here with no other way back. If
* can't get back, we're done.
*/
if (descend && (type == BCHILD || !nitems) &&
(cur->fts_level == FTS_ROOTLEVEL ?
FCHDIR(sp, sp->fts_rfd) :
fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) {
fts_lfree(head);
cur->fts_info = FTS_ERR;
SET(FTS_STOP);
return (NULL);
}
/* If didn't find anything, return NULL. */
if (!nitems) {
if (type == BREAD &&
cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR)
cur->fts_info = FTS_DP;
return (NULL);
}
/* Sort the entries. */
if (sp->fts_compar && nitems > 1)
head = fts_sort(sp, head, nitems);
return (head);
}
static int
fts_stat(FTS11 *sp, FTSENT11 *p, int follow, int dfd)
{
FTSENT11 *t;
uint32_t dev;
uint32_t ino;
struct freebsd11_stat *sbp, sb;
int saved_errno;
const char *path;
if (dfd == -1)
path = p->fts_accpath, dfd = AT_FDCWD;
else
path = p->fts_name;
/* If user needs stat info, stat buffer already allocated. */
sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp;
#ifdef FTS_WHITEOUT
/* Check for whiteout. */
if (p->fts_flags & FTS_ISW) {
if (sbp != &sb) {
memset(sbp, '\0', sizeof(*sbp));
sbp->st_mode = S_IFWHT;
}
return (FTS_W);
}
#endif
/*
* If doing a logical walk, or application requested FTS_FOLLOW, do
* a stat(2). If that fails, check for a non-existent symlink. If
* fail, set the errno from the stat call.
*/
if (ISSET(FTS_LOGICAL) || follow) {
if (freebsd11_fstatat(dfd, path, sbp, 0)) {
saved_errno = errno;
if (freebsd11_fstatat(dfd, path, sbp,
AT_SYMLINK_NOFOLLOW)) {
p->fts_errno = saved_errno;
goto err;
}
errno = 0;
if (S_ISLNK(sbp->st_mode))
return (FTS_SLNONE);
}
} else if (freebsd11_fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) {
p->fts_errno = errno;
err: memset(sbp, 0, sizeof(*sbp));
return (FTS_NS);
}
if (S_ISDIR(sbp->st_mode)) {
/*
* Set the device/inode. Used to find cycles and check for
* crossing mount points. Also remember the link count, used
* in fts_build to limit the number of stat calls. It is
* understood that these fields are only referenced if fts_info
* is set to FTS_D.
*/
dev = p->fts_dev = sbp->st_dev;
ino = p->fts_ino = sbp->st_ino;
p->fts_nlink = sbp->st_nlink;
if (ISDOT(p->fts_name))
return (FTS_DOT);
/*
* Cycle detection is done by brute force when the directory
* is first encountered. If the tree gets deep enough or the
* number of symbolic links to directories is high enough,
* something faster might be worthwhile.
*/
for (t = p->fts_parent;
t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent)
if (ino == t->fts_ino && dev == t->fts_dev) {
p->fts_cycle = t;
return (FTS_DC);
}
return (FTS_D);
}
if (S_ISLNK(sbp->st_mode))
return (FTS_SL);
if (S_ISREG(sbp->st_mode))
return (FTS_F);
return (FTS_DEFAULT);
}
/*
* The comparison function takes pointers to pointers to FTSENT structures.
* Qsort wants a comparison function that takes pointers to void.
* (Both with appropriate levels of const-poisoning, of course!)
* Use a trampoline function to deal with the difference.
*/
static int
fts_compar(const void *a, const void *b)
{
FTS11 *parent;
parent = (*(const FTSENT11 * const *)a)->fts_fts;
return (*parent->fts_compar)(a, b);
}
static FTSENT11 *
fts_sort(FTS11 *sp, FTSENT11 *head, size_t nitems)
{
FTSENT11 **ap, *p;
/*
* Construct an array of pointers to the structures and call qsort(3).
* Reassemble the array in the order returned by qsort. If unable to
* sort for memory reasons, return the directory entries in their
* current order. Allocate enough space for the current needs plus
* 40 so don't realloc one entry at a time.
*/
if (nitems > sp->fts_nitems) {
sp->fts_nitems = nitems + 40;
if ((sp->fts_array = reallocf(sp->fts_array,
sp->fts_nitems * sizeof(FTSENT11 *))) == NULL) {
sp->fts_nitems = 0;
return (head);
}
}
for (ap = sp->fts_array, p = head; p; p = p->fts_link)
*ap++ = p;
qsort(sp->fts_array, nitems, sizeof(FTSENT11 *), fts_compar);
for (head = *(ap = sp->fts_array); --nitems; ++ap)
ap[0]->fts_link = ap[1];
ap[0]->fts_link = NULL;
return (head);
}
static FTSENT11 *
fts_alloc(FTS11 *sp, char *name, size_t namelen)
{
FTSENT11 *p;
size_t len;
struct ftsent11_withstat {
FTSENT11 ent;
struct freebsd11_stat statbuf;
};
/*
* The file name is a variable length array and no stat structure is
* necessary if the user has set the nostat bit. Allocate the FTSENT
* structure, the file name and the stat structure in one chunk, but
* be careful that the stat structure is reasonably aligned.
*/
if (ISSET(FTS_NOSTAT))
len = sizeof(FTSENT11) + namelen + 1;
else
len = sizeof(struct ftsent11_withstat) + namelen + 1;
if ((p = malloc(len)) == NULL)
return (NULL);
if (ISSET(FTS_NOSTAT)) {
p->fts_name = (char *)(p + 1);
p->fts_statp = NULL;
} else {
p->fts_name = (char *)((struct ftsent11_withstat *)p + 1);
p->fts_statp = &((struct ftsent11_withstat *)p)->statbuf;
}
/* Copy the name and guarantee NUL termination. */
memcpy(p->fts_name, name, namelen);
p->fts_name[namelen] = '\0';
p->fts_namelen = namelen;
p->fts_path = sp->fts_path;
p->fts_errno = 0;
p->fts_flags = 0;
p->fts_instr = FTS_NOINSTR;
p->fts_number = 0;
p->fts_pointer = NULL;
p->fts_fts = sp;
return (p);
}
static void
fts_lfree(FTSENT11 *head)
{
FTSENT11 *p;
/* Free a linked list of structures. */
while ((p = head)) {
head = head->fts_link;
free(p);
}
}
/*
* Allow essentially unlimited paths; find, rm, ls should all work on any tree.
* Most systems will allow creation of paths much longer than MAXPATHLEN, even
* though the kernel won't resolve them. Add the size (not just what's needed)
* plus 256 bytes so don't realloc the path 2 bytes at a time.
*/
static int
fts_palloc(FTS11 *sp, size_t more)
{
sp->fts_pathlen += more + 256;
sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen);
return (sp->fts_path == NULL);
}
/*
* When the path is realloc'd, have to fix all of the pointers in structures
* already returned.
*/
static void
fts_padjust(FTS11 *sp, FTSENT11 *head)
{
FTSENT11 *p;
char *addr = sp->fts_path;
#define ADJUST(p) do { \
if ((p)->fts_accpath != (p)->fts_name) { \
(p)->fts_accpath = \
(char *)addr + ((p)->fts_accpath - (p)->fts_path); \
} \
(p)->fts_path = addr; \
} while (0)
/* Adjust the current set of children. */
for (p = sp->fts_child; p; p = p->fts_link)
ADJUST(p);
/* Adjust the rest of the tree, including the current level. */
for (p = head; p->fts_level >= FTS_ROOTLEVEL;) {
ADJUST(p);
p = p->fts_link ? p->fts_link : p->fts_parent;
}
}
static size_t
fts_maxarglen(char * const *argv)
{
size_t len, max;
for (max = 0; *argv; ++argv)
if ((len = strlen(*argv)) > max)
max = len;
return (max + 1);
}
/*
* Change to dir specified by fd or p->fts_accpath without getting
* tricked by someone changing the world out from underneath us.
* Assumes p->fts_dev and p->fts_ino are filled in.
*/
static int
fts_safe_changedir(FTS11 *sp, FTSENT11 *p, int fd, char *path)
{
int ret, oerrno, newfd;
struct freebsd11_stat sb;
newfd = fd;
if (ISSET(FTS_NOCHDIR))
return (0);
if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY |
O_CLOEXEC, 0)) < 0)
return (-1);
if (freebsd11_fstat(newfd, &sb)) {
ret = -1;
goto bail;
}
if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) {
errno = ENOENT; /* disinformation */
ret = -1;
goto bail;
}
ret = fchdir(newfd);
bail:
oerrno = errno;
if (fd < 0)
(void)_close(newfd);
errno = oerrno;
return (ret);
}
/*
* Check if the filesystem for "ent" has UFS-style links.
*/
static int
fts_ufslinks(FTS11 *sp, const FTSENT11 *ent)
{
struct _fts_private11 *priv;
const char **cpp;
priv = (struct _fts_private11 *)sp;
/*
* If this node's device is different from the previous, grab
* the filesystem information, and decide on the reliability
* of the link information from this filesystem for stat(2)
* avoidance.
*/
if (priv->ftsp_dev != ent->fts_dev) {
if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) {
priv->ftsp_dev = ent->fts_dev;
priv->ftsp_linksreliable = 0;
for (cpp = ufslike_filesystems; *cpp; cpp++) {
if (strcmp(priv->ftsp_statfs.f_fstypename,
*cpp) == 0) {
priv->ftsp_linksreliable = 1;
break;
}
}
} else {
priv->ftsp_linksreliable = 0;
}
}
return (priv->ftsp_linksreliable);
}
__sym_compat(fts_open, freebsd11_fts_open, FBSD_1.1);
__sym_compat(fts_close, freebsd11_fts_close, FBSD_1.1);
__sym_compat(fts_read, freebsd11_fts_read, FBSD_1.1);
__sym_compat(fts_set, freebsd11_fts_set, FBSD_1.1);
__sym_compat(fts_children, freebsd11_fts_children, FBSD_1.1);
__sym_compat(fts_get_clientptr, freebsd11_fts_get_clientptr, FBSD_1.1);
__sym_compat(fts_get_stream, freebsd11_fts_get_stream, FBSD_1.1);
__sym_compat(fts_set_clientptr, freebsd11_fts_set_clientptr, FBSD_1.1);
diff --git a/lib/libc/gen/ftw-compat11.c b/lib/libc/gen/ftw-compat11.c
index aa9d9358aa15..28d6398f6fd8 100644
--- a/lib/libc/gen/ftw-compat11.c
+++ b/lib/libc/gen/ftw-compat11.c
@@ -1,99 +1,98 @@
/* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */
/*
* Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*
* From: FreeBSD: head/lib/libc/gen/ftw.c 239151 2012-08-09 15:11:38Z jilles
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <ftw.h>
#include "fts-compat11.h"
int freebsd11_ftw(const char *path, int (*fn)(const char *,
const struct freebsd11_stat *, int), int nfds);
int
freebsd11_ftw(const char *path,
int (*fn)(const char *, const struct freebsd11_stat *, int), int nfds)
{
char * const paths[2] = { (char *)path, NULL };
FTSENT11 *cur;
FTS11 *ftsp;
int error = 0, fnflag, sverrno;
/* XXX - nfds is currently unused */
if (nfds < 1) {
errno = EINVAL;
return (-1);
}
ftsp = freebsd11_fts_open(paths,
FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
if (ftsp == NULL)
return (-1);
while ((cur = freebsd11_fts_read(ftsp)) != NULL) {
switch (cur->fts_info) {
case FTS_D:
fnflag = FTW_D;
break;
case FTS_DNR:
fnflag = FTW_DNR;
break;
case FTS_DP:
/* we only visit in preorder */
continue;
case FTS_F:
case FTS_DEFAULT:
fnflag = FTW_F;
break;
case FTS_NS:
case FTS_NSOK:
case FTS_SLNONE:
fnflag = FTW_NS;
break;
case FTS_SL:
fnflag = FTW_SL;
break;
case FTS_DC:
errno = ELOOP;
/* FALLTHROUGH */
default:
error = -1;
goto done;
}
error = fn(cur->fts_path, cur->fts_statp, fnflag);
if (error != 0)
break;
}
done:
sverrno = errno;
if (freebsd11_fts_close(ftsp) != 0 && error == 0)
error = -1;
else
errno = sverrno;
return (error);
}
__sym_compat(ftw, freebsd11_ftw, FBSD_1.0);
diff --git a/lib/libc/gen/ftw.c b/lib/libc/gen/ftw.c
index 80b45ff32f5c..35557d930bf4 100644
--- a/lib/libc/gen/ftw.c
+++ b/lib/libc/gen/ftw.c
@@ -1,89 +1,88 @@
/* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */
/*
* Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <ftw.h>
int
ftw(const char *path, int (*fn)(const char *, const struct stat *, int),
int nfds)
{
char * const paths[2] = { (char *)path, NULL };
FTSENT *cur;
FTS *ftsp;
int error = 0, fnflag, sverrno;
/* XXX - nfds is currently unused */
if (nfds < 1) {
errno = EINVAL;
return (-1);
}
ftsp = fts_open(paths, FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL);
if (ftsp == NULL)
return (-1);
while ((cur = fts_read(ftsp)) != NULL) {
switch (cur->fts_info) {
case FTS_D:
fnflag = FTW_D;
break;
case FTS_DNR:
fnflag = FTW_DNR;
break;
case FTS_DP:
/* we only visit in preorder */
continue;
case FTS_F:
case FTS_DEFAULT:
fnflag = FTW_F;
break;
case FTS_NS:
case FTS_NSOK:
case FTS_SLNONE:
fnflag = FTW_NS;
break;
case FTS_SL:
fnflag = FTW_SL;
break;
case FTS_DC:
errno = ELOOP;
/* FALLTHROUGH */
default:
error = -1;
goto done;
}
error = fn(cur->fts_path, cur->fts_statp, fnflag);
if (error != 0)
break;
}
done:
sverrno = errno;
if (fts_close(ftsp) != 0 && error == 0)
error = -1;
else
errno = sverrno;
return (error);
}
diff --git a/lib/libc/gen/getbootfile.c b/lib/libc/gen/getbootfile.c
index e2c36a96378d..0c9b8e27c6ab 100644
--- a/lib/libc/gen/getbootfile.c
+++ b/lib/libc/gen/getbootfile.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)gethostname.c 8.1 (Berkeley) 6/4/93
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <paths.h>
const char *
getbootfile(void)
{
static char name[MAXPATHLEN];
size_t size = sizeof name;
int mib[2];
mib[0] = CTL_KERN;
mib[1] = KERN_BOOTFILE;
if (sysctl(mib, 2, name, &size, NULL, 0) == -1)
return ("/boot/kernel/kernel");
return (name);
}
diff --git a/lib/libc/gen/getentropy.c b/lib/libc/gen/getentropy.c
index 44cb190f0237..38cd515e74d7 100644
--- a/lib/libc/gen/getentropy.c
+++ b/lib/libc/gen/getentropy.c
@@ -1,157 +1,156 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/random.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
#include "libc_private.h"
/* First __FreeBSD_version bump after introduction of getrandom(2) (r331279) */
#define GETRANDOM_FIRST 1200061
extern int __sysctl(int *, u_int, void *, size_t *, void *, size_t);
static inline void
_getentropy_fail(void)
{
raise(SIGKILL);
}
static size_t
arnd_sysctl(u_char *buf, size_t size)
{
int mib[2];
size_t len, done;
mib[0] = CTL_KERN;
mib[1] = KERN_ARND;
done = 0;
do {
len = size;
if (__sysctl(mib, 2, buf, &len, NULL, 0) == -1)
return (done);
done += len;
buf += len;
size -= len;
} while (size > 0);
return (done);
}
/*
* If a newer libc is accidentally installed on an older kernel, provide high
* quality random data anyway. The sysctl interface is not as fast and does
* not block by itself, but is provided by even very old kernels.
*/
static int
getentropy_fallback(void *buf, size_t buflen)
{
/*
* oldp (buf) == NULL has a special meaning for sysctl that results in
* no EFAULT. For compatibility with the kernel getrandom(2), detect
* this case and return the appropriate error.
*/
if (buf == NULL && buflen > 0) {
errno = EFAULT;
return (-1);
}
if (arnd_sysctl(buf, buflen) != buflen) {
if (errno == EFAULT)
return (-1);
/*
* This cannot happen. arnd_sysctl() spins until the random
* device is seeded and then repeatedly reads until the full
* request is satisfied. The only way for this to return a zero
* byte or short read is if sysctl(2) on the kern.arandom MIB
* fails. In this case, excepting the user-provided-a-bogus-
* buffer EFAULT, give up (like for arc4random(3)'s arc4_stir).
*/
_getentropy_fail();
}
return (0);
}
int
getentropy(void *buf, size_t buflen)
{
ssize_t rd;
bool have_getrandom;
if (buflen > 256) {
errno = EIO;
return (-1);
}
have_getrandom = (__getosreldate() >= GETRANDOM_FIRST);
while (buflen > 0) {
if (have_getrandom) {
rd = getrandom(buf, buflen, 0);
if (rd == -1) {
switch (errno) {
case ECAPMODE:
/*
* Kernel >= r331280 and < r337999
* will return ECAPMODE when the
* caller is already in capability
* mode, fallback to traditional
* method in this case.
*/
have_getrandom = false;
continue;
case EINTR:
continue;
case EFAULT:
return (-1);
default:
_getentropy_fail();
}
}
} else {
return (getentropy_fallback(buf, buflen));
}
/* This cannot happen. */
if (rd == 0)
_getentropy_fail();
buf = (char *)buf + rd;
buflen -= rd;
}
return (0);
}
diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c
index b7fe6021f9fd..508e3d63eb60 100644
--- a/lib/libc/gen/getgrent.c
+++ b/lib/libc/gen/getgrent.c
@@ -1,1576 +1,1575 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#ifdef HESIOD
#include <hesiod.h>
#endif
#include <grp.h>
#include <nsswitch.h>
#include <pthread.h>
#include <pthread_np.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "nss_tls.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
enum constants {
GRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
GRP_STORAGE_MAX = 1 << 20, /* 1 MByte */
SETGRENT = 1,
ENDGRENT = 2,
HESIOD_NAME_MAX = 256,
};
static const ns_src defaultsrc[] = {
{ NSSRC_COMPAT, NS_SUCCESS },
{ NULL, 0 }
};
int __getgroupmembership(const char *, gid_t, gid_t *, int, int *);
int __gr_match_entry(const char *, size_t, enum nss_lookup_type,
const char *, gid_t);
int __gr_parse_entry(char *, size_t, struct group *, char *, size_t,
int *);
static int is_comment_line(const char *, size_t);
union key {
const char *name;
gid_t gid;
};
static struct group *getgr(int (*)(union key, struct group *, char *, size_t,
struct group **), union key);
static int wrap_getgrnam_r(union key, struct group *, char *, size_t,
struct group **);
static int wrap_getgrgid_r(union key, struct group *, char *, size_t,
struct group **);
static int wrap_getgrent_r(union key, struct group *, char *, size_t,
struct group **);
struct files_state {
FILE *fp;
int stayopen;
};
static void files_endstate(void *);
NSS_TLS_HANDLING(files);
static int files_setgrent(void *, void *, va_list);
static int files_group(void *, void *, va_list);
#ifdef HESIOD
struct dns_state {
long counter;
};
static void dns_endstate(void *);
NSS_TLS_HANDLING(dns);
static int dns_setgrent(void *, void *, va_list);
static int dns_group(void *, void *, va_list);
#endif
#ifdef YP
struct nis_state {
char domain[MAXHOSTNAMELEN];
int done;
char *key;
int keylen;
};
static void nis_endstate(void *);
NSS_TLS_HANDLING(nis);
static int nis_setgrent(void *, void *, va_list);
static int nis_group(void *, void *, va_list);
#endif
struct compat_state {
FILE *fp;
int stayopen;
char *name;
enum _compat {
COMPAT_MODE_OFF = 0,
COMPAT_MODE_ALL,
COMPAT_MODE_NAME
} compat;
};
static void compat_endstate(void *);
NSS_TLS_HANDLING(compat);
static int compat_setgrent(void *, void *, va_list);
static int compat_group(void *, void *, va_list);
static int gr_addgid(gid_t, gid_t *, int, int *);
static int getgroupmembership_fallback(void *, void *, va_list);
#ifdef NS_CACHING
static int grp_id_func(char *, size_t *, va_list, void *);
static int grp_marshal_func(char *, size_t *, void *, va_list, void *);
static int grp_unmarshal_func(char *, size_t, void *, va_list, void *);
static int
grp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
{
char *name;
gid_t gid;
size_t desired_size, size;
int res = NS_UNAVAIL;
enum nss_lookup_type lookup_type;
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
size = strlen(name);
desired_size = sizeof(enum nss_lookup_type) + size + 1;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
res = NS_SUCCESS;
break;
case nss_lt_id:
gid = va_arg(ap, gid_t);
desired_size = sizeof(enum nss_lookup_type) + sizeof(gid_t);
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), &gid,
sizeof(gid_t));
res = NS_SUCCESS;
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
fin:
*buffer_size = desired_size;
return (res);
}
static int
grp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
gid_t gid __unused;
struct group *grp;
char *orig_buf __unused;
size_t orig_buf_size __unused;
struct group new_grp;
size_t desired_size, size, mem_size;
char *p, **mem;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
gid = va_arg(ap, gid_t);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
grp = va_arg(ap, struct group *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
desired_size = _ALIGNBYTES + sizeof(struct group) + sizeof(char *);
if (grp->gr_name != NULL)
desired_size += strlen(grp->gr_name) + 1;
if (grp->gr_passwd != NULL)
desired_size += strlen(grp->gr_passwd) + 1;
if (grp->gr_mem != NULL) {
mem_size = 0;
for (mem = grp->gr_mem; *mem; ++mem) {
desired_size += strlen(*mem) + 1;
++mem_size;
}
desired_size += _ALIGNBYTES + (mem_size + 1) * sizeof(char *);
}
if (desired_size > *buffer_size) {
/* this assignment is here for future use */
*buffer_size = desired_size;
return (NS_RETURN);
}
memcpy(&new_grp, grp, sizeof(struct group));
memset(buffer, 0, desired_size);
*buffer_size = desired_size;
p = buffer + sizeof(struct group) + sizeof(char *);
memcpy(buffer + sizeof(struct group), &p, sizeof(char *));
p = (char *)_ALIGN(p);
if (new_grp.gr_name != NULL) {
size = strlen(new_grp.gr_name);
memcpy(p, new_grp.gr_name, size);
new_grp.gr_name = p;
p += size + 1;
}
if (new_grp.gr_passwd != NULL) {
size = strlen(new_grp.gr_passwd);
memcpy(p, new_grp.gr_passwd, size);
new_grp.gr_passwd = p;
p += size + 1;
}
if (new_grp.gr_mem != NULL) {
p = (char *)_ALIGN(p);
memcpy(p, new_grp.gr_mem, sizeof(char *) * mem_size);
new_grp.gr_mem = (char **)p;
p += sizeof(char *) * (mem_size + 1);
for (mem = new_grp.gr_mem; *mem; ++mem) {
size = strlen(*mem);
memcpy(p, *mem, size);
*mem = p;
p += size + 1;
}
}
memcpy(buffer, &new_grp, sizeof(struct group));
return (NS_SUCCESS);
}
static int
grp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
gid_t gid __unused;
struct group *grp;
char *orig_buf;
size_t orig_buf_size;
int *ret_errno;
char *p;
char **mem;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
gid = va_arg(ap, gid_t);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
grp = va_arg(ap, struct group *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
ret_errno = va_arg(ap, int *);
if (orig_buf_size + sizeof(struct group) + sizeof(char *) < buffer_size)
{
*ret_errno = ERANGE;
return (NS_RETURN);
} else if (buffer_size < sizeof(struct group) + sizeof(char *)) {
/*
* nscd(8) sometimes returns buffer_size=1 for nonexistent
* entries.
*/
*ret_errno = 0;
return (NS_NOTFOUND);
}
memcpy(grp, buffer, sizeof(struct group));
memcpy(&p, buffer + sizeof(struct group), sizeof(char *));
if (orig_buf_size + sizeof(struct group) + sizeof(char *) +
_ALIGN(p) - (size_t)p < buffer_size) {
*ret_errno = ERANGE;
return (NS_RETURN);
}
orig_buf = (char *)_ALIGN(orig_buf);
memcpy(orig_buf, buffer + sizeof(struct group) + sizeof(char *) +
_ALIGN(p) - (size_t)p,
buffer_size - sizeof(struct group) - sizeof(char *) -
_ALIGN(p) + (size_t)p);
p = (char *)_ALIGN(p);
NS_APPLY_OFFSET(grp->gr_name, orig_buf, p, char *);
NS_APPLY_OFFSET(grp->gr_passwd, orig_buf, p, char *);
if (grp->gr_mem != NULL) {
NS_APPLY_OFFSET(grp->gr_mem, orig_buf, p, char **);
for (mem = grp->gr_mem; *mem; ++mem)
NS_APPLY_OFFSET(*mem, orig_buf, p, char *);
}
if (retval != NULL)
*((struct group **)retval) = grp;
return (NS_SUCCESS);
}
NSS_MP_CACHE_HANDLING(group);
#endif /* NS_CACHING */
#ifdef NS_CACHING
static const nss_cache_info setgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
group, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab setgrent_dtab[] = {
{ NSSRC_FILES, files_setgrent, (void *)SETGRENT },
#ifdef HESIOD
{ NSSRC_DNS, dns_setgrent, (void *)SETGRENT },
#endif
#ifdef YP
{ NSSRC_NIS, nis_setgrent, (void *)SETGRENT },
#endif
{ NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT },
#ifdef NS_CACHING
NS_CACHE_CB(&setgrent_cache_info)
#endif
{ NULL, NULL, NULL }
};
#ifdef NS_CACHING
static const nss_cache_info endgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
group, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab endgrent_dtab[] = {
{ NSSRC_FILES, files_setgrent, (void *)ENDGRENT },
#ifdef HESIOD
{ NSSRC_DNS, dns_setgrent, (void *)ENDGRENT },
#endif
#ifdef YP
{ NSSRC_NIS, nis_setgrent, (void *)ENDGRENT },
#endif
{ NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT },
#ifdef NS_CACHING
NS_CACHE_CB(&endgrent_cache_info)
#endif
{ NULL, NULL, NULL }
};
#ifdef NS_CACHING
static const nss_cache_info getgrent_r_cache_info = NS_MP_CACHE_INFO_INITIALIZER(
group, (void *)nss_lt_all,
grp_marshal_func, grp_unmarshal_func);
#endif
static const ns_dtab getgrent_r_dtab[] = {
{ NSSRC_FILES, files_group, (void *)nss_lt_all },
#ifdef HESIOD
{ NSSRC_DNS, dns_group, (void *)nss_lt_all },
#endif
#ifdef YP
{ NSSRC_NIS, nis_group, (void *)nss_lt_all },
#endif
{ NSSRC_COMPAT, compat_group, (void *)nss_lt_all },
#ifdef NS_CACHING
NS_CACHE_CB(&getgrent_r_cache_info)
#endif
{ NULL, NULL, NULL }
};
static int
gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *grpcnt)
{
int ret, dupc;
for (dupc = 1; dupc < MIN(maxgrp, *grpcnt); dupc++) {
if (groups[dupc] == gid)
return 1;
}
ret = 1;
if (*grpcnt < maxgrp)
groups[*grpcnt] = gid;
else
ret = 0;
(*grpcnt)++;
return ret;
}
static int
getgroupmembership_fallback(void *retval, void *mdata, va_list ap)
{
const ns_src src[] = {
{ mdata, NS_SUCCESS },
{ NULL, 0}
};
struct group grp;
struct group *grp_p;
char *buf;
size_t bufsize;
const char *uname;
gid_t *groups;
gid_t agroup;
int maxgrp, *grpcnt;
int i, rv, ret_errno;
/*
* As this is a fallback method, only provided src
* list will be respected during methods search.
*/
assert(src[0].name != NULL);
uname = va_arg(ap, const char *);
agroup = va_arg(ap, gid_t);
groups = va_arg(ap, gid_t *);
maxgrp = va_arg(ap, int);
grpcnt = va_arg(ap, int *);
rv = NS_UNAVAIL;
buf = malloc(GRP_STORAGE_INITIAL);
if (buf == NULL)
goto out;
bufsize = GRP_STORAGE_INITIAL;
gr_addgid(agroup, groups, maxgrp, grpcnt);
_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0);
for (;;) {
do {
ret_errno = 0;
grp_p = NULL;
rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP,
"getgrent_r", src, &grp, buf, bufsize, &ret_errno);
if (grp_p == NULL && ret_errno == ERANGE) {
free(buf);
if ((bufsize << 1) > GRP_STORAGE_MAX) {
buf = NULL;
errno = ERANGE;
goto out;
}
bufsize <<= 1;
buf = malloc(bufsize);
if (buf == NULL) {
goto out;
}
}
} while (grp_p == NULL && ret_errno == ERANGE);
if (ret_errno != 0) {
errno = ret_errno;
goto out;
}
if (grp_p == NULL)
break;
for (i = 0; grp.gr_mem[i]; i++) {
if (strcmp(grp.gr_mem[i], uname) == 0)
gr_addgid(grp.gr_gid, groups, maxgrp, grpcnt);
}
}
_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src);
out:
free(buf);
return (rv);
}
void
setgrent(void)
{
(void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 0);
}
int
setgroupent(int stayopen)
{
(void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc,
stayopen);
return (1);
}
void
endgrent(void)
{
(void)_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", defaultsrc);
}
int
getgrent_r(struct group *grp, char *buffer, size_t bufsize,
struct group **result)
{
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = _nsdispatch(result, getgrent_r_dtab, NSDB_GROUP, "getgrent_r", defaultsrc,
grp, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
int
getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize,
struct group **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
group, (void *)nss_lt_name,
grp_id_func, grp_marshal_func, grp_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_group, (void *)nss_lt_name },
#ifdef HESIOD
{ NSSRC_DNS, dns_group, (void *)nss_lt_name },
#endif
#ifdef YP
{ NSSRC_NIS, nis_group, (void *)nss_lt_name },
#endif
{ NSSRC_COMPAT, compat_group, (void *)nss_lt_name },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc,
name, grp, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
int
getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize,
struct group **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
group, (void *)nss_lt_id,
grp_id_func, grp_marshal_func, grp_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_group, (void *)nss_lt_id },
#ifdef HESIOD
{ NSSRC_DNS, dns_group, (void *)nss_lt_id },
#endif
#ifdef YP
{ NSSRC_NIS, nis_group, (void *)nss_lt_id },
#endif
{ NSSRC_COMPAT, compat_group, (void *)nss_lt_id },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc,
gid, grp, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
int
__getgroupmembership(const char *uname, gid_t agroup, gid_t *groups,
int maxgrp, int *grpcnt)
{
static const ns_dtab dtab[] = {
NS_FALLBACK_CB(getgroupmembership_fallback)
{ NULL, NULL, NULL }
};
assert(uname != NULL);
/* groups may be NULL if just sizing when invoked with maxgrp = 0 */
assert(grpcnt != NULL);
*grpcnt = 0;
(void)_nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership",
defaultsrc, uname, agroup, groups, maxgrp, grpcnt);
/* too many groups found? */
return (*grpcnt > maxgrp ? -1 : 0);
}
static struct group grp;
static char *grp_storage;
static size_t grp_storage_size;
static struct group *
getgr(int (*fn)(union key, struct group *, char *, size_t, struct group **),
union key key)
{
int rv;
struct group *res;
if (grp_storage == NULL) {
grp_storage = malloc(GRP_STORAGE_INITIAL);
if (grp_storage == NULL)
return (NULL);
grp_storage_size = GRP_STORAGE_INITIAL;
}
do {
rv = fn(key, &grp, grp_storage, grp_storage_size, &res);
if (res == NULL && rv == ERANGE) {
free(grp_storage);
if ((grp_storage_size << 1) > GRP_STORAGE_MAX) {
grp_storage = NULL;
errno = ERANGE;
return (NULL);
}
grp_storage_size <<= 1;
grp_storage = malloc(grp_storage_size);
if (grp_storage == NULL)
return (NULL);
}
} while (res == NULL && rv == ERANGE);
if (rv != 0)
errno = rv;
return (res);
}
static int
wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize,
struct group **res)
{
return (getgrnam_r(key.name, grp, buffer, bufsize, res));
}
static int
wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize,
struct group **res)
{
return (getgrgid_r(key.gid, grp, buffer, bufsize, res));
}
static int
wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer,
size_t bufsize, struct group **res)
{
return (getgrent_r(grp, buffer, bufsize, res));
}
struct group *
getgrnam(const char *name)
{
union key key;
key.name = name;
return (getgr(wrap_getgrnam_r, key));
}
struct group *
getgrgid(gid_t gid)
{
union key key;
key.gid = gid;
return (getgr(wrap_getgrgid_r, key));
}
struct group *
getgrent(void)
{
union key key;
key.gid = 0; /* not used */
return (getgr(wrap_getgrent_r, key));
}
static int
is_comment_line(const char *s, size_t n)
{
const char *eom;
eom = &s[n];
for (; s < eom; s++)
if (*s == '#' || !isspace((unsigned char)*s))
break;
return (*s == '#' || s == eom);
}
/*
* files backend
*/
static void
files_endstate(void *p)
{
if (p == NULL)
return;
if (((struct files_state *)p)->fp != NULL)
fclose(((struct files_state *)p)->fp);
free(p);
}
static int
files_setgrent(void *retval, void *mdata, va_list ap)
{
struct files_state *st;
int rv, stayopen;
rv = files_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata) {
case SETGRENT:
stayopen = va_arg(ap, int);
if (st->fp != NULL)
rewind(st->fp);
else if (stayopen)
st->fp = fopen(_PATH_GROUP, "re");
st->stayopen = stayopen;
break;
case ENDGRENT:
if (st->fp != NULL) {
fclose(st->fp);
st->fp = NULL;
}
break;
default:
break;
}
return (NS_UNAVAIL);
}
static int
files_group(void *retval, void *mdata, va_list ap)
{
struct files_state *st;
enum nss_lookup_type how;
const char *name, *line;
struct group *grp;
gid_t gid;
char *buffer;
size_t bufsize, linesize;
off_t pos;
int fresh, rv, stayopen, *errnop;
fresh = 0;
name = NULL;
gid = (gid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
break;
case nss_lt_id:
gid = va_arg(ap, gid_t);
break;
case nss_lt_all:
break;
default:
return (NS_NOTFOUND);
}
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = files_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->fp == NULL) {
st->fp = fopen(_PATH_GROUP, "re");
if (st->fp == NULL) {
*errnop = errno;
return (NS_UNAVAIL);
}
fresh = 1;
}
stayopen = (how == nss_lt_all || !fresh) ? 1 : st->stayopen;
if (stayopen)
pos = ftello(st->fp);
if (how != nss_lt_all && !fresh)
rewind(st->fp);
rv = NS_NOTFOUND;
while ((line = fgetln(st->fp, &linesize)) != NULL) {
if (line[linesize-1] == '\n')
linesize--;
rv = __gr_match_entry(line, linesize, how, name, gid);
if (rv != NS_SUCCESS)
continue;
/* We need room at least for the line, a string NUL
* terminator, alignment padding, and one (char *)
* pointer for the member list terminator.
*/
if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
*errnop = ERANGE;
rv = NS_RETURN;
break;
}
memcpy(buffer, line, linesize);
buffer[linesize] = '\0';
rv = __gr_parse_entry(buffer, linesize, grp,
&buffer[linesize + 1], bufsize - linesize - 1, errnop);
if (rv & NS_TERMINATE)
break;
if (how == nss_lt_all)
pos = ftello(st->fp);
}
if (st->fp != NULL && !stayopen) {
fclose(st->fp);
st->fp = NULL;
}
if (st->fp != NULL && how != nss_lt_all)
fseeko(st->fp, pos, SEEK_SET);
if (rv == NS_SUCCESS && retval != NULL)
*(struct group **)retval = grp;
else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
fseeko(st->fp, pos, SEEK_SET);
return (rv);
}
#ifdef HESIOD
/*
* dns backend
*/
static void
dns_endstate(void *p)
{
free(p);
}
static int
dns_setgrent(void *retval, void *cb_data, va_list ap)
{
struct dns_state *st;
int rv;
rv = dns_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
st->counter = 0;
return (NS_UNAVAIL);
}
static int
dns_group(void *retval, void *mdata, va_list ap)
{
char buf[HESIOD_NAME_MAX];
struct dns_state *st;
struct group *grp;
const char *name, *label;
void *ctx;
char *buffer, **hes;
size_t bufsize, adjsize, linesize;
gid_t gid;
enum nss_lookup_type how;
int rv, *errnop;
ctx = NULL;
hes = NULL;
name = NULL;
gid = (gid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
break;
case nss_lt_id:
gid = va_arg(ap, gid_t);
break;
case nss_lt_all:
break;
}
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = dns_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (hesiod_init(&ctx) != 0) {
*errnop = errno;
rv = NS_UNAVAIL;
goto fin;
}
do {
rv = NS_NOTFOUND;
switch (how) {
case nss_lt_name:
label = name;
break;
case nss_lt_id:
if (snprintf(buf, sizeof(buf), "%lu",
(unsigned long)gid) >= sizeof(buf))
goto fin;
label = buf;
break;
case nss_lt_all:
if (st->counter < 0)
goto fin;
if (snprintf(buf, sizeof(buf), "group-%ld",
st->counter++) >= sizeof(buf))
goto fin;
label = buf;
break;
}
hes = hesiod_resolve(ctx, label,
how == nss_lt_id ? "gid" : "group");
if ((how == nss_lt_id && hes == NULL &&
(hes = hesiod_resolve(ctx, buf, "group")) == NULL) ||
hes == NULL) {
if (how == nss_lt_all)
st->counter = -1;
if (errno != ENOENT)
*errnop = errno;
goto fin;
}
rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid);
if (rv != NS_SUCCESS) {
hesiod_free_list(ctx, hes);
hes = NULL;
continue;
}
/* We need room at least for the line, a string NUL
* terminator, alignment padding, and one (char *)
* pointer for the member list terminator.
*/
adjsize = bufsize - _ALIGNBYTES - sizeof(char *);
linesize = strlcpy(buffer, hes[0], adjsize);
if (linesize >= adjsize) {
*errnop = ERANGE;
rv = NS_RETURN;
goto fin;
}
hesiod_free_list(ctx, hes);
hes = NULL;
rv = __gr_parse_entry(buffer, linesize, grp,
&buffer[linesize + 1], bufsize - linesize - 1, errnop);
} while (how == nss_lt_all && !(rv & NS_TERMINATE));
fin:
if (hes != NULL)
hesiod_free_list(ctx, hes);
if (ctx != NULL)
hesiod_end(ctx);
if (rv == NS_SUCCESS && retval != NULL)
*(struct group **)retval = grp;
return (rv);
}
#endif /* HESIOD */
#ifdef YP
/*
* nis backend
*/
static void
nis_endstate(void *p)
{
if (p == NULL)
return;
free(((struct nis_state *)p)->key);
free(p);
}
static int
nis_setgrent(void *retval, void *cb_data, va_list ap)
{
struct nis_state *st;
int rv;
rv = nis_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
st->done = 0;
free(st->key);
st->key = NULL;
return (NS_UNAVAIL);
}
static int
nis_group(void *retval, void *mdata, va_list ap)
{
char *map;
struct nis_state *st;
struct group *grp;
const char *name;
char *buffer, *key, *result;
size_t bufsize;
gid_t gid;
enum nss_lookup_type how;
int *errnop, keylen, resultlen, rv;
name = NULL;
gid = (gid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
map = "group.byname";
break;
case nss_lt_id:
gid = va_arg(ap, gid_t);
map = "group.bygid";
break;
case nss_lt_all:
map = "group.byname";
break;
}
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = nis_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->domain[0] == '\0') {
if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
*errnop = errno;
return (NS_UNAVAIL);
}
}
result = NULL;
do {
rv = NS_NOTFOUND;
switch (how) {
case nss_lt_name:
if (strlcpy(buffer, name, bufsize) >= bufsize)
goto erange;
break;
case nss_lt_id:
if (snprintf(buffer, bufsize, "%lu",
(unsigned long)gid) >= bufsize)
goto erange;
break;
case nss_lt_all:
if (st->done)
goto fin;
break;
}
result = NULL;
if (how == nss_lt_all) {
if (st->key == NULL)
rv = yp_first(st->domain, map, &st->key,
&st->keylen, &result, &resultlen);
else {
key = st->key;
keylen = st->keylen;
st->key = NULL;
rv = yp_next(st->domain, map, key, keylen,
&st->key, &st->keylen, &result,
&resultlen);
free(key);
}
if (rv != 0) {
free(result);
free(st->key);
st->key = NULL;
if (rv == YPERR_NOMORE) {
st->done = 1;
rv = NS_NOTFOUND;
} else
rv = NS_UNAVAIL;
goto fin;
}
} else {
rv = yp_match(st->domain, map, buffer, strlen(buffer),
&result, &resultlen);
if (rv == YPERR_KEY) {
rv = NS_NOTFOUND;
continue;
} else if (rv != 0) {
free(result);
rv = NS_UNAVAIL;
continue;
}
}
/* We need room at least for the line, a string NUL
* terminator, alignment padding, and one (char *)
* pointer for the member list terminator.
*/
if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *)) {
free(result);
goto erange;
}
memcpy(buffer, result, resultlen);
buffer[resultlen] = '\0';
free(result);
rv = __gr_match_entry(buffer, resultlen, how, name, gid);
if (rv == NS_SUCCESS)
rv = __gr_parse_entry(buffer, resultlen, grp,
&buffer[resultlen+1], bufsize - resultlen - 1,
errnop);
} while (how == nss_lt_all && !(rv & NS_TERMINATE));
fin:
if (rv == NS_SUCCESS && retval != NULL)
*(struct group **)retval = grp;
return (rv);
erange:
*errnop = ERANGE;
return (NS_RETURN);
}
#endif /* YP */
/*
* compat backend
*/
static void
compat_endstate(void *p)
{
struct compat_state *st;
if (p == NULL)
return;
st = (struct compat_state *)p;
free(st->name);
if (st->fp != NULL)
fclose(st->fp);
free(p);
}
static int
compat_setgrent(void *retval, void *mdata, va_list ap)
{
static const ns_src compatsrc[] = {
#ifdef YP
{ NSSRC_NIS, NS_SUCCESS },
#endif
{ NULL, 0 }
};
ns_dtab dtab[] = {
#ifdef HESIOD
{ NSSRC_DNS, dns_setgrent, NULL },
#endif
#ifdef YP
{ NSSRC_NIS, nis_setgrent, NULL },
#endif
{ NULL, NULL, NULL }
};
struct compat_state *st;
int rv, stayopen;
#define set_setent(x, y) do { \
int i; \
for (i = 0; i < (int)(nitems(x) - 1); i++) \
x[i].mdata = (void *)y; \
} while (0)
rv = compat_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata) {
case SETGRENT:
stayopen = va_arg(ap, int);
if (st->fp != NULL)
rewind(st->fp);
else if (stayopen)
st->fp = fopen(_PATH_GROUP, "re");
st->stayopen = stayopen;
set_setent(dtab, mdata);
(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent",
compatsrc, 0);
break;
case ENDGRENT:
if (st->fp != NULL) {
fclose(st->fp);
st->fp = NULL;
}
set_setent(dtab, mdata);
(void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent",
compatsrc, 0);
break;
default:
break;
}
st->compat = COMPAT_MODE_OFF;
free(st->name);
st->name = NULL;
return (NS_UNAVAIL);
#undef set_setent
}
static int
compat_group(void *retval, void *mdata, va_list ap)
{
static const ns_src compatsrc[] = {
#ifdef YP
{ NSSRC_NIS, NS_SUCCESS },
#endif
{ NULL, 0 }
};
ns_dtab dtab[] = {
#ifdef YP
{ NSSRC_NIS, nis_group, NULL },
#endif
#ifdef HESIOD
{ NSSRC_DNS, dns_group, NULL },
#endif
{ NULL, NULL, NULL }
};
struct compat_state *st;
enum nss_lookup_type how;
const char *name, *line;
struct group *grp;
gid_t gid;
char *buffer, *p;
void *discard;
size_t bufsize, linesize;
off_t pos;
int fresh, rv, stayopen, *errnop;
#define set_lookup_type(x, y) do { \
int i; \
for (i = 0; i < (int)(nitems(x) - 1); i++) \
x[i].mdata = (void *)y; \
} while (0)
fresh = 0;
name = NULL;
gid = (gid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
break;
case nss_lt_id:
gid = va_arg(ap, gid_t);
break;
case nss_lt_all:
break;
default:
return (NS_NOTFOUND);
}
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = compat_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->fp == NULL) {
st->fp = fopen(_PATH_GROUP, "re");
if (st->fp == NULL) {
*errnop = errno;
rv = NS_UNAVAIL;
goto fin;
}
fresh = 1;
}
stayopen = (how == nss_lt_all || !fresh) ? 1 : st->stayopen;
if (stayopen)
pos = ftello(st->fp);
if (how != nss_lt_all && !fresh)
rewind(st->fp);
docompat:
switch (st->compat) {
case COMPAT_MODE_ALL:
set_lookup_type(dtab, how);
switch (how) {
case nss_lt_all:
rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
"getgrent_r", compatsrc, grp, buffer, bufsize,
errnop);
break;
case nss_lt_id:
rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
"getgrgid_r", compatsrc, gid, grp, buffer, bufsize,
errnop);
break;
case nss_lt_name:
rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
"getgrnam_r", compatsrc, name, grp, buffer,
bufsize, errnop);
break;
}
if (rv & NS_TERMINATE)
goto fin;
st->compat = COMPAT_MODE_OFF;
break;
case COMPAT_MODE_NAME:
set_lookup_type(dtab, nss_lt_name);
rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT,
"getgrnam_r", compatsrc, st->name, grp, buffer, bufsize,
errnop);
switch (rv) {
case NS_SUCCESS:
switch (how) {
case nss_lt_name:
if (strcmp(name, grp->gr_name) != 0)
rv = NS_NOTFOUND;
break;
case nss_lt_id:
if (gid != grp->gr_gid)
rv = NS_NOTFOUND;
break;
default:
break;
}
break;
case NS_RETURN:
goto fin;
default:
break;
}
free(st->name);
st->name = NULL;
st->compat = COMPAT_MODE_OFF;
if (rv == NS_SUCCESS)
goto fin;
break;
default:
break;
}
rv = NS_NOTFOUND;
while ((line = fgetln(st->fp, &linesize)) != NULL) {
if (line[linesize-1] == '\n')
linesize--;
if (linesize > 2 && line[0] == '+') {
p = memchr(&line[1], ':', linesize);
if (p == NULL || p == &line[1])
st->compat = COMPAT_MODE_ALL;
else {
st->name = malloc(p - line);
if (st->name == NULL) {
syslog(LOG_ERR,
"getgrent memory allocation failure");
*errnop = ENOMEM;
rv = NS_UNAVAIL;
break;
}
memcpy(st->name, &line[1], p - line - 1);
st->name[p - line - 1] = '\0';
st->compat = COMPAT_MODE_NAME;
}
goto docompat;
}
rv = __gr_match_entry(line, linesize, how, name, gid);
if (rv != NS_SUCCESS)
continue;
/* We need room at least for the line, a string NUL
* terminator, alignment padding, and one (char *)
* pointer for the member list terminator.
*/
if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
*errnop = ERANGE;
rv = NS_RETURN;
break;
}
memcpy(buffer, line, linesize);
buffer[linesize] = '\0';
rv = __gr_parse_entry(buffer, linesize, grp,
&buffer[linesize + 1], bufsize - linesize - 1, errnop);
if (rv & NS_TERMINATE)
break;
if (how == nss_lt_all)
pos = ftello(st->fp);
}
fin:
if (st->fp != NULL && !stayopen) {
fclose(st->fp);
st->fp = NULL;
}
if (st->fp != NULL && how != nss_lt_all)
fseeko(st->fp, pos, SEEK_SET);
if (rv == NS_SUCCESS && retval != NULL)
*(struct group **)retval = grp;
else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL)
fseeko(st->fp, pos, SEEK_SET);
return (rv);
#undef set_lookup_type
}
/*
* common group line matching and parsing
*/
int
__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how,
const char *name, gid_t gid)
{
size_t namesize;
const char *p, *eol;
char *q;
unsigned long n;
int i, needed;
if (linesize == 0 || is_comment_line(line, linesize))
return (NS_NOTFOUND);
switch (how) {
case nss_lt_name: needed = 1; break;
case nss_lt_id: needed = 2; break;
default: needed = 2; break;
}
eol = &line[linesize];
for (p = line, i = 0; i < needed && p < eol; p++)
if (*p == ':')
i++;
if (i < needed)
return (NS_NOTFOUND);
switch (how) {
case nss_lt_name:
namesize = strlen(name);
if (namesize + 1 == (size_t)(p - line) &&
memcmp(line, name, namesize) == 0)
return (NS_SUCCESS);
break;
case nss_lt_id:
n = strtoul(p, &q, 10);
if (q < eol && *q == ':' && gid == (gid_t)n)
return (NS_SUCCESS);
break;
case nss_lt_all:
return (NS_SUCCESS);
default:
break;
}
return (NS_NOTFOUND);
}
int
__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf,
size_t membufsize, int *errnop)
{
char *s_gid, *s_mem, *p, **members;
unsigned long n;
int maxmembers;
memset(grp, 0, sizeof(*grp));
members = (char **)_ALIGN(membuf);
membufsize -= (char *)members - membuf;
maxmembers = membufsize / sizeof(*members);
if (maxmembers <= 0 ||
(grp->gr_name = strsep(&line, ":")) == NULL ||
grp->gr_name[0] == '\0' ||
(grp->gr_passwd = strsep(&line, ":")) == NULL ||
(s_gid = strsep(&line, ":")) == NULL ||
s_gid[0] == '\0')
return (NS_NOTFOUND);
s_mem = line;
n = strtoul(s_gid, &s_gid, 10);
if (s_gid[0] != '\0')
return (NS_NOTFOUND);
grp->gr_gid = (gid_t)n;
grp->gr_mem = members;
while (maxmembers > 1 && s_mem != NULL) {
p = strsep(&s_mem, ",");
if (p != NULL && *p != '\0') {
*members++ = p;
maxmembers--;
}
}
*members = NULL;
if (s_mem == NULL)
return (NS_SUCCESS);
else {
*errnop = ERANGE;
return (NS_RETURN);
}
}
diff --git a/lib/libc/gen/getmntinfo-compat11.c b/lib/libc/gen/getmntinfo-compat11.c
index 317be508eda2..a1ef069043c2 100644
--- a/lib/libc/gen/getmntinfo-compat11.c
+++ b/lib/libc/gen/getmntinfo-compat11.c
@@ -1,69 +1,68 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)getmntinfo.c 8.1 (Berkeley) 6/4/93
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ucred.h>
#define _WANT_FREEBSD11_STATFS
#include <sys/mount.h>
#include <stdlib.h>
#include "gen-compat.h"
/*
* Return information about mounted filesystems.
*/
int
freebsd11_getmntinfo(struct freebsd11_statfs **mntbufp, int flags)
{
static struct freebsd11_statfs *mntbuf;
static int mntsize;
static long bufsize;
if (mntsize <= 0 &&
(mntsize = freebsd11_getfsstat(0, 0, MNT_NOWAIT)) < 0)
return (0);
if (bufsize > 0 &&
(mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0)
return (0);
while (bufsize <= mntsize * sizeof(struct freebsd11_statfs)) {
if (mntbuf)
free(mntbuf);
bufsize = (mntsize + 1) * sizeof(struct freebsd11_statfs);
if ((mntbuf = (struct freebsd11_statfs *)malloc(bufsize)) == 0)
return (0);
if ((mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0)
return (0);
}
*mntbufp = mntbuf;
return (mntsize);
}
__sym_compat(getmntinfo, freebsd11_getmntinfo, FBSD_1.0);
diff --git a/lib/libc/gen/getpagesizes.c b/lib/libc/gen/getpagesizes.c
index 2cb4ebee0d0e..c9f7f2f29e16 100644
--- a/lib/libc/gen/getpagesizes.c
+++ b/lib/libc/gen/getpagesizes.c
@@ -1,85 +1,84 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 Alan L. Cox <alc@cs.rice.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <link.h>
#include "libc_private.h"
/*
* Retrieves page size information from the system. Specifically, returns the
* number of distinct page sizes that are supported by the system, if
* "pagesize" is NULL and "nelem" is 0. Otherwise, assigns up to "nelem" of
* the system-supported page sizes to consecutive elements of the array
* referenced by "pagesize", and returns the number of such page sizes that it
* assigned to the array. These page sizes are expressed in bytes.
*
* The implementation of this function does not directly or indirectly call
* malloc(3) or any other dynamic memory allocator that may itself call this
* function.
*/
int
getpagesizes(size_t pagesize[], int nelem)
{
static u_long ps[MAXPAGESIZES];
static int nops;
size_t size;
int error, i;
if (nelem < 0 || (nelem > 0 && pagesize == NULL)) {
errno = EINVAL;
return (-1);
}
/* Cache the result of the sysctl(2). */
if (nops == 0) {
error = _elf_aux_info(AT_PAGESIZES, ps, sizeof(ps));
size = sizeof(ps);
if (error != 0 || ps[0] == 0) {
if (sysctlbyname("hw.pagesizes", ps, &size, NULL, 0)
== -1)
return (-1);
}
/* Count the number of page sizes that are supported. */
nops = size / sizeof(ps[0]);
while (nops > 0 && ps[nops - 1] == 0)
nops--;
}
if (pagesize == NULL)
return (nops);
/* Return up to "nelem" page sizes from the cached result. */
if (nelem > nops)
nelem = nops;
for (i = 0; i < nelem; i++)
pagesize[i] = ps[i];
return (nelem);
}
diff --git a/lib/libc/gen/getpeereid.c b/lib/libc/gen/getpeereid.c
index b1934a6c471b..444dd2664cc4 100644
--- a/lib/libc/gen/getpeereid.c
+++ b/lib/libc/gen/getpeereid.c
@@ -1,58 +1,57 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Dima Dorfman.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/ucred.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>
#include "un-namespace.h"
int
getpeereid(int s, uid_t *euid, gid_t *egid)
{
struct xucred xuc;
socklen_t xuclen;
int error;
xuclen = sizeof(xuc);
error = _getsockopt(s, SOL_LOCAL, LOCAL_PEERCRED, &xuc, &xuclen);
if (error != 0)
return (error);
if (xuc.cr_version != XUCRED_VERSION) {
errno = EINVAL;
return (-1);
}
*euid = xuc.cr_uid;
*egid = xuc.cr_gid;
return (0);
}
diff --git a/lib/libc/gen/getprogname.c b/lib/libc/gen/getprogname.c
index 5b563534616b..54e59b6ac412 100644
--- a/lib/libc/gen/getprogname.c
+++ b/lib/libc/gen/getprogname.c
@@ -1,15 +1,14 @@
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdlib.h>
#include "un-namespace.h"
#include "libc_private.h"
__weak_reference(_getprogname, getprogname);
const char *
_getprogname(void)
{
return (__progname);
}
diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c
index e3c8098fad0d..1cbf97e7eb52 100644
--- a/lib/libc/gen/getpwent.c
+++ b/lib/libc/gen/getpwent.c
@@ -1,2002 +1,2001 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HESIOD
#include <hesiod.h>
#endif
#include <netdb.h>
#include <nsswitch.h>
#include <pthread.h>
#include <pthread_np.h>
#include <pwd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "un-namespace.h"
#include <db.h>
#include "libc_private.h"
#include "pw_scan.h"
#include "nss_tls.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
#ifndef CTASSERT
#define CTASSERT(x) _CTASSERT(x, __LINE__)
#define _CTASSERT(x, y) __CTASSERT(x, y)
#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1]
#endif
/* Counter as stored in /etc/pwd.db */
typedef int pwkeynum;
CTASSERT(MAXLOGNAME > sizeof(uid_t));
CTASSERT(MAXLOGNAME > sizeof(pwkeynum));
enum constants {
PWD_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
PWD_STORAGE_MAX = 1 << 20, /* 1 MByte */
SETPWENT = 1,
ENDPWENT = 2,
HESIOD_NAME_MAX = 256
};
static const ns_src defaultsrc[] = {
{ NSSRC_COMPAT, NS_SUCCESS },
{ NULL, 0 }
};
int __pw_match_entry(const char *, size_t, enum nss_lookup_type,
const char *, uid_t);
int __pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop);
union key {
const char *name;
uid_t uid;
};
static struct passwd *getpw(int (*fn)(union key, struct passwd *, char *,
size_t, struct passwd **), union key);
static int wrap_getpwnam_r(union key, struct passwd *, char *,
size_t, struct passwd **);
static int wrap_getpwuid_r(union key, struct passwd *, char *, size_t,
struct passwd **);
static int wrap_getpwent_r(union key, struct passwd *, char *, size_t,
struct passwd **);
static int pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type,
const char *, uid_t);
static int pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *);
static int pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type,
const char *, uid_t);
static int pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *);
struct {
int (*match)(char *, size_t, enum nss_lookup_type, const char *,
uid_t);
int (*parse)(char *, size_t, struct passwd *, int *);
} pwdb_versions[] = {
{ NULL, NULL }, /* version 0 */
{ NULL, NULL }, /* version 1 */
{ NULL, NULL }, /* version 2 */
{ pwdb_match_entry_v3, pwdb_parse_entry_v3 }, /* version 3 */
{ pwdb_match_entry_v4, pwdb_parse_entry_v4 }, /* version 4 */
};
struct files_state {
DB *db;
pwkeynum keynum;
int stayopen;
int version;
};
static void files_endstate(void *);
NSS_TLS_HANDLING(files);
static DB *pwdbopen(int *);
static void files_endstate(void *);
static int files_setpwent(void *, void *, va_list);
static int files_passwd(void *, void *, va_list);
#ifdef HESIOD
struct dns_state {
long counter;
};
static void dns_endstate(void *);
NSS_TLS_HANDLING(dns);
static int dns_setpwent(void *, void *, va_list);
static int dns_passwd(void *, void *, va_list);
#endif
#ifdef YP
struct nis_state {
char domain[MAXHOSTNAMELEN];
int done;
char *key;
int keylen;
};
static void nis_endstate(void *);
NSS_TLS_HANDLING(nis);
static int nis_setpwent(void *, void *, va_list);
static int nis_passwd(void *, void *, va_list);
static int nis_map(char *, enum nss_lookup_type, char *, size_t, int *);
static int nis_adjunct(char *, const char *, char *, size_t);
#endif
struct compat_state {
DB *db;
pwkeynum keynum;
int stayopen;
int version;
DB *exclude;
struct passwd template;
char *name;
enum _compat {
COMPAT_MODE_OFF = 0,
COMPAT_MODE_ALL,
COMPAT_MODE_NAME,
COMPAT_MODE_NETGROUP
} compat;
};
static void compat_endstate(void *);
NSS_TLS_HANDLING(compat);
static int compat_setpwent(void *, void *, va_list);
static int compat_passwd(void *, void *, va_list);
static void compat_clear_template(struct passwd *);
static int compat_set_template(struct passwd *, struct passwd *);
static int compat_use_template(struct passwd *, struct passwd *, char *,
size_t);
static int compat_redispatch(struct compat_state *, enum nss_lookup_type,
enum nss_lookup_type, const char *, const char *, uid_t,
struct passwd *, char *, size_t, int *);
#ifdef NS_CACHING
static int pwd_id_func(char *, size_t *, va_list ap, void *);
static int pwd_marshal_func(char *, size_t *, void *, va_list, void *);
static int pwd_unmarshal_func(char *, size_t, void *, va_list, void *);
static int
pwd_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
{
char *name;
uid_t uid;
size_t size, desired_size;
int res = NS_UNAVAIL;
enum nss_lookup_type lookup_type;
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
size = strlen(name);
desired_size = sizeof(enum nss_lookup_type) + size + 1;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
res = NS_SUCCESS;
break;
case nss_lt_id:
uid = va_arg(ap, uid_t);
desired_size = sizeof(enum nss_lookup_type) + sizeof(uid_t);
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), &uid,
sizeof(uid_t));
res = NS_SUCCESS;
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
fin:
*buffer_size = desired_size;
return (res);
}
static int
pwd_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
uid_t uid __unused;
struct passwd *pwd;
char *orig_buf __unused;
size_t orig_buf_size __unused;
struct passwd new_pwd;
size_t desired_size, size;
char *p;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
uid = va_arg(ap, uid_t);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
pwd = va_arg(ap, struct passwd *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
desired_size = sizeof(struct passwd) + sizeof(char *) +
strlen(pwd->pw_name) + 1;
if (pwd->pw_passwd != NULL)
desired_size += strlen(pwd->pw_passwd) + 1;
if (pwd->pw_class != NULL)
desired_size += strlen(pwd->pw_class) + 1;
if (pwd->pw_gecos != NULL)
desired_size += strlen(pwd->pw_gecos) + 1;
if (pwd->pw_dir != NULL)
desired_size += strlen(pwd->pw_dir) + 1;
if (pwd->pw_shell != NULL)
desired_size += strlen(pwd->pw_shell) + 1;
if (*buffer_size < desired_size) {
/* this assignment is here for future use */
*buffer_size = desired_size;
return (NS_RETURN);
}
memcpy(&new_pwd, pwd, sizeof(struct passwd));
memset(buffer, 0, desired_size);
*buffer_size = desired_size;
p = buffer + sizeof(struct passwd) + sizeof(char *);
memcpy(buffer + sizeof(struct passwd), &p, sizeof(char *));
if (new_pwd.pw_name != NULL) {
size = strlen(new_pwd.pw_name);
memcpy(p, new_pwd.pw_name, size);
new_pwd.pw_name = p;
p += size + 1;
}
if (new_pwd.pw_passwd != NULL) {
size = strlen(new_pwd.pw_passwd);
memcpy(p, new_pwd.pw_passwd, size);
new_pwd.pw_passwd = p;
p += size + 1;
}
if (new_pwd.pw_class != NULL) {
size = strlen(new_pwd.pw_class);
memcpy(p, new_pwd.pw_class, size);
new_pwd.pw_class = p;
p += size + 1;
}
if (new_pwd.pw_gecos != NULL) {
size = strlen(new_pwd.pw_gecos);
memcpy(p, new_pwd.pw_gecos, size);
new_pwd.pw_gecos = p;
p += size + 1;
}
if (new_pwd.pw_dir != NULL) {
size = strlen(new_pwd.pw_dir);
memcpy(p, new_pwd.pw_dir, size);
new_pwd.pw_dir = p;
p += size + 1;
}
if (new_pwd.pw_shell != NULL) {
size = strlen(new_pwd.pw_shell);
memcpy(p, new_pwd.pw_shell, size);
new_pwd.pw_shell = p;
p += size + 1;
}
memcpy(buffer, &new_pwd, sizeof(struct passwd));
return (NS_SUCCESS);
}
static int
pwd_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
uid_t uid __unused;
struct passwd *pwd;
char *orig_buf;
size_t orig_buf_size;
int *ret_errno;
char *p;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
uid = va_arg(ap, uid_t);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
pwd = va_arg(ap, struct passwd *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
ret_errno = va_arg(ap, int *);
if (orig_buf_size + sizeof(struct passwd) + sizeof(char *) <
buffer_size) {
*ret_errno = ERANGE;
return (NS_RETURN);
} else if (buffer_size < sizeof(struct passwd) + sizeof(char *)) {
/*
* nscd(8) sometimes returns buffer_size=1 for nonexistent
* entries.
*/
*ret_errno = 0;
return (NS_NOTFOUND);
}
memcpy(pwd, buffer, sizeof(struct passwd));
memcpy(&p, buffer + sizeof(struct passwd), sizeof(char *));
memcpy(orig_buf, buffer + sizeof(struct passwd) + sizeof(char *),
buffer_size - sizeof(struct passwd) - sizeof(char *));
NS_APPLY_OFFSET(pwd->pw_name, orig_buf, p, char *);
NS_APPLY_OFFSET(pwd->pw_passwd, orig_buf, p, char *);
NS_APPLY_OFFSET(pwd->pw_class, orig_buf, p, char *);
NS_APPLY_OFFSET(pwd->pw_gecos, orig_buf, p, char *);
NS_APPLY_OFFSET(pwd->pw_dir, orig_buf, p, char *);
NS_APPLY_OFFSET(pwd->pw_shell, orig_buf, p, char *);
if (retval != NULL)
*((struct passwd **)retval) = pwd;
return (NS_SUCCESS);
}
NSS_MP_CACHE_HANDLING(passwd);
#endif /* NS_CACHING */
void
setpwent(void)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
passwd, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
#ifdef HESIOD
{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
#endif
#ifdef YP
{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
#endif
{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0);
}
int
setpassent(int stayopen)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
passwd, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setpwent, (void *)SETPWENT },
#ifdef HESIOD
{ NSSRC_DNS, dns_setpwent, (void *)SETPWENT },
#endif
#ifdef YP
{ NSSRC_NIS, nis_setpwent, (void *)SETPWENT },
#endif
{ NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc,
stayopen);
return (1);
}
void
endpwent(void)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
passwd, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setpwent, (void *)ENDPWENT },
#ifdef HESIOD
{ NSSRC_DNS, dns_setpwent, (void *)ENDPWENT },
#endif
#ifdef YP
{ NSSRC_NIS, nis_setpwent, (void *)ENDPWENT },
#endif
{ NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc);
}
int
getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
struct passwd **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
passwd, (void *)nss_lt_all,
pwd_marshal_func, pwd_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_passwd, (void *)nss_lt_all },
#ifdef HESIOD
{ NSSRC_DNS, dns_passwd, (void *)nss_lt_all },
#endif
#ifdef YP
{ NSSRC_NIS, nis_passwd, (void *)nss_lt_all },
#endif
{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
__pw_initpwd(pwd);
ret_errno = 0;
*result = NULL;
rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc,
pwd, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
int
getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize,
struct passwd **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
passwd, (void *)nss_lt_name,
pwd_id_func, pwd_marshal_func, pwd_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_passwd, (void *)nss_lt_name },
#ifdef HESIOD
{ NSSRC_DNS, dns_passwd, (void *)nss_lt_name },
#endif
#ifdef YP
{ NSSRC_NIS, nis_passwd, (void *)nss_lt_name },
#endif
{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
__pw_initpwd(pwd);
ret_errno = 0;
*result = NULL;
rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc,
name, pwd, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
int
getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize,
struct passwd **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
passwd, (void *)nss_lt_id,
pwd_id_func, pwd_marshal_func, pwd_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_passwd, (void *)nss_lt_id },
#ifdef HESIOD
{ NSSRC_DNS, dns_passwd, (void *)nss_lt_id },
#endif
#ifdef YP
{ NSSRC_NIS, nis_passwd, (void *)nss_lt_id },
#endif
{ NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
__pw_initpwd(pwd);
ret_errno = 0;
*result = NULL;
rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc,
uid, pwd, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
static struct passwd pwd;
static char *pwd_storage;
static size_t pwd_storage_size;
static struct passwd *
getpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **),
union key key)
{
int rv;
struct passwd *res;
if (pwd_storage == NULL) {
pwd_storage = malloc(PWD_STORAGE_INITIAL);
if (pwd_storage == NULL)
return (NULL);
pwd_storage_size = PWD_STORAGE_INITIAL;
}
do {
rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res);
if (res == NULL && rv == ERANGE) {
free(pwd_storage);
if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) {
pwd_storage = NULL;
errno = ERANGE;
return (NULL);
}
pwd_storage_size <<= 1;
pwd_storage = malloc(pwd_storage_size);
if (pwd_storage == NULL)
return (NULL);
}
} while (res == NULL && rv == ERANGE);
if (rv != 0)
errno = rv;
return (res);
}
static int
wrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer,
size_t bufsize, struct passwd **res)
{
return (getpwnam_r(key.name, pwd, buffer, bufsize, res));
}
static int
wrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer,
size_t bufsize, struct passwd **res)
{
return (getpwuid_r(key.uid, pwd, buffer, bufsize, res));
}
static int
wrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer,
size_t bufsize, struct passwd **res)
{
return (getpwent_r(pwd, buffer, bufsize, res));
}
struct passwd *
getpwnam(const char *name)
{
union key key;
key.name = name;
return (getpw(wrap_getpwnam_r, key));
}
struct passwd *
getpwuid(uid_t uid)
{
union key key;
key.uid = uid;
return (getpw(wrap_getpwuid_r, key));
}
struct passwd *
getpwent(void)
{
union key key;
key.uid = 0; /* not used */
return (getpw(wrap_getpwent_r, key));
}
/*
* files backend
*/
static DB *
pwdbopen(int *version)
{
DB *res;
DBT key, entry;
int rv;
if (geteuid() != 0 ||
(res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL)
res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL);
if (res == NULL)
return (NULL);
key.data = _PWD_VERSION_KEY;
key.size = strlen(_PWD_VERSION_KEY);
rv = res->get(res, &key, &entry, 0);
if (rv == 0)
*version = *(unsigned char *)entry.data;
else
*version = 3;
if (*version < 3 ||
*version >= nitems(pwdb_versions)) {
syslog(LOG_CRIT, "Unsupported password database version %d",
*version);
res->close(res);
res = NULL;
}
return (res);
}
static void
files_endstate(void *p)
{
DB *db;
if (p == NULL)
return;
db = ((struct files_state *)p)->db;
if (db != NULL)
db->close(db);
free(p);
}
static int
files_setpwent(void *retval, void *mdata, va_list ap)
{
struct files_state *st;
int rv, stayopen;
rv = files_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata) {
case SETPWENT:
stayopen = va_arg(ap, int);
st->keynum = 0;
if (stayopen)
st->db = pwdbopen(&st->version);
st->stayopen = stayopen;
break;
case ENDPWENT:
if (st->db != NULL) {
(void)st->db->close(st->db);
st->db = NULL;
}
break;
default:
break;
}
return (NS_UNAVAIL);
}
static int
files_passwd(void *retval, void *mdata, va_list ap)
{
char keybuf[MAXLOGNAME + 1];
DBT key, entry;
struct files_state *st;
enum nss_lookup_type how;
const char *name;
struct passwd *pwd;
char *buffer;
size_t bufsize, namesize;
uid_t uid;
uint32_t store;
int rv, stayopen = 0, *errnop;
name = NULL;
uid = (uid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
keybuf[0] = _PW_KEYBYNAME;
break;
case nss_lt_id:
uid = va_arg(ap, uid_t);
keybuf[0] = _PW_KEYBYUID;
break;
case nss_lt_all:
keybuf[0] = _PW_KEYBYNUM;
break;
default:
rv = NS_NOTFOUND;
goto fin;
}
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = files_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (how == nss_lt_all && st->keynum < 0) {
rv = NS_NOTFOUND;
goto fin;
}
if (st->db == NULL &&
(st->db = pwdbopen(&st->version)) == NULL) {
*errnop = errno;
rv = NS_UNAVAIL;
goto fin;
}
if (how == nss_lt_all)
stayopen = 1;
else
stayopen = st->stayopen;
key.data = keybuf;
do {
switch (how) {
case nss_lt_name:
/* MAXLOGNAME includes NUL byte, but we do not
* include the NUL byte in the key.
*/
namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1);
if (namesize >= sizeof(keybuf)-1) {
*errnop = EINVAL;
rv = NS_NOTFOUND;
goto fin;
}
key.size = namesize + 1;
break;
case nss_lt_id:
if (st->version < _PWD_CURRENT_VERSION) {
memcpy(&keybuf[1], &uid, sizeof(uid));
key.size = sizeof(uid) + 1;
} else {
store = htonl(uid);
memcpy(&keybuf[1], &store, sizeof(store));
key.size = sizeof(store) + 1;
}
break;
case nss_lt_all:
st->keynum++;
if (st->version < _PWD_CURRENT_VERSION) {
memcpy(&keybuf[1], &st->keynum,
sizeof(st->keynum));
key.size = sizeof(st->keynum) + 1;
} else {
store = htonl(st->keynum);
memcpy(&keybuf[1], &store, sizeof(store));
key.size = sizeof(store) + 1;
}
break;
}
keybuf[0] = _PW_VERSIONED(keybuf[0], st->version);
rv = st->db->get(st->db, &key, &entry, 0);
if (rv < 0 || rv > 1) { /* should never return > 1 */
*errnop = errno;
rv = NS_UNAVAIL;
goto fin;
} else if (rv == 1) {
if (how == nss_lt_all)
st->keynum = -1;
rv = NS_NOTFOUND;
goto fin;
}
rv = pwdb_versions[st->version].match(entry.data, entry.size,
how, name, uid);
if (rv != NS_SUCCESS)
continue;
if (entry.size > bufsize) {
*errnop = ERANGE;
rv = NS_RETURN;
break;
}
memcpy(buffer, entry.data, entry.size);
rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
errnop);
} while (how == nss_lt_all && !(rv & NS_TERMINATE));
fin:
if (st->db != NULL && !stayopen) {
(void)st->db->close(st->db);
st->db = NULL;
}
if (rv == NS_SUCCESS) {
pwd->pw_fields &= ~_PWF_SOURCE;
pwd->pw_fields |= _PWF_FILES;
if (retval != NULL)
*(struct passwd **)retval = pwd;
}
return (rv);
}
static int
pwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how,
const char *name, uid_t uid)
{
const char *p, *eom;
uid_t uid2;
eom = &entry[entrysize];
for (p = entry; p < eom; p++)
if (*p == '\0')
break;
if (*p != '\0')
return (NS_NOTFOUND);
if (how == nss_lt_all)
return (NS_SUCCESS);
if (how == nss_lt_name)
return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
for (p++; p < eom; p++)
if (*p == '\0')
break;
if (*p != '\0' || (++p) + sizeof(uid) >= eom)
return (NS_NOTFOUND);
memcpy(&uid2, p, sizeof(uid2));
return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND);
}
static int
pwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd,
int *errnop)
{
char *p, *eom;
int32_t pw_change, pw_expire;
/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
p = buffer;
eom = &buffer[bufsize];
#define STRING(field) do { \
(field) = p; \
while (p < eom && *p != '\0') \
p++; \
if (p >= eom) \
return (NS_NOTFOUND); \
p++; \
} while (0)
#define SCALAR(field) do { \
if (p + sizeof(field) > eom) \
return (NS_NOTFOUND); \
memcpy(&(field), p, sizeof(field)); \
p += sizeof(field); \
} while (0)
STRING(pwd->pw_name);
STRING(pwd->pw_passwd);
SCALAR(pwd->pw_uid);
SCALAR(pwd->pw_gid);
SCALAR(pw_change);
STRING(pwd->pw_class);
STRING(pwd->pw_gecos);
STRING(pwd->pw_dir);
STRING(pwd->pw_shell);
SCALAR(pw_expire);
SCALAR(pwd->pw_fields);
#undef STRING
#undef SCALAR
pwd->pw_change = pw_change;
pwd->pw_expire = pw_expire;
return (NS_SUCCESS);
}
static int
pwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how,
const char *name, uid_t uid)
{
const char *p, *eom;
uint32_t uid2;
eom = &entry[entrysize];
for (p = entry; p < eom; p++)
if (*p == '\0')
break;
if (*p != '\0')
return (NS_NOTFOUND);
if (how == nss_lt_all)
return (NS_SUCCESS);
if (how == nss_lt_name)
return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND);
for (p++; p < eom; p++)
if (*p == '\0')
break;
if (*p != '\0' || (++p) + sizeof(uid) >= eom)
return (NS_NOTFOUND);
memcpy(&uid2, p, sizeof(uid2));
uid2 = ntohl(uid2);
return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND);
}
static int
pwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd,
int *errnop)
{
char *p, *eom;
uint32_t n;
/* THIS CODE MUST MATCH THAT IN pwd_mkdb. */
p = buffer;
eom = &buffer[bufsize];
#define STRING(field) do { \
(field) = p; \
while (p < eom && *p != '\0') \
p++; \
if (p >= eom) \
return (NS_NOTFOUND); \
p++; \
} while (0)
#define SCALAR(field) do { \
if (p + sizeof(n) > eom) \
return (NS_NOTFOUND); \
memcpy(&n, p, sizeof(n)); \
(field) = ntohl(n); \
p += sizeof(n); \
} while (0)
STRING(pwd->pw_name);
STRING(pwd->pw_passwd);
SCALAR(pwd->pw_uid);
SCALAR(pwd->pw_gid);
SCALAR(pwd->pw_change);
STRING(pwd->pw_class);
STRING(pwd->pw_gecos);
STRING(pwd->pw_dir);
STRING(pwd->pw_shell);
SCALAR(pwd->pw_expire);
SCALAR(pwd->pw_fields);
#undef STRING
#undef SCALAR
return (NS_SUCCESS);
}
#ifdef HESIOD
/*
* dns backend
*/
static void
dns_endstate(void *p)
{
free(p);
}
static int
dns_setpwent(void *retval, void *mdata, va_list ap)
{
struct dns_state *st;
int rv;
rv = dns_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
st->counter = 0;
return (NS_UNAVAIL);
}
static int
dns_passwd(void *retval, void *mdata, va_list ap)
{
char buf[HESIOD_NAME_MAX];
struct dns_state *st;
struct passwd *pwd;
const char *name, *label;
void *ctx;
char *buffer, **hes;
size_t bufsize, linesize;
uid_t uid;
enum nss_lookup_type how;
int rv, *errnop;
ctx = NULL;
hes = NULL;
name = NULL;
uid = (uid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
break;
case nss_lt_id:
uid = va_arg(ap, uid_t);
break;
case nss_lt_all:
break;
}
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = dns_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (hesiod_init(&ctx) != 0) {
*errnop = errno;
rv = NS_UNAVAIL;
goto fin;
}
do {
rv = NS_NOTFOUND;
switch (how) {
case nss_lt_name:
label = name;
break;
case nss_lt_id:
if (snprintf(buf, sizeof(buf), "%lu",
(unsigned long)uid) >= sizeof(buf))
goto fin;
label = buf;
break;
case nss_lt_all:
if (st->counter < 0)
goto fin;
if (snprintf(buf, sizeof(buf), "passwd-%ld",
st->counter++) >= sizeof(buf))
goto fin;
label = buf;
break;
}
hes = hesiod_resolve(ctx, label,
how == nss_lt_id ? "uid" : "passwd");
if (hes == NULL) {
if (how == nss_lt_all)
st->counter = -1;
if (errno != ENOENT)
*errnop = errno;
goto fin;
}
rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid);
if (rv != NS_SUCCESS) {
hesiod_free_list(ctx, hes);
hes = NULL;
continue;
}
linesize = strlcpy(buffer, hes[0], bufsize);
if (linesize >= bufsize) {
*errnop = ERANGE;
rv = NS_RETURN;
continue;
}
hesiod_free_list(ctx, hes);
hes = NULL;
rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop);
} while (how == nss_lt_all && !(rv & NS_TERMINATE));
fin:
if (hes != NULL)
hesiod_free_list(ctx, hes);
if (ctx != NULL)
hesiod_end(ctx);
if (rv == NS_SUCCESS) {
pwd->pw_fields &= ~_PWF_SOURCE;
pwd->pw_fields |= _PWF_HESIOD;
if (retval != NULL)
*(struct passwd **)retval = pwd;
}
return (rv);
}
#endif /* HESIOD */
#ifdef YP
/*
* nis backend
*/
static void
nis_endstate(void *p)
{
free(((struct nis_state *)p)->key);
free(p);
}
/*
* Test for the presence of special FreeBSD-specific master.passwd.by*
* maps. We do this using yp_order(). If it fails, then either the server
* doesn't have the map, or the YPPROC_ORDER procedure isn't supported by
* the server (Sun NIS+ servers in YP compat mode behave this way). If
* the master.passwd.by* maps don't exist, then let the lookup routine try
* the regular passwd.by* maps instead. If the lookup routine fails, it
* can return an error as needed.
*/
static int
nis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize,
int *master)
{
int rv, order;
*master = 0;
if (geteuid() == 0) {
if (snprintf(buffer, bufsize, "master.passwd.by%s",
(how == nss_lt_id) ? "uid" : "name") >= bufsize)
return (NS_UNAVAIL);
rv = yp_order(domain, buffer, &order);
if (rv == 0) {
*master = 1;
return (NS_SUCCESS);
}
}
if (snprintf(buffer, bufsize, "passwd.by%s",
(how == nss_lt_id) ? "uid" : "name") >= bufsize)
return (NS_UNAVAIL);
return (NS_SUCCESS);
}
static int
nis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize)
{
int rv;
char *result, *p, *q, *eor;
int resultlen;
result = NULL;
rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name),
&result, &resultlen);
if (rv != 0)
rv = 1;
else {
eor = &result[resultlen];
p = memchr(result, ':', eor - result);
if (p != NULL && ++p < eor &&
(q = memchr(p, ':', eor - p)) != NULL) {
if (q - p >= bufsize)
rv = -1;
else {
memcpy(buffer, p, q - p);
buffer[q - p] ='\0';
}
} else
rv = 1;
}
free(result);
return (rv);
}
static int
nis_setpwent(void *retval, void *mdata, va_list ap)
{
struct nis_state *st;
int rv;
rv = nis_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
st->done = 0;
free(st->key);
st->key = NULL;
return (NS_UNAVAIL);
}
static int
nis_passwd(void *retval, void *mdata, va_list ap)
{
char map[YPMAXMAP];
struct nis_state *st;
struct passwd *pwd;
const char *name;
char *buffer, *key, *result;
size_t bufsize;
uid_t uid;
enum nss_lookup_type how;
int *errnop, keylen, resultlen, rv, master;
name = NULL;
uid = (uid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
break;
case nss_lt_id:
uid = va_arg(ap, uid_t);
break;
case nss_lt_all:
break;
}
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = nis_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->domain[0] == '\0') {
if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
*errnop = errno;
return (NS_UNAVAIL);
}
}
rv = nis_map(st->domain, how, map, sizeof(map), &master);
if (rv != NS_SUCCESS)
return (rv);
result = NULL;
do {
rv = NS_NOTFOUND;
switch (how) {
case nss_lt_name:
if (strlcpy(buffer, name, bufsize) >= bufsize)
goto erange;
break;
case nss_lt_id:
if (snprintf(buffer, bufsize, "%lu",
(unsigned long)uid) >= bufsize)
goto erange;
break;
case nss_lt_all:
if (st->done)
goto fin;
break;
}
result = NULL;
if (how == nss_lt_all) {
if (st->key == NULL)
rv = yp_first(st->domain, map, &st->key,
&st->keylen, &result, &resultlen);
else {
key = st->key;
keylen = st->keylen;
st->key = NULL;
rv = yp_next(st->domain, map, key, keylen,
&st->key, &st->keylen, &result,
&resultlen);
free(key);
}
if (rv != 0) {
free(result);
free(st->key);
st->key = NULL;
if (rv == YPERR_NOMORE)
st->done = 1;
else
rv = NS_UNAVAIL;
goto fin;
}
} else {
rv = yp_match(st->domain, map, buffer, strlen(buffer),
&result, &resultlen);
if (rv == YPERR_KEY) {
rv = NS_NOTFOUND;
continue;
} else if (rv != 0) {
free(result);
rv = NS_UNAVAIL;
continue;
}
}
if (resultlen >= bufsize) {
free(result);
goto erange;
}
memcpy(buffer, result, resultlen);
buffer[resultlen] = '\0';
free(result);
rv = __pw_match_entry(buffer, resultlen, how, name, uid);
if (rv == NS_SUCCESS)
rv = __pw_parse_entry(buffer, resultlen, pwd, master,
errnop);
} while (how == nss_lt_all && !(rv & NS_TERMINATE));
fin:
if (rv == NS_SUCCESS) {
if (strstr(pwd->pw_passwd, "##") != NULL) {
rv = nis_adjunct(st->domain, pwd->pw_name,
&buffer[resultlen+1], bufsize-resultlen-1);
if (rv < 0)
goto erange;
else if (rv == 0)
pwd->pw_passwd = &buffer[resultlen+1];
}
pwd->pw_fields &= ~_PWF_SOURCE;
pwd->pw_fields |= _PWF_NIS;
if (retval != NULL)
*(struct passwd **)retval = pwd;
rv = NS_SUCCESS;
}
return (rv);
erange:
*errnop = ERANGE;
return (NS_RETURN);
}
#endif /* YP */
/*
* compat backend
*/
static void
compat_clear_template(struct passwd *template)
{
free(template->pw_passwd);
free(template->pw_gecos);
free(template->pw_dir);
free(template->pw_shell);
memset(template, 0, sizeof(*template));
}
static int
compat_set_template(struct passwd *src, struct passwd *template)
{
compat_clear_template(template);
#ifdef PW_OVERRIDE_PASSWD
if ((src->pw_fields & _PWF_PASSWD) &&
(template->pw_passwd = strdup(src->pw_passwd)) == NULL)
goto enomem;
#endif
if (src->pw_fields & _PWF_UID)
template->pw_uid = src->pw_uid;
if (src->pw_fields & _PWF_GID)
template->pw_gid = src->pw_gid;
if ((src->pw_fields & _PWF_GECOS) &&
(template->pw_gecos = strdup(src->pw_gecos)) == NULL)
goto enomem;
if ((src->pw_fields & _PWF_DIR) &&
(template->pw_dir = strdup(src->pw_dir)) == NULL)
goto enomem;
if ((src->pw_fields & _PWF_SHELL) &&
(template->pw_shell = strdup(src->pw_shell)) == NULL)
goto enomem;
template->pw_fields = src->pw_fields;
return (0);
enomem:
syslog(LOG_ERR, "getpwent memory allocation failure");
return (-1);
}
static int
compat_use_template(struct passwd *pwd, struct passwd *template, char *buffer,
size_t bufsize)
{
struct passwd hold;
char *copy, *p, *q, *eob;
size_t n;
/* We cannot know the layout of the password fields in `buffer',
* so we have to copy everything.
*/
if (template->pw_fields == 0) /* nothing to fill-in */
return (0);
n = 0;
n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0;
n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0;
n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0;
n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0;
n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0;
n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0;
copy = malloc(n);
if (copy == NULL) {
syslog(LOG_ERR, "getpwent memory allocation failure");
return (ENOMEM);
}
p = copy;
eob = &copy[n];
#define COPY(field) do { \
if (pwd->field == NULL) \
hold.field = NULL; \
else { \
hold.field = p; \
p += strlcpy(p, pwd->field, eob-p) + 1; \
} \
} while (0)
COPY(pw_name);
COPY(pw_passwd);
COPY(pw_class);
COPY(pw_gecos);
COPY(pw_dir);
COPY(pw_shell);
#undef COPY
p = buffer;
eob = &buffer[bufsize];
#define COPY(field, flag) do { \
q = (template->pw_fields & flag) ? template->field : hold.field; \
if (q == NULL) \
pwd->field = NULL; \
else { \
pwd->field = p; \
if ((n = strlcpy(p, q, eob-p)) >= eob-p) { \
free(copy); \
return (ERANGE); \
} \
p += n + 1; \
} \
} while (0)
COPY(pw_name, 0);
#ifdef PW_OVERRIDE_PASSWD
COPY(pw_passwd, _PWF_PASSWD);
#else
COPY(pw_passwd, 0);
#endif
COPY(pw_class, 0);
COPY(pw_gecos, _PWF_GECOS);
COPY(pw_dir, _PWF_DIR);
COPY(pw_shell, _PWF_SHELL);
#undef COPY
#define COPY(field, flag) do { \
if (template->pw_fields & flag) \
pwd->field = template->field; \
} while (0)
COPY(pw_uid, _PWF_UID);
COPY(pw_gid, _PWF_GID);
#undef COPY
free(copy);
return (0);
}
static int
compat_exclude(const char *name, DB **db)
{
DBT key, data;
if (*db == NULL &&
(*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL)
return (errno);
key.size = strlen(name);
key.data = (char *)name;
data.size = 0;
data.data = NULL;
if ((*db)->put(*db, &key, &data, 0) == -1)
return (errno);
return (0);
}
static int
compat_is_excluded(const char *name, DB *db)
{
DBT key, data;
if (db == NULL)
return (0);
key.size = strlen(name);
key.data = (char *)name;
return (db->get(db, &key, &data, 0) == 0);
}
static int
compat_redispatch(struct compat_state *st, enum nss_lookup_type how,
enum nss_lookup_type lookup_how, const char *name, const char *lookup_name,
uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop)
{
static const ns_src compatsrc[] = {
#ifdef YP
{ NSSRC_NIS, NS_SUCCESS },
#endif
{ NULL, 0 }
};
ns_dtab dtab[] = {
#ifdef YP
{ NSSRC_NIS, nis_passwd, NULL },
#endif
#ifdef HESIOD
{ NSSRC_DNS, dns_passwd, NULL },
#endif
{ NULL, NULL, NULL }
};
void *discard;
int e, i, rv;
for (i = 0; i < (int)(nitems(dtab) - 1); i++)
dtab[i].mdata = (void *)lookup_how;
more:
__pw_initpwd(pwd);
switch (lookup_how) {
case nss_lt_all:
rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
"getpwent_r", compatsrc, pwd, buffer, bufsize,
errnop);
break;
case nss_lt_id:
rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
"getpwuid_r", compatsrc, uid, pwd, buffer,
bufsize, errnop);
break;
case nss_lt_name:
rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT,
"getpwnam_r", compatsrc, lookup_name, pwd, buffer,
bufsize, errnop);
break;
default:
return (NS_UNAVAIL);
}
if (rv != NS_SUCCESS)
return (rv);
if (compat_is_excluded(pwd->pw_name, st->exclude)) {
if (how == nss_lt_all)
goto more;
return (NS_NOTFOUND);
}
e = compat_use_template(pwd, &st->template, buffer, bufsize);
if (e != 0) {
*errnop = e;
if (e == ERANGE)
return (NS_RETURN);
else
return (NS_UNAVAIL);
}
switch (how) {
case nss_lt_name:
if (strcmp(name, pwd->pw_name) != 0)
return (NS_NOTFOUND);
break;
case nss_lt_id:
if (uid != pwd->pw_uid)
return (NS_NOTFOUND);
break;
default:
break;
}
return (NS_SUCCESS);
}
static void
compat_endstate(void *p)
{
struct compat_state *st;
if (p == NULL)
return;
st = (struct compat_state *)p;
if (st->db != NULL)
st->db->close(st->db);
if (st->exclude != NULL)
st->exclude->close(st->exclude);
compat_clear_template(&st->template);
free(p);
}
static int
compat_setpwent(void *retval, void *mdata, va_list ap)
{
static const ns_src compatsrc[] = {
#ifdef YP
{ NSSRC_NIS, NS_SUCCESS },
#endif
{ NULL, 0 }
};
ns_dtab dtab[] = {
#ifdef YP
{ NSSRC_NIS, nis_setpwent, NULL },
#endif
#ifdef HESIOD
{ NSSRC_DNS, dns_setpwent, NULL },
#endif
{ NULL, NULL, NULL }
};
struct compat_state *st;
int rv, stayopen;
#define set_setent(x, y) do { \
int i; \
for (i = 0; i < (int)(nitems(x) - 1); i++) \
x[i].mdata = (void *)y; \
} while (0)
rv = compat_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata) {
case SETPWENT:
stayopen = va_arg(ap, int);
st->keynum = 0;
if (stayopen)
st->db = pwdbopen(&st->version);
st->stayopen = stayopen;
set_setent(dtab, mdata);
(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent",
compatsrc, 0);
break;
case ENDPWENT:
if (st->db != NULL) {
(void)st->db->close(st->db);
st->db = NULL;
}
set_setent(dtab, mdata);
(void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent",
compatsrc, 0);
break;
default:
break;
}
return (NS_UNAVAIL);
#undef set_setent
}
static int
compat_passwd(void *retval, void *mdata, va_list ap)
{
char keybuf[MAXLOGNAME + 1];
DBT key, entry;
pwkeynum keynum;
struct compat_state *st;
enum nss_lookup_type how;
const char *name;
struct passwd *pwd;
char *buffer, *pw_name;
char *host, *user, *domain;
size_t bufsize;
uid_t uid;
uint32_t store;
int rv, from_compat, stayopen, *errnop;
from_compat = 0;
name = NULL;
uid = (uid_t)-1;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, const char *);
break;
case nss_lt_id:
uid = va_arg(ap, uid_t);
break;
case nss_lt_all:
break;
default:
rv = NS_NOTFOUND;
goto fin;
}
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = compat_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (how == nss_lt_all && st->keynum < 0) {
rv = NS_NOTFOUND;
goto fin;
}
if (st->db == NULL &&
(st->db = pwdbopen(&st->version)) == NULL) {
*errnop = errno;
rv = NS_UNAVAIL;
goto fin;
}
if (how == nss_lt_all) {
if (st->keynum < 0) {
rv = NS_NOTFOUND;
goto fin;
}
keynum = st->keynum;
stayopen = 1;
} else {
keynum = 0;
stayopen = st->stayopen;
}
docompat:
rv = NS_NOTFOUND;
switch (st->compat) {
case COMPAT_MODE_ALL:
rv = compat_redispatch(st, how, how, name, name, uid, pwd,
buffer, bufsize, errnop);
if (rv != NS_SUCCESS)
st->compat = COMPAT_MODE_OFF;
break;
case COMPAT_MODE_NETGROUP:
/* XXX getnetgrent is not thread-safe. */
do {
rv = getnetgrent(&host, &user, &domain);
if (rv == 0) {
endnetgrent();
st->compat = COMPAT_MODE_OFF;
rv = NS_NOTFOUND;
continue;
} else if (user == NULL || user[0] == '\0')
continue;
rv = compat_redispatch(st, how, nss_lt_name, name,
user, uid, pwd, buffer, bufsize, errnop);
} while (st->compat == COMPAT_MODE_NETGROUP &&
!(rv & NS_TERMINATE));
break;
case COMPAT_MODE_NAME:
rv = compat_redispatch(st, how, nss_lt_name, name, st->name,
uid, pwd, buffer, bufsize, errnop);
free(st->name);
st->name = NULL;
st->compat = COMPAT_MODE_OFF;
break;
default:
break;
}
if (rv & NS_TERMINATE) {
from_compat = 1;
goto fin;
}
key.data = keybuf;
rv = NS_NOTFOUND;
while (keynum >= 0) {
keynum++;
if (st->version < _PWD_CURRENT_VERSION) {
memcpy(&keybuf[1], &keynum, sizeof(keynum));
key.size = sizeof(keynum) + 1;
} else {
store = htonl(keynum);
memcpy(&keybuf[1], &store, sizeof(store));
key.size = sizeof(store) + 1;
}
keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version);
rv = st->db->get(st->db, &key, &entry, 0);
if (rv < 0 || rv > 1) { /* should never return > 1 */
*errnop = errno;
rv = NS_UNAVAIL;
goto fin;
} else if (rv == 1) {
keynum = -1;
rv = NS_NOTFOUND;
goto fin;
}
pw_name = (char *)entry.data;
switch (pw_name[0]) {
case '+':
switch (pw_name[1]) {
case '\0':
st->compat = COMPAT_MODE_ALL;
break;
case '@':
setnetgrent(&pw_name[2]);
st->compat = COMPAT_MODE_NETGROUP;
break;
default:
st->name = strdup(&pw_name[1]);
if (st->name == NULL) {
syslog(LOG_ERR,
"getpwent memory allocation failure");
*errnop = ENOMEM;
rv = NS_UNAVAIL;
break;
}
st->compat = COMPAT_MODE_NAME;
}
if (entry.size > bufsize) {
*errnop = ERANGE;
rv = NS_RETURN;
goto fin;
}
memcpy(buffer, entry.data, entry.size);
rv = pwdb_versions[st->version].parse(buffer,
entry.size, pwd, errnop);
if (rv != NS_SUCCESS)
;
else if (compat_set_template(pwd, &st->template) < 0) {
*errnop = ENOMEM;
rv = NS_UNAVAIL;
goto fin;
}
goto docompat;
case '-':
switch (pw_name[1]) {
case '\0':
/* XXX Maybe syslog warning */
continue;
case '@':
setnetgrent(&pw_name[2]);
while (getnetgrent(&host, &user, &domain) !=
0) {
if (user != NULL && user[0] != '\0')
compat_exclude(user,
&st->exclude);
}
endnetgrent();
continue;
default:
compat_exclude(&pw_name[1], &st->exclude);
continue;
}
break;
default:
break;
}
if (compat_is_excluded((char *)entry.data, st->exclude))
continue;
rv = pwdb_versions[st->version].match(entry.data, entry.size,
how, name, uid);
if (rv == NS_RETURN)
break;
else if (rv != NS_SUCCESS)
continue;
if (entry.size > bufsize) {
*errnop = ERANGE;
rv = NS_RETURN;
break;
}
memcpy(buffer, entry.data, entry.size);
rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd,
errnop);
if (rv & NS_TERMINATE)
break;
}
fin:
if (how == nss_lt_all)
st->keynum = keynum;
if (st->db != NULL && !stayopen) {
(void)st->db->close(st->db);
st->db = NULL;
}
if (rv == NS_SUCCESS) {
if (!from_compat) {
pwd->pw_fields &= ~_PWF_SOURCE;
pwd->pw_fields |= _PWF_FILES;
}
if (retval != NULL)
*(struct passwd **)retval = pwd;
}
return (rv);
}
/*
* common passwd line matching and parsing
*/
int
__pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how,
const char *name, uid_t uid)
{
const char *p, *eom;
char *q;
size_t len;
unsigned long m;
eom = entry + entrysize;
for (p = entry; p < eom; p++)
if (*p == ':')
break;
if (*p != ':')
return (NS_NOTFOUND);
if (how == nss_lt_all)
return (NS_SUCCESS);
if (how == nss_lt_name) {
len = strlen(name);
if (len == (p - entry) && memcmp(name, entry, len) == 0)
return (NS_SUCCESS);
else
return (NS_NOTFOUND);
}
for (p++; p < eom; p++)
if (*p == ':')
break;
if (*p != ':')
return (NS_NOTFOUND);
m = strtoul(++p, &q, 10);
if (q[0] != ':' || (uid_t)m != uid)
return (NS_NOTFOUND);
else
return (NS_SUCCESS);
}
/* XXX buffer must be NUL-terminated. errnop is not set correctly. */
int
__pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd,
int master, int *errnop __unused)
{
if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0)
return (NS_NOTFOUND);
else
return (NS_SUCCESS);
}
diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c
index 94a20592c1bb..d0c307538930 100644
--- a/lib/libc/gen/getutxent.c
+++ b/lib/libc/gen/getutxent.c
@@ -1,241 +1,240 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/endian.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <utmpx.h>
#include "utxdb.h"
#include "un-namespace.h"
static _Thread_local FILE *uf = NULL;
static _Thread_local int udb;
int
setutxdb(int db, const char *file)
{
struct stat sb;
switch (db) {
case UTXDB_ACTIVE:
if (file == NULL)
file = _PATH_UTX_ACTIVE;
break;
case UTXDB_LASTLOGIN:
if (file == NULL)
file = _PATH_UTX_LASTLOGIN;
break;
case UTXDB_LOG:
if (file == NULL)
file = _PATH_UTX_LOG;
break;
default:
errno = EINVAL;
return (-1);
}
if (uf != NULL)
fclose(uf);
uf = fopen(file, "re");
if (uf == NULL)
return (-1);
if (db != UTXDB_LOG) {
/* Safety check: never use broken files. */
if (_fstat(fileno(uf), &sb) != -1 &&
sb.st_size % sizeof(struct futx) != 0) {
fclose(uf);
uf = NULL;
errno = EFTYPE;
return (-1);
}
/* Prevent reading of partial records. */
(void)setvbuf(uf, NULL, _IOFBF,
rounddown(BUFSIZ, sizeof(struct futx)));
}
udb = db;
return (0);
}
void
setutxent(void)
{
setutxdb(UTXDB_ACTIVE, NULL);
}
void
endutxent(void)
{
if (uf != NULL) {
fclose(uf);
uf = NULL;
}
}
static int
getfutxent(struct futx *fu)
{
if (uf == NULL)
setutxent();
if (uf == NULL)
return (-1);
if (udb == UTXDB_LOG) {
uint16_t len;
retry:
if (fread(&len, sizeof(len), 1, uf) != 1)
return (-1);
len = be16toh(len);
if (len == 0) {
/*
* XXX: Though zero-size records are valid in theory,
* they can never occur in practice. Zero-size records
* indicate file corruption. Seek one byte forward, to
* see if we can find a record there.
*/
ungetc('\0', uf);
goto retry;
}
if (len > sizeof *fu) {
/* Forward compatibility. */
if (fread(fu, sizeof(*fu), 1, uf) != 1)
return (-1);
fseek(uf, len - sizeof(*fu), SEEK_CUR);
} else {
/* Partial record. */
memset(fu, 0, sizeof(*fu));
if (fread(fu, len, 1, uf) != 1)
return (-1);
}
} else {
if (fread(fu, sizeof(*fu), 1, uf) != 1)
return (-1);
}
return (0);
}
struct utmpx *
getutxent(void)
{
struct futx fu;
if (getfutxent(&fu) != 0)
return (NULL);
return (futx_to_utx(&fu));
}
struct utmpx *
getutxid(const struct utmpx *id)
{
struct futx fu;
for (;;) {
if (getfutxent(&fu) != 0)
return (NULL);
switch (fu.fu_type) {
case USER_PROCESS:
case INIT_PROCESS:
case LOGIN_PROCESS:
case DEAD_PROCESS:
switch (id->ut_type) {
case USER_PROCESS:
case INIT_PROCESS:
case LOGIN_PROCESS:
case DEAD_PROCESS:
if (memcmp(fu.fu_id, id->ut_id,
MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
0)
goto found;
}
break;
default:
if (fu.fu_type == id->ut_type)
goto found;
break;
}
}
found:
return (futx_to_utx(&fu));
}
struct utmpx *
getutxline(const struct utmpx *line)
{
struct futx fu;
for (;;) {
if (getfutxent(&fu) != 0)
return (NULL);
switch (fu.fu_type) {
case USER_PROCESS:
case LOGIN_PROCESS:
if (strncmp(fu.fu_line, line->ut_line,
MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
0)
goto found;
break;
}
}
found:
return (futx_to_utx(&fu));
}
struct utmpx *
getutxuser(const char *user)
{
struct futx fu;
for (;;) {
if (getfutxent(&fu) != 0)
return (NULL);
switch (fu.fu_type) {
case USER_PROCESS:
if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
goto found;
break;
}
}
found:
return (futx_to_utx(&fu));
}
diff --git a/lib/libc/gen/glob-compat11.c b/lib/libc/gen/glob-compat11.c
index 8fb45210b775..a681881b5e1c 100644
--- a/lib/libc/gen/glob-compat11.c
+++ b/lib/libc/gen/glob-compat11.c
@@ -1,1088 +1,1087 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
* Copyright (c) 2011 The FreeBSD Foundation
* All rights reserved.
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)glob.c 8.3 (Berkeley) 10/13/93
* From: FreeBSD: head/lib/libc/gen/glob.c 317913 2017-05-07 19:52:56Z jilles
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#define _WANT_FREEBSD11_STAT
#include <sys/stat.h>
#include <ctype.h>
#define _WANT_FREEBSD11_DIRENT
#include <dirent.h>
#include <errno.h>
#include <glob.h>
#include <limits.h>
#include <pwd.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wchar.h>
#include "collate.h"
#include "gen-compat.h"
#include "glob-compat11.h"
/*
* glob(3) expansion limits. Stop the expansion if any of these limits
* is reached. This caps the runtime in the face of DoS attacks. See
* also CVE-2010-2632
*/
#define GLOB_LIMIT_BRACE 128 /* number of brace calls */
#define GLOB_LIMIT_PATH 65536 /* number of path elements */
#define GLOB_LIMIT_READDIR 16384 /* number of readdirs */
#define GLOB_LIMIT_STAT 1024 /* number of stat system calls */
#define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */
struct glob_limit {
size_t l_brace_cnt;
size_t l_path_lim;
size_t l_readdir_cnt;
size_t l_stat_cnt;
size_t l_string_cnt;
};
#define DOT L'.'
#define EOS L'\0'
#define LBRACKET L'['
#define NOT L'!'
#define QUESTION L'?'
#define QUOTE L'\\'
#define RANGE L'-'
#define RBRACKET L']'
#define SEP L'/'
#define STAR L'*'
#define TILDE L'~'
#define LBRACE L'{'
#define RBRACE L'}'
#define COMMA L','
#define M_QUOTE 0x8000000000ULL
#define M_PROTECT 0x4000000000ULL
#define M_MASK 0xffffffffffULL
#define M_CHAR 0x00ffffffffULL
typedef uint_fast64_t Char;
#define CHAR(c) ((Char)((c)&M_CHAR))
#define META(c) ((Char)((c)|M_QUOTE))
#define UNPROT(c) ((c) & ~M_PROTECT)
#define M_ALL META(L'*')
#define M_END META(L']')
#define M_NOT META(L'!')
#define M_ONE META(L'?')
#define M_RNG META(L'-')
#define M_SET META(L'[')
#define ismeta(c) (((c)&M_QUOTE) != 0)
#ifdef DEBUG
#define isprot(c) (((c)&M_PROTECT) != 0)
#endif
static int compare(const void *, const void *);
static int g_Ctoc(const Char *, char *, size_t);
static int g_lstat(Char *, struct freebsd11_stat *, glob11_t *);
static DIR *g_opendir(Char *, glob11_t *);
static const Char *g_strchr(const Char *, wchar_t);
#ifdef notdef
static Char *g_strcat(Char *, const Char *);
#endif
static int g_stat(Char *, struct freebsd11_stat *, glob11_t *);
static int glob0(const Char *, glob11_t *, struct glob_limit *,
const char *);
static int glob1(Char *, glob11_t *, struct glob_limit *);
static int glob2(Char *, Char *, Char *, Char *, glob11_t *,
struct glob_limit *);
static int glob3(Char *, Char *, Char *, Char *, Char *, glob11_t *,
struct glob_limit *);
static int globextend(const Char *, glob11_t *, struct glob_limit *,
const char *);
static const Char *
globtilde(const Char *, Char *, size_t, glob11_t *);
static int globexp0(const Char *, glob11_t *, struct glob_limit *,
const char *);
static int globexp1(const Char *, glob11_t *, struct glob_limit *);
static int globexp2(const Char *, const Char *, glob11_t *,
struct glob_limit *);
static int globfinal(glob11_t *, struct glob_limit *, size_t,
const char *);
static int match(Char *, Char *, Char *);
static int err_nomatch(glob11_t *, struct glob_limit *, const char *);
static int err_aborted(glob11_t *, int, char *);
#ifdef DEBUG
static void qprintf(const char *, Char *);
#endif
int
freebsd11_glob(const char * __restrict pattern, int flags,
int (*errfunc)(const char *, int), glob11_t * __restrict pglob)
{
struct glob_limit limit = { 0, 0, 0, 0, 0 };
const char *patnext;
Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot;
mbstate_t mbs;
wchar_t wc;
size_t clen;
int too_long;
patnext = pattern;
if (!(flags & GLOB_APPEND)) {
pglob->gl_pathc = 0;
pglob->gl_pathv = NULL;
if (!(flags & GLOB_DOOFFS))
pglob->gl_offs = 0;
}
if (flags & GLOB_LIMIT) {
limit.l_path_lim = pglob->gl_matchc;
if (limit.l_path_lim == 0)
limit.l_path_lim = GLOB_LIMIT_PATH;
}
pglob->gl_flags = flags & ~GLOB_MAGCHAR;
pglob->gl_errfunc = errfunc;
pglob->gl_matchc = 0;
bufnext = patbuf;
bufend = bufnext + MAXPATHLEN - 1;
too_long = 1;
if (flags & GLOB_NOESCAPE) {
memset(&mbs, 0, sizeof(mbs));
while (bufnext <= bufend) {
clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2)
return (err_nomatch(pglob, &limit, pattern));
else if (clen == 0) {
too_long = 0;
break;
}
*bufnext++ = wc;
patnext += clen;
}
} else {
/* Protect the quoted characters. */
memset(&mbs, 0, sizeof(mbs));
while (bufnext <= bufend) {
if (*patnext == '\\') {
if (*++patnext == '\0') {
*bufnext++ = QUOTE;
continue;
}
prot = M_PROTECT;
} else
prot = 0;
clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2)
return (err_nomatch(pglob, &limit, pattern));
else if (clen == 0) {
too_long = 0;
break;
}
*bufnext++ = wc | prot;
patnext += clen;
}
}
if (too_long)
return (err_nomatch(pglob, &limit, pattern));
*bufnext = EOS;
if (flags & GLOB_BRACE)
return (globexp0(patbuf, pglob, &limit, pattern));
else
return (glob0(patbuf, pglob, &limit, pattern));
}
static int
globexp0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit,
const char *origpat) {
int rv;
size_t oldpathc;
/* Protect a single {}, for find(1), like csh */
if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) {
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
return (glob0(pattern, pglob, limit, origpat));
}
oldpathc = pglob->gl_pathc;
if ((rv = globexp1(pattern, pglob, limit)) != 0)
return rv;
return (globfinal(pglob, limit, oldpathc, origpat));
}
/*
* Expand recursively a glob {} pattern. When there is no more expansion
* invoke the standard globbing routine to glob the rest of the magic
* characters
*/
static int
globexp1(const Char *pattern, glob11_t *pglob, struct glob_limit *limit)
{
const Char* ptr;
if ((ptr = g_strchr(pattern, LBRACE)) != NULL) {
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
return (globexp2(ptr, pattern, pglob, limit));
}
return (glob0(pattern, pglob, limit, NULL));
}
/*
* Recursive brace globbing helper. Tries to expand a single brace.
* If it succeeds then it invokes globexp1 with the new pattern.
* If it fails then it tries to glob the rest of the pattern and returns.
*/
static int
globexp2(const Char *ptr, const Char *pattern, glob11_t *pglob,
struct glob_limit *limit)
{
int i, rv;
Char *lm, *ls;
const Char *pe, *pm, *pm1, *pl;
Char patbuf[MAXPATHLEN];
/* copy part up to the brace */
for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
continue;
*lm = EOS;
ls = lm;
/* Find the balanced brace */
for (i = 0, pe = ++ptr; *pe != EOS; pe++)
if (*pe == LBRACKET) {
/* Ignore everything between [] */
for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
continue;
if (*pe == EOS) {
/*
* We could not find a matching RBRACKET.
* Ignore and just look for RBRACE
*/
pe = pm;
}
}
else if (*pe == LBRACE)
i++;
else if (*pe == RBRACE) {
if (i == 0)
break;
i--;
}
/* Non matching braces; just glob the pattern */
if (i != 0 || *pe == EOS)
return (glob0(pattern, pglob, limit, NULL));
for (i = 0, pl = pm = ptr; pm <= pe; pm++)
switch (*pm) {
case LBRACKET:
/* Ignore everything between [] */
for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++)
continue;
if (*pm == EOS) {
/*
* We could not find a matching RBRACKET.
* Ignore and just look for RBRACE
*/
pm = pm1;
}
break;
case LBRACE:
i++;
break;
case RBRACE:
if (i) {
i--;
break;
}
/* FALLTHROUGH */
case COMMA:
if (i && *pm == COMMA)
break;
else {
/* Append the current string */
for (lm = ls; (pl < pm); *lm++ = *pl++)
continue;
/*
* Append the rest of the pattern after the
* closing brace
*/
for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
continue;
/* Expand the current pattern */
#ifdef DEBUG
qprintf("globexp2:", patbuf);
#endif
rv = globexp1(patbuf, pglob, limit);
if (rv)
return (rv);
/* move after the comma, to the next string */
pl = pm + 1;
}
break;
default:
break;
}
return (0);
}
/*
* expand tilde from the passwd file.
*/
static const Char *
globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob11_t *pglob)
{
struct passwd *pwd;
char *h, *sc;
const Char *p;
Char *b, *eb;
wchar_t wc;
wchar_t wbuf[MAXPATHLEN];
wchar_t *wbufend, *dc;
size_t clen;
mbstate_t mbs;
int too_long;
if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
return (pattern);
/*
* Copy up to the end of the string or /
*/
eb = &patbuf[patbuf_len - 1];
for (p = pattern + 1, b = patbuf;
b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++)
continue;
if (*p != EOS && UNPROT(*p) != SEP)
return (NULL);
*b = EOS;
h = NULL;
if (patbuf[0] == EOS) {
/*
* handle a plain ~ or ~/ by expanding $HOME first (iff
* we're not running setuid or setgid) and then trying
* the password file
*/
if ((h = secure_getenv("HOME")) == NULL) {
if (((h = getlogin()) != NULL &&
(pwd = getpwnam(h)) != NULL) ||
(pwd = getpwuid(getuid())) != NULL)
h = pwd->pw_dir;
else
return (pattern);
}
}
else {
/*
* Expand a ~user
*/
if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf)))
return (NULL);
if ((pwd = getpwnam((char *)wbuf)) == NULL)
return (pattern);
else
h = pwd->pw_dir;
}
/* Copy the home directory */
dc = wbuf;
sc = h;
wbufend = wbuf + MAXPATHLEN - 1;
too_long = 1;
memset(&mbs, 0, sizeof(mbs));
while (dc <= wbufend) {
clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2) {
/* XXX See initial comment #2. */
wc = (unsigned char)*sc;
clen = 1;
memset(&mbs, 0, sizeof(mbs));
}
if ((*dc++ = wc) == EOS) {
too_long = 0;
break;
}
sc += clen;
}
if (too_long)
return (NULL);
dc = wbuf;
for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT)
continue;
if (*dc != EOS)
return (NULL);
/* Append the rest of the pattern */
if (*p != EOS) {
too_long = 1;
while (b <= eb) {
if ((*b++ = *p++) == EOS) {
too_long = 0;
break;
}
}
if (too_long)
return (NULL);
} else
*b = EOS;
return (patbuf);
}
/*
* The main glob() routine: compiles the pattern (optionally processing
* quotes), calls glob1() to do the real pattern matching, and finally
* sorts the list (unless unsorted operation is requested). Returns 0
* if things went well, nonzero if errors occurred.
*/
static int
glob0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit,
const char *origpat) {
const Char *qpatnext;
int err;
size_t oldpathc;
Char *bufnext, c, patbuf[MAXPATHLEN];
qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
if (qpatnext == NULL) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
oldpathc = pglob->gl_pathc;
bufnext = patbuf;
/* We don't need to check for buffer overflow any more. */
while ((c = *qpatnext++) != EOS) {
switch (c) {
case LBRACKET:
c = *qpatnext;
if (c == NOT)
++qpatnext;
if (*qpatnext == EOS ||
g_strchr(qpatnext+1, RBRACKET) == NULL) {
*bufnext++ = LBRACKET;
if (c == NOT)
--qpatnext;
break;
}
*bufnext++ = M_SET;
if (c == NOT)
*bufnext++ = M_NOT;
c = *qpatnext++;
do {
*bufnext++ = CHAR(c);
if (*qpatnext == RANGE &&
(c = qpatnext[1]) != RBRACKET) {
*bufnext++ = M_RNG;
*bufnext++ = CHAR(c);
qpatnext += 2;
}
} while ((c = *qpatnext++) != RBRACKET);
pglob->gl_flags |= GLOB_MAGCHAR;
*bufnext++ = M_END;
break;
case QUESTION:
pglob->gl_flags |= GLOB_MAGCHAR;
*bufnext++ = M_ONE;
break;
case STAR:
pglob->gl_flags |= GLOB_MAGCHAR;
/* collapse adjacent stars to one,
* to avoid exponential behavior
*/
if (bufnext == patbuf || bufnext[-1] != M_ALL)
*bufnext++ = M_ALL;
break;
default:
*bufnext++ = CHAR(c);
break;
}
}
*bufnext = EOS;
#ifdef DEBUG
qprintf("glob0:", patbuf);
#endif
if ((err = glob1(patbuf, pglob, limit)) != 0)
return(err);
if (origpat != NULL)
return (globfinal(pglob, limit, oldpathc, origpat));
return (0);
}
static int
globfinal(glob11_t *pglob, struct glob_limit *limit, size_t oldpathc,
const char *origpat) {
if (pglob->gl_pathc == oldpathc)
return (err_nomatch(pglob, limit, origpat));
if (!(pglob->gl_flags & GLOB_NOSORT))
qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
pglob->gl_pathc - oldpathc, sizeof(char *), compare);
return (0);
}
static int
compare(const void *p, const void *q)
{
return (strcoll(*(char **)p, *(char **)q));
}
static int
glob1(Char *pattern, glob11_t *pglob, struct glob_limit *limit)
{
Char pathbuf[MAXPATHLEN];
/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
if (*pattern == EOS)
return (0);
return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1,
pattern, pglob, limit));
}
/*
* The functions glob2 and glob3 are mutually recursive; there is one level
* of recursion for each segment in the pattern that contains one or more
* meta characters.
*/
static int
glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern,
glob11_t *pglob, struct glob_limit *limit)
{
struct freebsd11_stat sb;
Char *p, *q;
int anymeta;
/*
* Loop over pattern segments until end of pattern or until
* segment with meta character found.
*/
for (anymeta = 0;;) {
if (*pattern == EOS) { /* End of pattern? */
*pathend = EOS;
if (g_lstat(pathbuf, &sb, pglob))
return (0);
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
if ((pglob->gl_flags & GLOB_MARK) &&
UNPROT(pathend[-1]) != SEP &&
(S_ISDIR(sb.st_mode) ||
(S_ISLNK(sb.st_mode) &&
g_stat(pathbuf, &sb, pglob) == 0 &&
S_ISDIR(sb.st_mode)))) {
if (pathend + 1 > pathend_last) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
*pathend++ = SEP;
*pathend = EOS;
}
++pglob->gl_matchc;
return (globextend(pathbuf, pglob, limit, NULL));
}
/* Find end of next segment, copy tentatively to pathend. */
q = pathend;
p = pattern;
while (*p != EOS && UNPROT(*p) != SEP) {
if (ismeta(*p))
anymeta = 1;
if (q + 1 > pathend_last) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
*q++ = *p++;
}
if (!anymeta) { /* No expansion, do next segment. */
pathend = q;
pattern = p;
while (UNPROT(*pattern) == SEP) {
if (pathend + 1 > pathend_last) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
*pathend++ = *pattern++;
}
} else /* Need expansion, recurse. */
return (glob3(pathbuf, pathend, pathend_last, pattern,
p, pglob, limit));
}
/* NOTREACHED */
}
static int
glob3(Char *pathbuf, Char *pathend, Char *pathend_last,
Char *pattern, Char *restpattern,
glob11_t *pglob, struct glob_limit *limit)
{
struct freebsd11_dirent *dp;
DIR *dirp;
int err, too_long, saverrno, saverrno2;
char buf[MAXPATHLEN + MB_LEN_MAX - 1];
struct freebsd11_dirent *(*readdirfunc)(DIR *);
if (pathend > pathend_last) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
*pathend = EOS;
if (pglob->gl_errfunc != NULL &&
g_Ctoc(pathbuf, buf, sizeof(buf))) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
saverrno = errno;
errno = 0;
if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
if (errno == ENOENT || errno == ENOTDIR)
return (0);
err = err_aborted(pglob, errno, buf);
if (errno == 0)
errno = saverrno;
return (err);
}
err = 0;
/* pglob->gl_readdir takes a void *, fix this manually */
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
readdirfunc =
(struct freebsd11_dirent *(*)(DIR *))pglob->gl_readdir;
else
readdirfunc = freebsd11_readdir;
errno = 0;
/* Search directory for matching names. */
while ((dp = (*readdirfunc)(dirp)) != NULL) {
char *sc;
Char *dc;
wchar_t wc;
size_t clen;
mbstate_t mbs;
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) {
errno = E2BIG;
err = GLOB_NOSPACE;
break;
}
/* Initial DOT must be matched literally. */
if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) {
errno = 0;
continue;
}
memset(&mbs, 0, sizeof(mbs));
dc = pathend;
sc = dp->d_name;
too_long = 1;
while (dc <= pathend_last) {
clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs);
if (clen == (size_t)-1 || clen == (size_t)-2) {
/* XXX See initial comment #2. */
wc = (unsigned char)*sc;
clen = 1;
memset(&mbs, 0, sizeof(mbs));
}
if ((*dc++ = wc) == EOS) {
too_long = 0;
break;
}
sc += clen;
}
if (too_long && (err = err_aborted(pglob, ENAMETOOLONG,
buf))) {
errno = ENAMETOOLONG;
break;
}
if (too_long || !match(pathend, pattern, restpattern)) {
*pathend = EOS;
errno = 0;
continue;
}
if (errno == 0)
errno = saverrno;
err = glob2(pathbuf, --dc, pathend_last, restpattern,
pglob, limit);
if (err)
break;
errno = 0;
}
saverrno2 = errno;
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
(*pglob->gl_closedir)(dirp);
else
closedir(dirp);
errno = saverrno2;
if (err)
return (err);
if (dp == NULL && errno != 0 &&
(err = err_aborted(pglob, errno, buf)))
return (err);
if (errno == 0)
errno = saverrno;
return (0);
}
/*
* Extend the gl_pathv member of a glob11_t structure to accommodate a new item,
* add the new item, and update gl_pathc.
*
* This assumes the BSD realloc, which only copies the block when its size
* crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
* behavior.
*
* Return 0 if new item added, error code if memory couldn't be allocated.
*
* Invariant of the glob11_t structure:
* Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
* gl_pathv points to (gl_offs + gl_pathc + 1) items.
*/
static int
globextend(const Char *path, glob11_t *pglob, struct glob_limit *limit,
const char *origpat)
{
char **pathv;
size_t i, newn, len;
char *copy;
const Char *p;
if ((pglob->gl_flags & GLOB_LIMIT) &&
pglob->gl_matchc > limit->l_path_lim) {
errno = E2BIG;
return (GLOB_NOSPACE);
}
newn = 2 + pglob->gl_pathc + pglob->gl_offs;
/* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */
pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv));
if (pathv == NULL)
return (GLOB_NOSPACE);
if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
/* first time around -- clear initial gl_offs items */
pathv += pglob->gl_offs;
for (i = pglob->gl_offs + 1; --i > 0; )
*--pathv = NULL;
}
pglob->gl_pathv = pathv;
if (origpat != NULL)
copy = strdup(origpat);
else {
for (p = path; *p++ != EOS;)
continue;
len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */
if ((copy = malloc(len)) != NULL) {
if (g_Ctoc(path, copy, len)) {
free(copy);
errno = E2BIG;
return (GLOB_NOSPACE);
}
}
}
if (copy != NULL) {
limit->l_string_cnt += strlen(copy) + 1;
if ((pglob->gl_flags & GLOB_LIMIT) &&
limit->l_string_cnt >= GLOB_LIMIT_STRING) {
free(copy);
errno = E2BIG;
return (GLOB_NOSPACE);
}
pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
}
pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
return (copy == NULL ? GLOB_NOSPACE : 0);
}
/*
* pattern matching function for filenames.
*/
static int
match(Char *name, Char *pat, Char *patend)
{
int ok, negate_range;
Char c, k, *nextp, *nextn;
struct xlocale_collate *table =
(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
nextn = NULL;
nextp = NULL;
while (1) {
while (pat < patend) {
c = *pat++;
switch (c & M_MASK) {
case M_ALL:
if (pat == patend)
return (1);
if (*name == EOS)
return (0);
nextn = name + 1;
nextp = pat - 1;
break;
case M_ONE:
if (*name++ == EOS)
goto fail;
break;
case M_SET:
ok = 0;
if ((k = *name++) == EOS)
goto fail;
negate_range = ((*pat & M_MASK) == M_NOT);
if (negate_range != 0)
++pat;
while (((c = *pat++) & M_MASK) != M_END)
if ((*pat & M_MASK) == M_RNG) {
if (table->__collate_load_error ?
CHAR(c) <= CHAR(k) &&
CHAR(k) <= CHAR(pat[1]) :
__wcollate_range_cmp(CHAR(c),
CHAR(k)) <= 0 &&
__wcollate_range_cmp(CHAR(k),
CHAR(pat[1])) <= 0)
ok = 1;
pat += 2;
} else if (c == k)
ok = 1;
if (ok == negate_range)
goto fail;
break;
default:
if (*name++ != c)
goto fail;
break;
}
}
if (*name == EOS)
return (1);
fail:
if (nextn == NULL)
break;
pat = nextp;
name = nextn;
}
return (0);
}
/* Free allocated data belonging to a glob11_t structure. */
void
freebsd11_globfree(glob11_t *pglob)
{
size_t i;
char **pp;
if (pglob->gl_pathv != NULL) {
pp = pglob->gl_pathv + pglob->gl_offs;
for (i = pglob->gl_pathc; i--; ++pp)
if (*pp)
free(*pp);
free(pglob->gl_pathv);
pglob->gl_pathv = NULL;
}
}
static DIR *
g_opendir(Char *str, glob11_t *pglob)
{
char buf[MAXPATHLEN + MB_LEN_MAX - 1];
if (*str == EOS)
strcpy(buf, ".");
else {
if (g_Ctoc(str, buf, sizeof(buf))) {
errno = ENAMETOOLONG;
return (NULL);
}
}
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
return ((*pglob->gl_opendir)(buf));
return (opendir(buf));
}
static int
g_lstat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob)
{
char buf[MAXPATHLEN + MB_LEN_MAX - 1];
if (g_Ctoc(fn, buf, sizeof(buf))) {
errno = ENAMETOOLONG;
return (-1);
}
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
return((*pglob->gl_lstat)(buf, sb));
return (freebsd11_lstat(buf, sb));
}
static int
g_stat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob)
{
char buf[MAXPATHLEN + MB_LEN_MAX - 1];
if (g_Ctoc(fn, buf, sizeof(buf))) {
errno = ENAMETOOLONG;
return (-1);
}
if (pglob->gl_flags & GLOB_ALTDIRFUNC)
return ((*pglob->gl_stat)(buf, sb));
return (freebsd11_stat(buf, sb));
}
static const Char *
g_strchr(const Char *str, wchar_t ch)
{
do {
if (*str == ch)
return (str);
} while (*str++);
return (NULL);
}
static int
g_Ctoc(const Char *str, char *buf, size_t len)
{
mbstate_t mbs;
size_t clen;
memset(&mbs, 0, sizeof(mbs));
while (len >= MB_CUR_MAX) {
clen = wcrtomb(buf, CHAR(*str), &mbs);
if (clen == (size_t)-1) {
/* XXX See initial comment #2. */
*buf = (char)CHAR(*str);
clen = 1;
memset(&mbs, 0, sizeof(mbs));
}
if (CHAR(*str) == EOS)
return (0);
str++;
buf += clen;
len -= clen;
}
return (1);
}
static int
err_nomatch(glob11_t *pglob, struct glob_limit *limit, const char *origpat) {
/*
* If there was no match we are going to append the origpat
* if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
* and the origpat did not contain any magic characters
* GLOB_NOMAGIC is there just for compatibility with csh.
*/
if ((pglob->gl_flags & GLOB_NOCHECK) ||
((pglob->gl_flags & GLOB_NOMAGIC) &&
!(pglob->gl_flags & GLOB_MAGCHAR)))
return (globextend(NULL, pglob, limit, origpat));
return (GLOB_NOMATCH);
}
static int
err_aborted(glob11_t *pglob, int err, char *buf) {
if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) ||
(pglob->gl_flags & GLOB_ERR))
return (GLOB_ABORTED);
return (0);
}
#ifdef DEBUG
static void
qprintf(const char *str, Char *s)
{
Char *p;
(void)printf("%s\n", str);
if (s != NULL) {
for (p = s; *p != EOS; p++)
(void)printf("%c", (char)CHAR(*p));
(void)printf("\n");
for (p = s; *p != EOS; p++)
(void)printf("%c", (isprot(*p) ? '\\' : ' '));
(void)printf("\n");
for (p = s; *p != EOS; p++)
(void)printf("%c", (ismeta(*p) ? '_' : ' '));
(void)printf("\n");
}
}
#endif
__sym_compat(glob, freebsd11_glob, FBSD_1.0);
__sym_compat(globfree, freebsd11_globfree, FBSD_1.0);
diff --git a/lib/libc/gen/glob-compat11.h b/lib/libc/gen/glob-compat11.h
index 720f3fab36f9..d91127db0428 100644
--- a/lib/libc/gen/glob-compat11.h
+++ b/lib/libc/gen/glob-compat11.h
@@ -1,70 +1,69 @@
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Guido van Rossum.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)glob.h 8.1 (Berkeley) 6/2/93
*/
#ifndef _GLOB_COMPAT11_H_
#define _GLOB_COMPAT11_H_
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <glob.h>
struct freebsd11_stat;
typedef struct {
size_t gl_pathc; /* Count of total paths so far. */
size_t gl_matchc; /* Count of paths matching pattern. */
size_t gl_offs; /* Reserved at beginning of gl_pathv. */
int gl_flags; /* Copy of flags parameter to glob. */
char **gl_pathv; /* List of paths matching pattern. */
/* Copy of errfunc parameter to glob. */
int (*gl_errfunc)(const char *, int);
/*
* Alternate filesystem access methods for glob; replacement
* versions of closedir(3), readdir(3), opendir(3), stat(2)
* and lstat(2).
*/
void (*gl_closedir)(void *);
struct freebsd11_dirent *(*gl_readdir)(void *);
void *(*gl_opendir)(const char *);
int (*gl_lstat)(const char *, struct freebsd11_stat *);
int (*gl_stat)(const char *, struct freebsd11_stat *);
} glob11_t;
__BEGIN_DECLS
int freebsd11_glob(const char * __restrict, int,
int (*)(const char *, int), glob11_t * __restrict);
void freebsd11_globfree(glob11_t *);
__END_DECLS
#endif /* !_GLOB_COMPAT11_H_ */
diff --git a/lib/libc/gen/jrand48.c b/lib/libc/gen/jrand48.c
index 5fdd1778c340..0a9f780a9e5c 100644
--- a/lib/libc/gen/jrand48.c
+++ b/lib/libc/gen/jrand48.c
@@ -1,25 +1,24 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include <stdint.h>
#include "rand48.h"
long
jrand48(unsigned short xseed[3])
{
_dorand48(xseed);
return ((int32_t)(((uint32_t)xseed[2] << 16) | (uint32_t)xseed[1]));
}
diff --git a/lib/libc/gen/lcong48.c b/lib/libc/gen/lcong48.c
index b77278db1750..f13826b3d3f3 100644
--- a/lib/libc/gen/lcong48.c
+++ b/lib/libc/gen/lcong48.c
@@ -1,31 +1,30 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include "rand48.h"
extern unsigned short _rand48_seed[3];
extern unsigned short _rand48_mult[3];
extern unsigned short _rand48_add;
void
lcong48(unsigned short p[7])
{
_rand48_seed[0] = p[0];
_rand48_seed[1] = p[1];
_rand48_seed[2] = p[2];
_rand48_mult[0] = p[3];
_rand48_mult[1] = p[4];
_rand48_mult[2] = p[5];
_rand48_add = p[6];
}
diff --git a/lib/libc/gen/ldexp.c b/lib/libc/gen/ldexp.c
index 5055add84ff3..1db62afc609e 100644
--- a/lib/libc/gen/ldexp.c
+++ b/lib/libc/gen/ldexp.c
@@ -1,8 +1,7 @@
-#include <sys/cdefs.h>
/*
* ldexp() and scalbn() are defined to be identical, but ldexp() lives in libc
* for backwards compatibility.
*/
#define scalbn ldexp
#include "../../msun/src/s_scalbn.c"
#undef scalbn
diff --git a/lib/libc/gen/libc_dlopen.c b/lib/libc/gen/libc_dlopen.c
index bc7e13ca0043..4e5ec2961ac2 100644
--- a/lib/libc/gen/libc_dlopen.c
+++ b/lib/libc/gen/libc_dlopen.c
@@ -1,57 +1,56 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011 Xin LI <delphij@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <dlfcn.h>
#include <stddef.h>
#include <unistd.h>
#include "libc_private.h"
/*
* Whether we want to restrict dlopen()s.
*/
static int __libc_restricted_mode = 0;
void *
libc_dlopen(const char *path, int mode)
{
if (__libc_restricted_mode) {
_rtld_error("Service unavailable -- libc in restricted mode");
return (NULL);
}
return (dlopen(path, mode));
}
void
__FreeBSD_libc_enter_restricted_mode(void)
{
__libc_restricted_mode = 1;
}
diff --git a/lib/libc/gen/lockf.c b/lib/libc/gen/lockf.c
index 247066706a2b..fec65896eaaa 100644
--- a/lib/libc/gen/lockf.c
+++ b/lib/libc/gen/lockf.c
@@ -1,84 +1,83 @@
/* $NetBSD: lockf.c,v 1.3 2008/04/28 20:22:59 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Klaus Klein.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
int
lockf(int filedes, int function, off_t size)
{
struct flock fl;
int cmd;
fl.l_start = 0;
fl.l_len = size;
fl.l_whence = SEEK_CUR;
switch (function) {
case F_ULOCK:
cmd = F_SETLK;
fl.l_type = F_UNLCK;
break;
case F_LOCK:
cmd = F_SETLKW;
fl.l_type = F_WRLCK;
break;
case F_TLOCK:
cmd = F_SETLK;
fl.l_type = F_WRLCK;
break;
case F_TEST:
fl.l_type = F_WRLCK;
if (((int (*)(int, int, ...))
__libc_interposing[INTERPOS_fcntl])(filedes, F_GETLK, &fl)
== -1)
return (-1);
if (fl.l_type == F_UNLCK || (fl.l_sysid == 0 &&
fl.l_pid == getpid()))
return (0);
errno = EAGAIN;
return (-1);
/* NOTREACHED */
default:
errno = EINVAL;
return (-1);
/* NOTREACHED */
}
return (((int (*)(int, int, ...))
__libc_interposing[INTERPOS_fcntl])(filedes, cmd, &fl));
}
diff --git a/lib/libc/gen/lrand48.c b/lib/libc/gen/lrand48.c
index d7257febe717..a3d0111cf4d5 100644
--- a/lib/libc/gen/lrand48.c
+++ b/lib/libc/gen/lrand48.c
@@ -1,24 +1,23 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include "rand48.h"
extern unsigned short _rand48_seed[3];
long
lrand48(void)
{
_dorand48(_rand48_seed);
return ((long) _rand48_seed[2] << 15) + ((long) _rand48_seed[1] >> 1);
}
diff --git a/lib/libc/gen/memalign.c b/lib/libc/gen/memalign.c
index af64c998dbd4..269a5bc829b1 100644
--- a/lib/libc/gen/memalign.c
+++ b/lib/libc/gen/memalign.c
@@ -1,44 +1,43 @@
/*-
* Copyright (c) 2020 The FreeBSD Foundation
*
* This software was developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdlib.h>
void *
memalign(size_t align, size_t size)
{
/*
* glibc allows align == 0, but that is not valid for roundup.
* Just pass through to malloc in that case.
*/
if (align != 0)
return (aligned_alloc(align, roundup(size, align)));
else
return (malloc(size));
}
diff --git a/lib/libc/gen/modf.c b/lib/libc/gen/modf.c
index 6853a56d051d..35ed2f2ec736 100644
--- a/lib/libc/gen/modf.c
+++ b/lib/libc/gen/modf.c
@@ -1,136 +1,135 @@
/* @(#)s_modf.c 5.1 93/09/24 */
/*
* ====================================================
* Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
*
* Developed at SunPro, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
* software is freely granted, provided that this notice
* is preserved.
* ====================================================
*/
-#include <sys/cdefs.h>
/*
* modf(double x, double *iptr)
* return fraction part of x, and return x's integral part in *iptr.
* Method:
* Bit twiddling.
*
* Exception:
* No exception.
*/
#include <sys/types.h>
#include <machine/endian.h>
#include <math.h>
/* Bit fiddling routines copied from msun/src/math_private.h,v 1.15 */
#if BYTE_ORDER == BIG_ENDIAN
typedef union
{
double value;
struct
{
u_int32_t msw;
u_int32_t lsw;
} parts;
} ieee_double_shape_type;
#endif
#if BYTE_ORDER == LITTLE_ENDIAN
typedef union
{
double value;
struct
{
u_int32_t lsw;
u_int32_t msw;
} parts;
} ieee_double_shape_type;
#endif
/* Get two 32 bit ints from a double. */
#define EXTRACT_WORDS(ix0,ix1,d) \
do { \
ieee_double_shape_type ew_u; \
ew_u.value = (d); \
(ix0) = ew_u.parts.msw; \
(ix1) = ew_u.parts.lsw; \
} while (0)
/* Get the more significant 32 bit int from a double. */
#define GET_HIGH_WORD(i,d) \
do { \
ieee_double_shape_type gh_u; \
gh_u.value = (d); \
(i) = gh_u.parts.msw; \
} while (0)
/* Set a double from two 32 bit ints. */
#define INSERT_WORDS(d,ix0,ix1) \
do { \
ieee_double_shape_type iw_u; \
iw_u.parts.msw = (ix0); \
iw_u.parts.lsw = (ix1); \
(d) = iw_u.value; \
} while (0)
static const double one = 1.0;
double
modf(double x, double *iptr)
{
int32_t i0,i1,j0;
u_int32_t i;
EXTRACT_WORDS(i0,i1,x);
j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */
if(j0<20) { /* integer part in high x */
if(j0<0) { /* |x|<1 */
INSERT_WORDS(*iptr,i0&0x80000000,0); /* *iptr = +-0 */
return x;
} else {
i = (0x000fffff)>>j0;
if(((i0&i)|i1)==0) { /* x is integral */
u_int32_t high;
*iptr = x;
GET_HIGH_WORD(high,x);
INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */
return x;
} else {
INSERT_WORDS(*iptr,i0&(~i),0);
return x - *iptr;
}
}
} else if (j0>51) { /* no fraction part */
u_int32_t high;
if (j0 == 0x400) { /* inf/NaN */
*iptr = x;
return 0.0 / x;
}
*iptr = x*one;
GET_HIGH_WORD(high,x);
INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */
return x;
} else { /* fraction part in low x */
i = ((u_int32_t)(0xffffffff))>>(j0-20);
if((i1&i)==0) { /* x is integral */
u_int32_t high;
*iptr = x;
GET_HIGH_WORD(high,x);
INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */
return x;
} else {
INSERT_WORDS(*iptr,i0,i1&(~i));
return x - *iptr;
}
}
}
diff --git a/lib/libc/gen/mrand48.c b/lib/libc/gen/mrand48.c
index 6ee078e95c81..15b0bfb1bd6e 100644
--- a/lib/libc/gen/mrand48.c
+++ b/lib/libc/gen/mrand48.c
@@ -1,28 +1,27 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include <stdint.h>
#include "rand48.h"
extern unsigned short _rand48_seed[3];
long
mrand48(void)
{
_dorand48(_rand48_seed);
return ((int32_t)(((uint32_t)_rand48_seed[2] << 16) |
(uint32_t)_rand48_seed[1]));
}
diff --git a/lib/libc/gen/nftw-compat11.c b/lib/libc/gen/nftw-compat11.c
index fdd5c9a707a4..36970424bf2a 100644
--- a/lib/libc/gen/nftw-compat11.c
+++ b/lib/libc/gen/nftw-compat11.c
@@ -1,113 +1,112 @@
/*
* Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*
* From: $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $
* From: FreeBSD: head/lib/libc/gen/nftw.c 239160 2012-08-09 22:05:40Z jilles
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <ftw.h>
#include "fts-compat11.h"
int
freebsd11_nftw(const char *path,
int (*fn)(const char *, const struct freebsd11_stat *, int, struct FTW *),
int nfds, int ftwflags)
{
char * const paths[2] = { (char *)path, NULL };
struct FTW ftw;
FTSENT11 *cur;
FTS11 *ftsp;
int error = 0, ftsflags, fnflag, postorder, sverrno;
/* XXX - nfds is currently unused */
if (nfds < 1) {
errno = EINVAL;
return (-1);
}
ftsflags = FTS_COMFOLLOW;
if (!(ftwflags & FTW_CHDIR))
ftsflags |= FTS_NOCHDIR;
if (ftwflags & FTW_MOUNT)
ftsflags |= FTS_XDEV;
if (ftwflags & FTW_PHYS)
ftsflags |= FTS_PHYSICAL;
else
ftsflags |= FTS_LOGICAL;
postorder = (ftwflags & FTW_DEPTH) != 0;
ftsp = freebsd11_fts_open(paths, ftsflags, NULL);
if (ftsp == NULL)
return (-1);
while ((cur = freebsd11_fts_read(ftsp)) != NULL) {
switch (cur->fts_info) {
case FTS_D:
if (postorder)
continue;
fnflag = FTW_D;
break;
case FTS_DC:
continue;
case FTS_DNR:
fnflag = FTW_DNR;
break;
case FTS_DP:
if (!postorder)
continue;
fnflag = FTW_DP;
break;
case FTS_F:
case FTS_DEFAULT:
fnflag = FTW_F;
break;
case FTS_NS:
case FTS_NSOK:
fnflag = FTW_NS;
break;
case FTS_SL:
fnflag = FTW_SL;
break;
case FTS_SLNONE:
fnflag = FTW_SLN;
break;
default:
error = -1;
goto done;
}
ftw.base = cur->fts_pathlen - cur->fts_namelen;
ftw.level = cur->fts_level;
error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
if (error != 0)
break;
}
done:
sverrno = errno;
if (freebsd11_fts_close(ftsp) != 0 && error == 0)
error = -1;
else
errno = sverrno;
return (error);
}
__sym_compat(nftw, freebsd11_nftw, FBSD_1.0);
diff --git a/lib/libc/gen/nftw.c b/lib/libc/gen/nftw.c
index 9b5c33e1057c..95cc9947b7c1 100644
--- a/lib/libc/gen/nftw.c
+++ b/lib/libc/gen/nftw.c
@@ -1,107 +1,106 @@
/* $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $ */
/*
* Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fts.h>
#include <ftw.h>
int
nftw(const char *path, int (*fn)(const char *, const struct stat *, int,
struct FTW *), int nfds, int ftwflags)
{
char * const paths[2] = { (char *)path, NULL };
struct FTW ftw;
FTSENT *cur;
FTS *ftsp;
int error = 0, ftsflags, fnflag, postorder, sverrno;
/* XXX - nfds is currently unused */
if (nfds < 1) {
errno = EINVAL;
return (-1);
}
ftsflags = FTS_COMFOLLOW;
if (!(ftwflags & FTW_CHDIR))
ftsflags |= FTS_NOCHDIR;
if (ftwflags & FTW_MOUNT)
ftsflags |= FTS_XDEV;
if (ftwflags & FTW_PHYS)
ftsflags |= FTS_PHYSICAL;
else
ftsflags |= FTS_LOGICAL;
postorder = (ftwflags & FTW_DEPTH) != 0;
ftsp = fts_open(paths, ftsflags, NULL);
if (ftsp == NULL)
return (-1);
while ((cur = fts_read(ftsp)) != NULL) {
switch (cur->fts_info) {
case FTS_D:
if (postorder)
continue;
fnflag = FTW_D;
break;
case FTS_DC:
continue;
case FTS_DNR:
fnflag = FTW_DNR;
break;
case FTS_DP:
if (!postorder)
continue;
fnflag = FTW_DP;
break;
case FTS_F:
case FTS_DEFAULT:
fnflag = FTW_F;
break;
case FTS_NS:
case FTS_NSOK:
fnflag = FTW_NS;
break;
case FTS_SL:
fnflag = FTW_SL;
break;
case FTS_SLNONE:
fnflag = FTW_SLN;
break;
default:
error = -1;
goto done;
}
ftw.base = cur->fts_pathlen - cur->fts_namelen;
ftw.level = cur->fts_level;
error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw);
if (error != 0)
break;
}
done:
sverrno = errno;
if (fts_close(ftsp) != 0 && error == 0)
error = -1;
else
errno = sverrno;
return (error);
}
diff --git a/lib/libc/gen/nrand48.c b/lib/libc/gen/nrand48.c
index 12016ed76ec9..6c54065e7e0f 100644
--- a/lib/libc/gen/nrand48.c
+++ b/lib/libc/gen/nrand48.c
@@ -1,22 +1,21 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include "rand48.h"
long
nrand48(unsigned short xseed[3])
{
_dorand48(xseed);
return ((long) xseed[2] << 15) + ((long) xseed[1] >> 1);
}
diff --git a/lib/libc/gen/pmadvise.c b/lib/libc/gen/pmadvise.c
index ac4f858d09c9..19525c939c26 100644
--- a/lib/libc/gen/pmadvise.c
+++ b/lib/libc/gen/pmadvise.c
@@ -1,24 +1,23 @@
/*
* The contents of this file are in the public domain.
* Written by Garrett A. Wollman, 2000-10-07.
*
*/
-#include <sys/cdefs.h>
#include <sys/mman.h>
#include <errno.h>
int
posix_madvise(void *address, size_t size, int how)
{
int ret, saved_errno;
saved_errno = errno;
if (madvise(address, size, how) == -1) {
ret = errno;
errno = saved_errno;
} else {
ret = 0;
}
return (ret);
}
diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c
index 77f7dd9955cd..b1bb49d63ffd 100644
--- a/lib/libc/gen/posix_spawn.c
+++ b/lib/libc/gen/posix_spawn.c
@@ -1,673 +1,672 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <sched.h>
#include <spawn.h>
#include <signal.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
struct __posix_spawnattr {
short sa_flags;
pid_t sa_pgroup;
struct sched_param sa_schedparam;
int sa_schedpolicy;
sigset_t sa_sigdefault;
sigset_t sa_sigmask;
};
struct __posix_spawn_file_actions {
STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list;
};
typedef struct __posix_spawn_file_actions_entry {
STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list;
enum {
FAE_OPEN,
FAE_DUP2,
FAE_CLOSE,
FAE_CHDIR,
FAE_FCHDIR,
FAE_CLOSEFROM,
} fae_action;
int fae_fildes;
union {
struct {
char *path;
#define fae_path fae_data.open.path
int oflag;
#define fae_oflag fae_data.open.oflag
mode_t mode;
#define fae_mode fae_data.open.mode
} open;
struct {
int newfildes;
#define fae_newfildes fae_data.dup2.newfildes
} dup2;
} fae_data;
} posix_spawn_file_actions_entry_t;
/*
* Spawn routines
*/
static int
process_spawnattr(const posix_spawnattr_t sa)
{
struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL };
int i;
/*
* POSIX doesn't really describe in which order everything
* should be set. We'll just set them in the order in which they
* are mentioned.
*/
/* Set process group */
if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) {
if (setpgid(0, sa->sa_pgroup) != 0)
return (errno);
}
/* Set scheduler policy */
if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) {
if (sched_setscheduler(0, sa->sa_schedpolicy,
&sa->sa_schedparam) != 0)
return (errno);
} else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) {
if (sched_setparam(0, &sa->sa_schedparam) != 0)
return (errno);
}
/* Reset user ID's */
if (sa->sa_flags & POSIX_SPAWN_RESETIDS) {
if (setegid(getgid()) != 0)
return (errno);
if (seteuid(getuid()) != 0)
return (errno);
}
/*
* Set signal masks/defaults.
* Use unwrapped syscall, libthr is in undefined state after vfork().
*/
if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) {
__sys_sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL);
}
if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) {
for (i = 1; i <= _SIG_MAXSIG; i++) {
if (sigismember(&sa->sa_sigdefault, i))
if (__sys_sigaction(i, &sigact, NULL) != 0)
return (errno);
}
}
return (0);
}
static int
process_file_actions_entry(posix_spawn_file_actions_entry_t *fae)
{
int fd, saved_errno;
switch (fae->fae_action) {
case FAE_OPEN:
/* Perform an open(), make it use the right fd */
fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode);
if (fd < 0)
return (errno);
if (fd != fae->fae_fildes) {
if (_dup2(fd, fae->fae_fildes) == -1) {
saved_errno = errno;
(void)_close(fd);
return (saved_errno);
}
if (_close(fd) != 0) {
if (errno == EBADF)
return (EBADF);
}
}
if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1)
return (errno);
break;
case FAE_DUP2:
/* Perform a dup2() */
if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1)
return (errno);
if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1)
return (errno);
break;
case FAE_CLOSE:
/* Perform a close(), do not fail if already closed */
(void)_close(fae->fae_fildes);
break;
case FAE_CHDIR:
if (chdir(fae->fae_path) != 0)
return (errno);
break;
case FAE_FCHDIR:
if (fchdir(fae->fae_fildes) != 0)
return (errno);
break;
case FAE_CLOSEFROM:
closefrom(fae->fae_fildes);
break;
}
return (0);
}
static int
process_file_actions(const posix_spawn_file_actions_t fa)
{
posix_spawn_file_actions_entry_t *fae;
int error;
/* Replay all file descriptor modifications */
STAILQ_FOREACH(fae, &fa->fa_list, fae_list) {
error = process_file_actions_entry(fae);
if (error)
return (error);
}
return (0);
}
struct posix_spawn_args {
const char *path;
const posix_spawn_file_actions_t *fa;
const posix_spawnattr_t *sa;
char * const * argv;
char * const * envp;
int use_env_path;
volatile int error;
};
#define PSPAWN_STACK_ALIGNMENT 16
#define PSPAWN_STACK_ALIGNBYTES (PSPAWN_STACK_ALIGNMENT - 1)
#define PSPAWN_STACK_ALIGN(sz) \
(((sz) + PSPAWN_STACK_ALIGNBYTES) & ~PSPAWN_STACK_ALIGNBYTES)
#if defined(__i386__) || defined(__amd64__)
/*
* Below we'll assume that _RFORK_THREAD_STACK_SIZE is appropriately aligned for
* the posix_spawn() case where we do not end up calling _execvpe and won't ever
* try to allocate space on the stack for argv[].
*/
#define _RFORK_THREAD_STACK_SIZE 4096
_Static_assert((_RFORK_THREAD_STACK_SIZE % PSPAWN_STACK_ALIGNMENT) == 0,
"Inappropriate stack size alignment");
#endif
static int
_posix_spawn_thr(void *data)
{
struct posix_spawn_args *psa;
char * const *envp;
psa = data;
if (psa->sa != NULL) {
psa->error = process_spawnattr(*psa->sa);
if (psa->error)
_exit(127);
}
if (psa->fa != NULL) {
psa->error = process_file_actions(*psa->fa);
if (psa->error)
_exit(127);
}
envp = psa->envp != NULL ? psa->envp : environ;
if (psa->use_env_path)
_execvpe(psa->path, psa->argv, envp);
else
_execve(psa->path, psa->argv, envp);
psa->error = errno;
/* This is called in such a way that it must not exit. */
_exit(127);
}
static int
do_posix_spawn(pid_t *pid, const char *path,
const posix_spawn_file_actions_t *fa,
const posix_spawnattr_t *sa,
char * const argv[], char * const envp[], int use_env_path)
{
struct posix_spawn_args psa;
pid_t p;
#ifdef _RFORK_THREAD_STACK_SIZE
char *stack;
size_t cnt, stacksz;
stacksz = _RFORK_THREAD_STACK_SIZE;
if (use_env_path) {
/*
* We need to make sure we have enough room on the stack for the
* potential alloca() in execvPe if it gets kicked back an
* ENOEXEC from execve(2), plus the original buffer we gave
* ourselves; this protects us in the event that the caller
* intentionally or inadvertently supplies enough arguments to
* make us blow past the stack we've allocated from it.
*/
for (cnt = 0; argv[cnt] != NULL; ++cnt)
;
stacksz += MAX(3, cnt + 2) * sizeof(char *);
stacksz = PSPAWN_STACK_ALIGN(stacksz);
}
/*
* aligned_alloc is not safe to use here, because we can't guarantee
* that aligned_alloc and free will be provided by the same
* implementation. We've actively hit at least one application that
* will provide its own malloc/free but not aligned_alloc leading to
* a free by the wrong allocator.
*/
stack = malloc(stacksz);
if (stack == NULL)
return (ENOMEM);
stacksz = (((uintptr_t)stack + stacksz) & ~PSPAWN_STACK_ALIGNBYTES) -
(uintptr_t)stack;
#endif
psa.path = path;
psa.fa = fa;
psa.sa = sa;
psa.argv = argv;
psa.envp = envp;
psa.use_env_path = use_env_path;
psa.error = 0;
/*
* Passing RFSPAWN to rfork(2) gives us effectively a vfork that drops
* non-ignored signal handlers. We'll fall back to the slightly less
* ideal vfork(2) if we get an EINVAL from rfork -- this should only
* happen with newer libc on older kernel that doesn't accept
* RFSPAWN.
*/
#ifdef _RFORK_THREAD_STACK_SIZE
/*
* x86 stores the return address on the stack, so rfork(2) cannot work
* as-is because the child would clobber the return address om the
* parent. Because of this, we must use rfork_thread instead while
* almost every other arch stores the return address in a register.
*/
p = rfork_thread(RFSPAWN, stack + stacksz, _posix_spawn_thr, &psa);
free(stack);
#else
p = rfork(RFSPAWN);
if (p == 0)
/* _posix_spawn_thr does not return */
_posix_spawn_thr(&psa);
#endif
/*
* The above block should leave us in a state where we've either
* succeeded and we're ready to process the results, or we need to
* fallback to vfork() if the kernel didn't like RFSPAWN.
*/
if (p == -1 && errno == EINVAL) {
p = vfork();
if (p == 0)
/* _posix_spawn_thr does not return */
_posix_spawn_thr(&psa);
}
if (p == -1)
return (errno);
if (psa.error != 0)
/* Failed; ready to reap */
_waitpid(p, NULL, WNOHANG);
else if (pid != NULL)
/* exec succeeded */
*pid = p;
return (psa.error);
}
int
posix_spawn(pid_t *pid, const char *path,
const posix_spawn_file_actions_t *fa,
const posix_spawnattr_t *sa,
char * const argv[], char * const envp[])
{
return (do_posix_spawn(pid, path, fa, sa, argv, envp, 0));
}
int
posix_spawnp(pid_t *pid, const char *path,
const posix_spawn_file_actions_t *fa,
const posix_spawnattr_t *sa,
char * const argv[], char * const envp[])
{
return (do_posix_spawn(pid, path, fa, sa, argv, envp, 1));
}
/*
* File descriptor actions
*/
int
posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret)
{
posix_spawn_file_actions_t fa;
fa = malloc(sizeof(struct __posix_spawn_file_actions));
if (fa == NULL)
return (-1);
STAILQ_INIT(&fa->fa_list);
*ret = fa;
return (0);
}
int
posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa)
{
posix_spawn_file_actions_entry_t *fae;
while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) {
/* Remove file action entry from the queue */
STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list);
/* Deallocate file action entry */
if (fae->fae_action == FAE_OPEN ||
fae->fae_action == FAE_CHDIR)
free(fae->fae_path);
free(fae);
}
free(*fa);
return (0);
}
int
posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa,
int fildes, const char * __restrict path, int oflag, mode_t mode)
{
posix_spawn_file_actions_entry_t *fae;
int error;
if (fildes < 0)
return (EBADF);
/* Allocate object */
fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
if (fae == NULL)
return (errno);
/* Set values and store in queue */
fae->fae_action = FAE_OPEN;
fae->fae_path = strdup(path);
if (fae->fae_path == NULL) {
error = errno;
free(fae);
return (error);
}
fae->fae_fildes = fildes;
fae->fae_oflag = oflag;
fae->fae_mode = mode;
STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
return (0);
}
int
posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa,
int fildes, int newfildes)
{
posix_spawn_file_actions_entry_t *fae;
if (fildes < 0 || newfildes < 0)
return (EBADF);
/* Allocate object */
fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
if (fae == NULL)
return (errno);
/* Set values and store in queue */
fae->fae_action = FAE_DUP2;
fae->fae_fildes = fildes;
fae->fae_newfildes = newfildes;
STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
return (0);
}
int
posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa,
int fildes)
{
posix_spawn_file_actions_entry_t *fae;
if (fildes < 0)
return (EBADF);
/* Allocate object */
fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
if (fae == NULL)
return (errno);
/* Set values and store in queue */
fae->fae_action = FAE_CLOSE;
fae->fae_fildes = fildes;
STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
return (0);
}
int
posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t *
__restrict fa, const char *__restrict path)
{
posix_spawn_file_actions_entry_t *fae;
int error;
fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
if (fae == NULL)
return (errno);
fae->fae_action = FAE_CHDIR;
fae->fae_path = strdup(path);
if (fae->fae_path == NULL) {
error = errno;
free(fae);
return (error);
}
STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
return (0);
}
int
posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *__restrict fa,
int fildes)
{
posix_spawn_file_actions_entry_t *fae;
if (fildes < 0)
return (EBADF);
/* Allocate object */
fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
if (fae == NULL)
return (errno);
fae->fae_action = FAE_FCHDIR;
fae->fae_fildes = fildes;
STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
return (0);
}
int
posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t *
__restrict fa, int from)
{
posix_spawn_file_actions_entry_t *fae;
if (from < 0)
return (EBADF);
/* Allocate object */
fae = malloc(sizeof(posix_spawn_file_actions_entry_t));
if (fae == NULL)
return (errno);
fae->fae_action = FAE_CLOSEFROM;
fae->fae_fildes = from;
STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list);
return (0);
}
/*
* Spawn attributes
*/
int
posix_spawnattr_init(posix_spawnattr_t *ret)
{
posix_spawnattr_t sa;
sa = calloc(1, sizeof(struct __posix_spawnattr));
if (sa == NULL)
return (errno);
/* Set defaults as specified by POSIX, cleared above */
*ret = sa;
return (0);
}
int
posix_spawnattr_destroy(posix_spawnattr_t *sa)
{
free(*sa);
return (0);
}
int
posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa,
short * __restrict flags)
{
*flags = (*sa)->sa_flags;
return (0);
}
int
posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa,
pid_t * __restrict pgroup)
{
*pgroup = (*sa)->sa_pgroup;
return (0);
}
int
posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa,
struct sched_param * __restrict schedparam)
{
*schedparam = (*sa)->sa_schedparam;
return (0);
}
int
posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa,
int * __restrict schedpolicy)
{
*schedpolicy = (*sa)->sa_schedpolicy;
return (0);
}
int
posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa,
sigset_t * __restrict sigdefault)
{
*sigdefault = (*sa)->sa_sigdefault;
return (0);
}
int
posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa,
sigset_t * __restrict sigmask)
{
*sigmask = (*sa)->sa_sigmask;
return (0);
}
int
posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags)
{
(*sa)->sa_flags = flags;
return (0);
}
int
posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup)
{
(*sa)->sa_pgroup = pgroup;
return (0);
}
int
posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa,
const struct sched_param * __restrict schedparam)
{
(*sa)->sa_schedparam = *schedparam;
return (0);
}
int
posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy)
{
(*sa)->sa_schedpolicy = schedpolicy;
return (0);
}
int
posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa,
const sigset_t * __restrict sigdefault)
{
(*sa)->sa_sigdefault = *sigdefault;
return (0);
}
int
posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa,
const sigset_t * __restrict sigmask)
{
(*sa)->sa_sigmask = *sigmask;
return (0);
}
diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c
index 36f987ee7ae7..15df7b5f6783 100644
--- a/lib/libc/gen/pututxline.c
+++ b/lib/libc/gen/pututxline.c
@@ -1,335 +1,334 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/endian.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <utmpx.h>
#include "utxdb.h"
#include "un-namespace.h"
static FILE *
futx_open(const char *file)
{
FILE *fp;
struct stat sb;
int fd;
fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK|O_CLOEXEC, 0644);
if (fd < 0)
return (NULL);
/* Safety check: never use broken files. */
if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) {
_close(fd);
errno = EFTYPE;
return (NULL);
}
fp = fdopen(fd, "r+");
if (fp == NULL) {
_close(fd);
return (NULL);
}
return (fp);
}
static int
utx_active_add(const struct futx *fu)
{
FILE *fp;
struct futx fe;
off_t partial;
int error, ret;
partial = -1;
ret = 0;
/*
* Register user login sessions. Overwrite entries of sessions
* that have already been terminated.
*/
fp = futx_open(_PATH_UTX_ACTIVE);
if (fp == NULL)
return (-1);
while (fread(&fe, sizeof(fe), 1, fp) == 1) {
switch (fe.fu_type) {
case BOOT_TIME:
/* Leave these intact. */
break;
case USER_PROCESS:
case INIT_PROCESS:
case LOGIN_PROCESS:
case DEAD_PROCESS:
/* Overwrite when ut_id matches. */
if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) ==
0) {
ret = fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR);
goto exact;
}
if (fe.fu_type != DEAD_PROCESS)
break;
/* FALLTHROUGH */
default:
/* Allow us to overwrite unused records. */
if (partial == -1) {
partial = ftello(fp);
/*
* Distinguish errors from valid values so we
* don't overwrite good data by accident.
*/
if (partial != -1)
partial -= (off_t)sizeof(fe);
}
break;
}
}
/*
* No exact match found. Use the partial match. If no partial
* match was found, just append a new record.
*/
if (partial != -1)
ret = fseeko(fp, partial, SEEK_SET);
exact:
if (ret == -1)
error = errno;
else if (fwrite(fu, sizeof(*fu), 1, fp) < 1)
error = errno;
else
error = 0;
fclose(fp);
if (error != 0)
errno = error;
return (error == 0 ? 0 : 1);
}
static int
utx_active_remove(struct futx *fu)
{
FILE *fp;
struct futx fe;
int error, ret;
/*
* Remove user login sessions, having the same ut_id.
*/
fp = futx_open(_PATH_UTX_ACTIVE);
if (fp == NULL)
return (-1);
error = ESRCH;
ret = -1;
while (fread(&fe, sizeof(fe), 1, fp) == 1 && ret != 0)
switch (fe.fu_type) {
case USER_PROCESS:
case INIT_PROCESS:
case LOGIN_PROCESS:
if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) != 0)
continue;
/* Terminate session. */
if (fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR) == -1)
error = errno;
else if (fwrite(fu, sizeof(*fu), 1, fp) < 1)
error = errno;
else
ret = 0;
}
fclose(fp);
if (ret != 0)
errno = error;
return (ret);
}
static void
utx_active_init(const struct futx *fu)
{
int fd;
/* Initialize utx.active with a single BOOT_TIME record. */
fd = _open(_PATH_UTX_ACTIVE, O_CREAT|O_RDWR|O_TRUNC, 0644);
if (fd < 0)
return;
_write(fd, fu, sizeof(*fu));
_close(fd);
}
static void
utx_active_purge(void)
{
truncate(_PATH_UTX_ACTIVE, 0);
}
static int
utx_lastlogin_add(const struct futx *fu)
{
struct futx fe;
FILE *fp;
int error, ret;
ret = 0;
/*
* Write an entry to lastlogin. Overwrite the entry if the
* current user already has an entry. If not, append a new
* entry.
*/
fp = futx_open(_PATH_UTX_LASTLOGIN);
if (fp == NULL)
return (-1);
while (fread(&fe, sizeof fe, 1, fp) == 1) {
if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0)
continue;
/* Found a previous lastlogin entry for this user. */
ret = fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
break;
}
if (ret == -1)
error = errno;
else if (fwrite(fu, sizeof *fu, 1, fp) < 1) {
error = errno;
ret = -1;
}
fclose(fp);
if (ret == -1)
errno = error;
return (ret);
}
static void
utx_lastlogin_upgrade(void)
{
struct stat sb;
int fd;
fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR|O_CLOEXEC, 0644);
if (fd < 0)
return;
/*
* Truncate broken lastlogin files. In the future we should
* check for older versions of the file format here and try to
* upgrade it.
*/
if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0)
ftruncate(fd, 0);
_close(fd);
}
static int
utx_log_add(const struct futx *fu)
{
struct iovec vec[2];
int error, fd;
uint16_t l;
/*
* Append an entry to the log file. We only need to append
* records to this file, so to conserve space, trim any trailing
* zero-bytes. Prepend a length field, indicating the length of
* the record, excluding the length field itself.
*/
for (l = sizeof(*fu); l > 0 && ((const char *)fu)[l - 1] == '\0'; l--) ;
vec[0].iov_base = &l;
vec[0].iov_len = sizeof(l);
vec[1].iov_base = __DECONST(void *, fu);
vec[1].iov_len = l;
l = htobe16(l);
fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND|O_CLOEXEC, 0644);
if (fd < 0)
return (-1);
if (_writev(fd, vec, 2) == -1)
error = errno;
else
error = 0;
_close(fd);
if (error != 0)
errno = error;
return (error == 0 ? 0 : 1);
}
struct utmpx *
pututxline(const struct utmpx *utmpx)
{
struct futx fu;
int bad;
bad = 0;
utx_to_futx(utmpx, &fu);
switch (fu.fu_type) {
case BOOT_TIME:
utx_active_init(&fu);
utx_lastlogin_upgrade();
break;
case SHUTDOWN_TIME:
utx_active_purge();
break;
case OLD_TIME:
case NEW_TIME:
break;
case USER_PROCESS:
bad |= utx_active_add(&fu);
bad |= utx_lastlogin_add(&fu);
break;
#if 0 /* XXX: Are these records of any use to us? */
case INIT_PROCESS:
case LOGIN_PROCESS:
bad |= utx_active_add(&fu);
break;
#endif
case DEAD_PROCESS:
/*
* In case writing a logout entry fails, never attempt
* to write it to utx.log. The logout entry's ut_id
* might be invalid.
*/
if (utx_active_remove(&fu) != 0)
return (NULL);
break;
default:
errno = EINVAL;
return (NULL);
}
bad |= utx_log_add(&fu);
return (bad ? NULL : futx_to_utx(&fu));
}
diff --git a/lib/libc/gen/readdir-compat11.c b/lib/libc/gen/readdir-compat11.c
index 30cec5acd0e6..cfc964733264 100644
--- a/lib/libc/gen/readdir-compat11.c
+++ b/lib/libc/gen/readdir-compat11.c
@@ -1,115 +1,114 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)readdir.c 8.3 (Berkeley) 9/29/94
* From: FreeBSD: head/lib/libc/gen/readdir.c 314436 2017-02-28 23:42:47Z imp
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#define _WANT_FREEBSD11_DIRENT
#include <dirent.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "gen-private.h"
#include "telldir.h"
#include "gen-compat.h"
static bool
freebsd11_cvtdirent(struct freebsd11_dirent *dstdp, struct dirent *srcdp)
{
if (srcdp->d_namlen >= sizeof(dstdp->d_name))
return (false);
dstdp->d_type = srcdp->d_type;
dstdp->d_namlen = srcdp->d_namlen;
dstdp->d_fileno = srcdp->d_fileno; /* truncate */
dstdp->d_reclen = FREEBSD11_DIRSIZ(dstdp);
bcopy(srcdp->d_name, dstdp->d_name, dstdp->d_namlen);
bzero(dstdp->d_name + dstdp->d_namlen,
dstdp->d_reclen - offsetof(struct freebsd11_dirent, d_name) -
dstdp->d_namlen);
return (true);
}
struct freebsd11_dirent *
freebsd11_readdir(DIR *dirp)
{
struct freebsd11_dirent *dstdp;
struct dirent *dp;
if (__isthreaded)
_pthread_mutex_lock(&dirp->dd_lock);
dp = _readdir_unlocked(dirp, RDU_SKIP);
if (dp != NULL) {
if (dirp->dd_compat_de == NULL)
dirp->dd_compat_de = malloc(sizeof(struct
freebsd11_dirent));
if (freebsd11_cvtdirent(dirp->dd_compat_de, dp))
dstdp = dirp->dd_compat_de;
else
dstdp = NULL;
} else
dstdp = NULL;
if (__isthreaded)
_pthread_mutex_unlock(&dirp->dd_lock);
return (dstdp);
}
int
freebsd11_readdir_r(DIR *dirp, struct freebsd11_dirent *entry,
struct freebsd11_dirent **result)
{
struct dirent xentry, *xresult;
int error;
error = __readdir_r(dirp, &xentry, &xresult);
if (error != 0)
return (error);
if (xresult != NULL) {
if (freebsd11_cvtdirent(entry, &xentry))
*result = entry;
else /* should not happen due to RDU_SHORT */
*result = NULL;
} else
*result = NULL;
return (0);
}
__sym_compat(readdir, freebsd11_readdir, FBSD_1.0);
__sym_compat(readdir_r, freebsd11_readdir_r, FBSD_1.0);
diff --git a/lib/libc/gen/readpassphrase.c b/lib/libc/gen/readpassphrase.c
index c6eb63f1469c..5319d3e634af 100644
--- a/lib/libc/gen/readpassphrase.c
+++ b/lib/libc/gen/readpassphrase.c
@@ -1,201 +1,200 @@
/* $OpenBSD: readpassphrase.c,v 1.24 2013/11/24 23:51:29 deraadt Exp $ */
/*
* Copyright (c) 2000-2002, 2007, 2010
* Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <pwd.h>
#include <signal.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <readpassphrase.h>
#include "un-namespace.h"
#include "libc_private.h"
static volatile sig_atomic_t signo[NSIG];
static void handler(int);
char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
ssize_t nr;
int input, output, save_errno, i, need_restart, input_is_tty;
char ch, *p, *end;
struct termios term, oterm;
struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm;
struct sigaction savetstp, savettin, savettou, savepipe;
/* I suppose we could alloc on demand in this case (XXX). */
if (bufsiz == 0) {
errno = EINVAL;
return(NULL);
}
restart:
for (i = 0; i < NSIG; i++)
signo[i] = 0;
nr = -1;
save_errno = 0;
need_restart = 0;
/*
* Read and write to /dev/tty if available. If not, read from
* stdin and write to stderr unless a tty is required.
*/
input_is_tty = 0;
if (!(flags & RPP_STDIN)) {
input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC);
if (input == -1) {
if (flags & RPP_REQUIRE_TTY) {
errno = ENOTTY;
return(NULL);
}
input = STDIN_FILENO;
output = STDERR_FILENO;
} else {
input_is_tty = 1;
}
} else {
input = STDIN_FILENO;
output = STDERR_FILENO;
}
/*
* Turn off echo if possible.
* If we are using a tty but are not the foreground pgrp this will
* generate SIGTTOU, so do it *before* installing the signal handlers.
*/
if (input_is_tty && tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON))
term.c_lflag &= ~(ECHO | ECHONL);
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
(void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term);
} else {
memset(&term, 0, sizeof(term));
term.c_lflag |= ECHO;
memset(&oterm, 0, sizeof(oterm));
oterm.c_lflag |= ECHO;
}
/*
* Catch signals that would otherwise cause the user to end
* up with echo turned off in the shell. Don't worry about
* things like SIGXCPU and SIGVTALRM for now.
*/
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0; /* don't restart system calls */
sa.sa_handler = handler;
(void)__libc_sigaction(SIGALRM, &sa, &savealrm);
(void)__libc_sigaction(SIGHUP, &sa, &savehup);
(void)__libc_sigaction(SIGINT, &sa, &saveint);
(void)__libc_sigaction(SIGPIPE, &sa, &savepipe);
(void)__libc_sigaction(SIGQUIT, &sa, &savequit);
(void)__libc_sigaction(SIGTERM, &sa, &saveterm);
(void)__libc_sigaction(SIGTSTP, &sa, &savetstp);
(void)__libc_sigaction(SIGTTIN, &sa, &savettin);
(void)__libc_sigaction(SIGTTOU, &sa, &savettou);
if (!(flags & RPP_STDIN))
(void)_write(output, prompt, strlen(prompt));
end = buf + bufsiz - 1;
p = buf;
while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') {
if (p < end) {
if ((flags & RPP_SEVENBIT))
ch &= 0x7f;
if (isalpha((unsigned char)ch)) {
if ((flags & RPP_FORCELOWER))
ch = (char)tolower((unsigned char)ch);
if ((flags & RPP_FORCEUPPER))
ch = (char)toupper((unsigned char)ch);
}
*p++ = ch;
}
}
*p = '\0';
save_errno = errno;
if (!(term.c_lflag & ECHO))
(void)_write(output, "\n", 1);
/* Restore old terminal settings and signals. */
if (memcmp(&term, &oterm, sizeof(term)) != 0) {
while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 &&
errno == EINTR && !signo[SIGTTOU])
continue;
}
(void)__libc_sigaction(SIGALRM, &savealrm, NULL);
(void)__libc_sigaction(SIGHUP, &savehup, NULL);
(void)__libc_sigaction(SIGINT, &saveint, NULL);
(void)__libc_sigaction(SIGQUIT, &savequit, NULL);
(void)__libc_sigaction(SIGPIPE, &savepipe, NULL);
(void)__libc_sigaction(SIGTERM, &saveterm, NULL);
(void)__libc_sigaction(SIGTSTP, &savetstp, NULL);
(void)__libc_sigaction(SIGTTIN, &savettin, NULL);
(void)__libc_sigaction(SIGTTOU, &savettou, NULL);
if (input_is_tty)
(void)_close(input);
/*
* If we were interrupted by a signal, resend it to ourselves
* now that we have restored the signal handlers.
*/
for (i = 0; i < NSIG; i++) {
if (signo[i]) {
kill(getpid(), i);
switch (i) {
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
need_restart = 1;
}
}
}
if (need_restart)
goto restart;
if (save_errno)
errno = save_errno;
return(nr == -1 ? NULL : buf);
}
char *
getpass(const char *prompt)
{
static char buf[_PASSWORD_LEN + 1];
if (readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF) == NULL)
buf[0] = '\0';
return(buf);
}
static void handler(int s)
{
signo[s] = 1;
}
diff --git a/lib/libc/gen/recvmmsg.c b/lib/libc/gen/recvmmsg.c
index 6fa400f00c22..24c4abf58287 100644
--- a/lib/libc/gen/recvmmsg.c
+++ b/lib/libc/gen/recvmmsg.c
@@ -1,95 +1,94 @@
/*
* Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <errno.h>
#include <poll.h>
#include <stddef.h>
#include "libc_private.h"
ssize_t
recvmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags,
const struct timespec *__restrict timeout)
{
struct pollfd pfd[1];
size_t i, rcvd;
ssize_t ret;
int res;
short ev;
if (timeout != NULL) {
pfd[0].fd = s;
pfd[0].revents = 0;
pfd[0].events = ev = POLLIN | POLLRDNORM | POLLRDBAND |
POLLPRI;
res = ppoll(&pfd[0], 1, timeout, NULL);
if (res == -1 || res == 0)
return (res);
if (pfd[0].revents & POLLNVAL) {
errno = EBADF;
return (-1);
}
if ((pfd[0].revents & ev) == 0) {
errno = ETIMEDOUT;
return (-1);
}
}
ret = __sys_recvmsg(s, &msgvec[0].msg_hdr, flags);
if (ret == -1)
return (ret);
msgvec[0].msg_len = ret;
/*
* Do non-blocking receive for second and later messages if
* WAITFORONE is set.
*/
if (flags & MSG_WAITFORONE)
flags |= MSG_DONTWAIT;
rcvd = 1;
for (i = rcvd; i < vlen; i++, rcvd++) {
ret = __sys_recvmsg(s, &msgvec[i].msg_hdr, flags);
if (ret == -1) {
/* We have received messages. Let caller know
* about the data received, socket error is
* returned on next invocation.
*/
return (rcvd);
}
/* Save received bytes. */
msgvec[i].msg_len = ret;
}
return (rcvd);
}
diff --git a/lib/libc/gen/scandir-compat11.c b/lib/libc/gen/scandir-compat11.c
index b5c9846c2798..5ed35fee7680 100644
--- a/lib/libc/gen/scandir-compat11.c
+++ b/lib/libc/gen/scandir-compat11.c
@@ -1,154 +1,153 @@
/*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* From: @(#)scandir.c 8.3 (Berkeley) 1/2/94
* From: FreeBSD: head/lib/libc/gen/scandir.c 317372 2017-04-24 14:56:41Z pfg
*/
-#include <sys/cdefs.h>
/*
* Scan the directory dirname calling select to make a list of selected
* directory entries then sort using qsort and compare routine dcomp.
* Returns the number of entries and a pointer to a list of pointers to
* struct dirent (through namelist). Returns -1 if there were any errors.
*/
#include "namespace.h"
#define _WANT_FREEBSD11_DIRENT
#include <dirent.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#include "gen-compat.h"
/*
* scandir_b@FBSD_1.4 was never exported from libc.so.7 due to a
* mistake, so there is no use of exporting it now with some earlier
* symbol version. As result, we do not need to implement compat
* function freebsd11_scandir_b().
*/
#define SELECT(x) select(x)
static int freebsd11_scandir_thunk_cmp(const void *p1, const void *p2,
void *thunk);
int
freebsd11_scandir(const char *dirname, struct freebsd11_dirent ***namelist,
int (*select)(const struct freebsd11_dirent *),
int (*dcomp)(const struct freebsd11_dirent **,
const struct freebsd11_dirent **))
{
struct freebsd11_dirent *d, *p, **names = NULL;
size_t arraysz, numitems;
DIR *dirp;
if ((dirp = opendir(dirname)) == NULL)
return(-1);
numitems = 0;
arraysz = 32; /* initial estimate of the array size */
names = (struct freebsd11_dirent **)malloc(
arraysz * sizeof(struct freebsd11_dirent *));
if (names == NULL)
goto fail;
while ((d = freebsd11_readdir(dirp)) != NULL) {
if (select != NULL && !SELECT(d))
continue; /* just selected names */
/*
* Make a minimum size copy of the data
*/
p = (struct freebsd11_dirent *)malloc(FREEBSD11_DIRSIZ(d));
if (p == NULL)
goto fail;
p->d_fileno = d->d_fileno;
p->d_type = d->d_type;
p->d_reclen = d->d_reclen;
p->d_namlen = d->d_namlen;
bcopy(d->d_name, p->d_name, p->d_namlen + 1);
/*
* Check to make sure the array has space left and
* realloc the maximum size.
*/
if (numitems >= arraysz) {
struct freebsd11_dirent **names2;
names2 = reallocarray(names, arraysz,
2 * sizeof(struct freebsd11_dirent *));
if (names2 == NULL) {
free(p);
goto fail;
}
names = names2;
arraysz *= 2;
}
names[numitems++] = p;
}
closedir(dirp);
if (numitems && dcomp != NULL)
qsort_r(names, numitems, sizeof(struct freebsd11_dirent *),
freebsd11_scandir_thunk_cmp, &dcomp);
*namelist = names;
return (numitems);
fail:
while (numitems > 0)
free(names[--numitems]);
free(names);
closedir(dirp);
return (-1);
}
/*
* Alphabetic order comparison routine for those who want it.
* POSIX 2008 requires that alphasort() uses strcoll().
*/
int
freebsd11_alphasort(const struct freebsd11_dirent **d1,
const struct freebsd11_dirent **d2)
{
return (strcoll((*d1)->d_name, (*d2)->d_name));
}
static int
freebsd11_scandir_thunk_cmp(const void *p1, const void *p2, void *thunk)
{
int (*dc)(const struct freebsd11_dirent **, const struct
freebsd11_dirent **);
dc = *(int (**)(const struct freebsd11_dirent **,
const struct freebsd11_dirent **))thunk;
return (dc((const struct freebsd11_dirent **)p1,
(const struct freebsd11_dirent **)p2));
}
__sym_compat(alphasort, freebsd11_alphasort, FBSD_1.0);
__sym_compat(scandir, freebsd11_scandir, FBSD_1.0);
diff --git a/lib/libc/gen/seed48.c b/lib/libc/gen/seed48.c
index 230348ff0fa8..258c4bac3c9f 100644
--- a/lib/libc/gen/seed48.c
+++ b/lib/libc/gen/seed48.c
@@ -1,37 +1,36 @@
/*
* Copyright (c) 1993 Martin Birgmeier
* All rights reserved.
*
* You may redistribute unmodified or modified versions of this source
* code provided that the above copyright notice and this and the
* following conditions are retained.
*
* This software is provided ``as is'', and comes with no warranties
* of any kind. I shall in no event be liable for anything that happens
* to anyone/anything when using this software.
*/
-#include <sys/cdefs.h>
#include "rand48.h"
extern unsigned short _rand48_seed[3];
extern unsigned short _rand48_mult[3];
extern unsigned short _rand48_add;
unsigned short *
seed48(unsigned short xseed[3])
{
static unsigned short sseed[3];
sseed[0] = _rand48_seed[0];
sseed[1] = _rand48_seed[1];
sseed[2] = _rand48_seed[2];
_rand48_seed[0] = xseed[0];
_rand48_seed[1] = xseed[1];
_rand48_seed[2] = xseed[2];
_rand48_mult[0] = RAND48_MULT_0;
_rand48_mult[1] = RAND48_MULT_1;
_rand48_mult[2] = RAND48_MULT_2;
_rand48_add = RAND48_ADD;
return sseed;
}
diff --git a/lib/libc/gen/semctl.c b/lib/libc/gen/semctl.c
index 84df40e4c9af..374f01508236 100644
--- a/lib/libc/gen/semctl.c
+++ b/lib/libc/gen/semctl.c
@@ -1,91 +1,90 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#ifndef NO_COMPAT7
#define _WANT_SEMUN_OLD
#endif
#define _WANT_SEMUN
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdarg.h>
#include <stdlib.h>
int __semctl(int semid, int semnum, int cmd, union semun *arg);
#ifndef NO_COMPAT7
int freebsd7___semctl(int semid, int semnum, int cmd, union semun_old *arg);
int freebsd7_semctl(int semid, int semnum, int cmd, ...);
#endif
int
semctl(int semid, int semnum, int cmd, ...)
{
va_list ap;
union semun semun;
union semun *semun_ptr;
va_start(ap, cmd);
if (cmd == IPC_SET || cmd == IPC_STAT || cmd == GETALL
|| cmd == SETVAL || cmd == SETALL) {
semun = va_arg(ap, union semun);
semun_ptr = &semun;
} else {
semun_ptr = NULL;
}
va_end(ap);
return (__semctl(semid, semnum, cmd, semun_ptr));
}
#ifndef NO_COMPAT7
int
freebsd7_semctl(int semid, int semnum, int cmd, ...)
{
va_list ap;
union semun_old semun;
union semun_old *semun_ptr;
va_start(ap, cmd);
if (cmd == IPC_SET || cmd == IPC_STAT || cmd == GETALL
|| cmd == SETVAL || cmd == SETALL) {
semun = va_arg(ap, union semun_old);
semun_ptr = &semun;
} else {
semun_ptr = NULL;
}
va_end(ap);
return (freebsd7___semctl(semid, semnum, cmd, semun_ptr));
}
__sym_compat(semctl, freebsd7_semctl, FBSD_1.0);
#endif
diff --git a/lib/libc/gen/sendmmsg.c b/lib/libc/gen/sendmmsg.c
index 72b551792741..41eb62d1e0c8 100644
--- a/lib/libc/gen/sendmmsg.c
+++ b/lib/libc/gen/sendmmsg.c
@@ -1,62 +1,61 @@
/*
* Copyright (c) 2016 Boris Astardzhiev, Smartcom-Bulgaria AD
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "libc_private.h"
ssize_t
sendmmsg(int s, struct mmsghdr *__restrict msgvec, size_t vlen, int flags)
{
size_t i, sent;
ssize_t ret;
sent = 0;
for (i = 0; i < vlen; i++, sent++) {
ret = __sys_sendmsg(s, &msgvec[i].msg_hdr, flags);
if (ret == -1) {
if (sent != 0) {
/*
* We have sent messages. Let caller
* know about the data sent, socket
* error is returned on next
* invocation.
*/
return (sent);
}
return (ret);
}
/* Save sent bytes. */
msgvec[i].msg_len = ret;
}
return (sent);
}
diff --git a/lib/libc/gen/setproctitle.c b/lib/libc/gen/setproctitle.c
index 9c73fd77ca42..715951a8c96d 100644
--- a/lib/libc/gen/setproctitle.c
+++ b/lib/libc/gen/setproctitle.c
@@ -1,219 +1,218 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1995 Peter Wemm
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/elf_common.h>
#include <sys/exec.h>
#include <sys/sysctl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
/*
* Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and
* in different locations.
* 1: old_ps_strings at the very top of the stack.
* 2: old_ps_strings at SPARE_USRSPACE below the top of the stack.
* 3: ps_strings at the very top of the stack.
* We only support a kernel providing #3 style ps_strings.
*
* For historical purposes, a definition of the old ps_strings structure
* and location is preserved below:
struct old_ps_strings {
char *old_ps_argvstr;
int old_ps_nargvstr;
char *old_ps_envstr;
int old_ps_nenvstr;
};
#define OLD_PS_STRINGS ((struct old_ps_strings *) \
(USRSTACK - SPARE_USRSPACE - sizeof(struct old_ps_strings)))
*/
#include <stdarg.h>
#define SPT_BUFSIZE 2048 /* from other parts of sendmail */
static char *
setproctitle_internal(const char *fmt, va_list ap)
{
static struct ps_strings *ps_strings;
static char *buf = NULL;
static char *obuf = NULL;
static char **oargv;
static int oargc = -1;
static char *nargv[2] = { NULL, NULL };
char **nargvp;
int nargc;
int i;
size_t len;
unsigned long ul_ps_strings;
if (buf == NULL) {
buf = malloc(SPT_BUFSIZE);
if (buf == NULL)
return (NULL);
nargv[0] = buf;
}
if (obuf == NULL ) {
obuf = malloc(SPT_BUFSIZE);
if (obuf == NULL)
return (NULL);
*obuf = '\0';
}
if (fmt) {
buf[SPT_BUFSIZE - 1] = '\0';
if (fmt[0] == '-') {
/* skip program name prefix */
fmt++;
len = 0;
} else {
/* print program name heading for grep */
(void)snprintf(buf, SPT_BUFSIZE, "%s: ", _getprogname());
len = strlen(buf);
}
/* print the argument string */
(void)vsnprintf(buf + len, SPT_BUFSIZE - len, fmt, ap);
nargvp = nargv;
nargc = 1;
} else if (*obuf != '\0') {
/* Idea from NetBSD - reset the title on fmt == NULL */
nargvp = oargv;
nargc = oargc;
} else
/* Nothing to restore */
return (NULL);
if (ps_strings == NULL)
(void)_elf_aux_info(AT_PS_STRINGS, &ps_strings,
sizeof(ps_strings));
if (ps_strings == NULL) {
len = sizeof(ul_ps_strings);
if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL,
0) == -1)
return (NULL);
ps_strings = (struct ps_strings *)ul_ps_strings;
}
if (ps_strings == NULL)
return (NULL);
/*
* PS_STRINGS points to zeroed memory on a style #2 kernel.
* Should not happen.
*/
if (ps_strings->ps_argvstr == NULL)
return (NULL);
/* style #3 */
if (oargc == -1) {
/* Record our original args */
oargc = ps_strings->ps_nargvstr;
oargv = ps_strings->ps_argvstr;
for (i = len = 0; i < oargc; i++) {
/*
* The program may have scribbled into its
* argv array, e.g., to remove some arguments.
* If that has happened, break out before
* trying to call strlen on a NULL pointer.
*/
if (oargv[i] == NULL) {
oargc = i;
break;
}
snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s",
len != 0 ? " " : "", oargv[i]);
if (len != 0)
len++;
len += strlen(oargv[i]);
if (len >= SPT_BUFSIZE)
break;
}
}
ps_strings->ps_nargvstr = nargc;
ps_strings->ps_argvstr = nargvp;
return (nargvp[0]);
}
static int fast_update = 0;
void
setproctitle_fast(const char *fmt, ...)
{
va_list ap;
char *buf;
int oid[4];
va_start(ap, fmt);
buf = setproctitle_internal(fmt, ap);
va_end(ap);
if (buf && !fast_update) {
/* Tell the kernel to start looking in user-space */
oid[0] = CTL_KERN;
oid[1] = KERN_PROC;
oid[2] = KERN_PROC_ARGS;
oid[3] = -1;
sysctl(oid, 4, 0, 0, "", 0);
fast_update = 1;
}
}
void
setproctitle(const char *fmt, ...)
{
va_list ap;
char *buf;
int oid[4];
va_start(ap, fmt);
buf = setproctitle_internal(fmt, ap);
va_end(ap);
if (buf != NULL) {
/* Set the title into the kernel cached command line */
oid[0] = CTL_KERN;
oid[1] = KERN_PROC;
oid[2] = KERN_PROC_ARGS;
oid[3] = -1;
sysctl(oid, 4, 0, 0, buf, strlen(buf) + 1);
fast_update = 0;
}
}
diff --git a/lib/libc/gen/setprogname.c b/lib/libc/gen/setprogname.c
index 849ff9188d47..853c5f277386 100644
--- a/lib/libc/gen/setprogname.c
+++ b/lib/libc/gen/setprogname.c
@@ -1,17 +1,16 @@
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <string.h>
#include "libc_private.h"
void
setprogname(const char *progname)
{
const char *p;
p = strrchr(progname, '/');
if (p != NULL)
__progname = p + 1;
else
__progname = progname;
}
diff --git a/lib/libc/gen/statvfs.c b/lib/libc/gen/statvfs.c
index a7190f9a707d..94c61f0cd73d 100644
--- a/lib/libc/gen/statvfs.c
+++ b/lib/libc/gen/statvfs.c
@@ -1,158 +1,157 @@
/*
* Copyright 2002 Massachusetts Institute of Technology
*
* Permission to use, copy, modify, and distribute this software and
* its documentation for any purpose and without fee is hereby
* granted, provided that both the above copyright notice and this
* permission notice appear in all copies, that both the above
* copyright notice and this permission notice appear in all
* supporting documentation, and that the name of M.I.T. not be used
* in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission. M.I.T. makes
* no representations about the suitability of this software for any
* purpose. It is provided "as is" without express or implied
* warranty.
*
* THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
* ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
* SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/statvfs.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include "un-namespace.h"
static int sfs2svfs(const struct statfs *from, struct statvfs *to);
int
fstatvfs(int fd, struct statvfs *result)
{
struct statfs sfs;
int rv;
long pcval;
rv = _fstatfs(fd, &sfs);
if (rv != 0)
return (rv);
rv = sfs2svfs(&sfs, result);
if (rv != 0)
return (rv);
/*
* Whether pathconf's -1 return means error or unlimited does not
* make any difference in this best-effort implementation.
*/
pcval = _fpathconf(fd, _PC_NAME_MAX);
if (pcval == -1)
result->f_namemax = ~0UL;
else
result->f_namemax = (unsigned long)pcval;
return (0);
}
int
statvfs(const char * __restrict path, struct statvfs * __restrict result)
{
struct statfs sfs;
int rv;
long pcval;
rv = statfs(path, &sfs);
if (rv != 0)
return (rv);
sfs2svfs(&sfs, result);
/*
* Whether pathconf's -1 return means error or unlimited does not
* make any difference in this best-effort implementation.
*/
pcval = pathconf(path, _PC_NAME_MAX);
if (pcval == -1)
result->f_namemax = ~0UL;
else
result->f_namemax = (unsigned long)pcval;
return (0);
}
static int
sfs2svfs(const struct statfs *from, struct statvfs *to)
{
static const struct statvfs zvfs;
*to = zvfs;
if (from->f_flags & MNT_RDONLY)
to->f_flag |= ST_RDONLY;
if (from->f_flags & MNT_NOSUID)
to->f_flag |= ST_NOSUID;
/* XXX should we clamp negative values? */
#define COPY(field) \
do { \
to->field = from->field; \
if (from->field != to->field) { \
errno = EOVERFLOW; \
return (-1); \
} \
} while(0)
COPY(f_bavail);
COPY(f_bfree);
COPY(f_blocks);
COPY(f_ffree);
COPY(f_files);
to->f_bsize = from->f_iosize;
to->f_frsize = from->f_bsize;
to->f_favail = to->f_ffree;
return (0);
}
#ifdef MAIN
#include <err.h>
#include <stdint.h>
#include <stdio.h>
int
main(int argc, char **argv)
{
struct statvfs buf;
if (statvfs(argv[1], &buf) < 0)
err(1, "statvfs");
#define SHOW(field) \
printf(#field ": %ju\n", (uintmax_t)buf.field)
SHOW(f_bavail);
SHOW(f_bfree);
SHOW(f_blocks);
SHOW(f_favail);
SHOW(f_ffree);
SHOW(f_files);
SHOW(f_bsize);
SHOW(f_frsize);
SHOW(f_namemax);
printf("f_flag: %lx\n", (unsigned long)buf.f_flag);
return 0;
}
#endif /* MAIN */
diff --git a/lib/libc/gen/sysctlbyname.c b/lib/libc/gen/sysctlbyname.c
index 017dba86c11a..8cc9599f7a95 100644
--- a/lib/libc/gen/sysctlbyname.c
+++ b/lib/libc/gen/sysctlbyname.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2019 Pawel Biernacki, Mysterious Code Ltd.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <string.h>
extern int __sysctlbyname(const char *name, size_t namelen, void *oldp,
size_t *oldlenp, const void *newp, size_t newlen);
int
sysctlbyname(const char *name, void *oldp, size_t *oldlenp,
const void *newp, size_t newlen)
{
size_t len;
int oid[2];
if (__predict_true(strncmp(name, "user.", 5) != 0)) {
len = strlen(name);
return (__sysctlbyname(name, len, oldp, oldlenp, newp,
newlen));
} else {
len = nitems(oid);
if (sysctlnametomib(name, oid, &len) == -1)
return (-1);
return (sysctl(oid, (u_int)len, oldp, oldlenp, newp,
newlen));
}
}
diff --git a/lib/libc/gen/sysctlnametomib.c b/lib/libc/gen/sysctlnametomib.c
index d2e33f5690ff..e45d23e10714 100644
--- a/lib/libc/gen/sysctlnametomib.c
+++ b/lib/libc/gen/sysctlnametomib.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2001 The FreeBSD Project. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <string.h>
/*
* This function uses a presently undocumented interface to the kernel
* to walk the tree and get the type so it can print the value.
* This interface is under work and consideration, and should probably
* be killed with a big axe by the first person who can find the time.
* (be aware though, that the proper interface isn't as obvious as it
* may seem, there are various conflicting requirements.
*/
int
sysctlnametomib(const char *name, int *mibp, size_t *sizep)
{
int oid[2];
int error;
oid[0] = CTL_SYSCTL;
oid[1] = CTL_SYSCTL_NAME2OID;
*sizep *= sizeof(int);
error = sysctl(oid, 2, mibp, sizep, name, strlen(name));
*sizep /= sizeof(int);
return (error);
}
diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c
index c81ef7e9ad0e..3c1a5472c0e5 100644
--- a/lib/libc/gen/tls.c
+++ b/lib/libc/gen/tls.c
@@ -1,451 +1,450 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Doug Rabson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Define stubs for TLS internals so that programs and libraries can
* link. These functions will be replaced by functional versions at
* runtime from ld-elf.so.1.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdlib.h>
#include <string.h>
#include <elf.h>
#include <unistd.h>
#include "rtld.h"
#include "libc_private.h"
#define tls_assert(cond) ((cond) ? (void) 0 : \
(tls_msg(#cond ": assert failed: " __FILE__ ":" \
__XSTRING(__LINE__) "\n"), abort()))
#define tls_msg(s) write(STDOUT_FILENO, s, strlen(s))
/* Provided by jemalloc to avoid bootstrapping issues. */
void *__je_bootstrap_malloc(size_t size);
void *__je_bootstrap_calloc(size_t num, size_t size);
void __je_bootstrap_free(void *ptr);
__weak_reference(__libc_allocate_tls, _rtld_allocate_tls);
__weak_reference(__libc_free_tls, _rtld_free_tls);
#ifdef __i386__
__weak_reference(___libc_tls_get_addr, ___tls_get_addr);
__attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *);
#endif
void * __libc_tls_get_addr(void *);
__weak_reference(__libc_tls_get_addr, __tls_get_addr);
void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign);
void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign);
void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign);
#ifndef PIC
static size_t libc_tls_static_space;
static size_t libc_tls_init_size;
static size_t libc_tls_init_align;
static void *libc_tls_init;
#endif
void *
__libc_tls_get_addr(void *vti)
{
uintptr_t *dtv;
tls_index *ti;
dtv = _tcb_get()->tcb_dtv;
ti = vti;
return ((char *)(dtv[ti->ti_module + 1] + ti->ti_offset) +
TLS_DTV_OFFSET);
}
#ifdef __i386__
/* GNU ABI */
__attribute__((__regparm__(1)))
void *
___libc_tls_get_addr(void *vti)
{
return (__libc_tls_get_addr(vti));
}
#endif
#ifndef PIC
static void *
libc_malloc_aligned(size_t size, size_t align)
{
void *mem, *res;
if (align < sizeof(void *))
align = sizeof(void *);
mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1);
res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align);
*(void **)((uintptr_t)res - sizeof(void *)) = mem;
return (res);
}
static void
libc_free_aligned(void *ptr)
{
void *mem;
uintptr_t x;
if (ptr == NULL)
return;
x = (uintptr_t)ptr;
x -= sizeof(void *);
mem = *(void **)x;
__je_bootstrap_free(mem);
}
#ifdef TLS_VARIANT_I
/*
* There are two versions of variant I of TLS
*
* - ARM and aarch64 uses original variant I as is described in [1] and [2],
* where TP points to start of TCB followed by aligned TLS segment.
* Both TCB and TLS must be aligned to alignment of TLS section. The TCB[0]
* points to DTV vector and DTV values are real addresses (without bias).
* Note: for Local Exec TLS Model, the offsets from TP (TCB in this case) to
* TLS variables are computed by linker, so we cannot overalign TLS section.
*
* - PowerPC and RISC-V use modified version of variant I, described in [3]
* where TP points (with bias) to TLS and TCB immediately precedes TLS without
* any alignment gap[4]. Only TLS should be aligned. The TCB[0] points to DTV
* vector and DTV values are biased by constant value (TLS_DTV_OFFSET) from
* real addresses[5].
*
* [1] Ulrich Drepper: ELF Handling for Thread-Local Storage
* www.akkadia.org/drepper/tls.pdf
*
* [2] ARM IHI 0045E: Addenda to, and Errata in, the ABI for the ARM(r)
* Architecture
* infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf
*
* [3] OpenPOWER: Power Architecture 64-Bit ELF V2 ABI Specification
* https://members.openpowerfoundation.org/document/dl/576
*
* [4] Its unclear if "without any alignment gap" is hard ABI requirement,
* but we must follow this rule due to suboptimal _tcb_set()
* (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but
* TCB as argument.
*
* [5] I'm not able to validate "values are biased" assertions.
*/
/*
* Return pointer to allocated TLS block
*/
static void *
get_tls_block_ptr(void *tcb, size_t tcbsize)
{
size_t extra_size, post_size, pre_size, tls_block_size;
/* Compute fragments sizes. */
extra_size = tcbsize - TLS_TCB_SIZE;
#if defined(__aarch64__) || defined(__arm__)
post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE;
#else
post_size = 0;
#endif
tls_block_size = tcbsize + post_size;
pre_size = roundup2(tls_block_size, libc_tls_init_align) -
tls_block_size;
return ((char *)tcb - pre_size - extra_size);
}
/*
* Free Static TLS using the Variant I method. The tcbsize
* and tcbalign parameters must be the same as those used to allocate
* the block.
*/
void
__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused)
{
Elf_Addr *dtv;
Elf_Addr **tls;
tls = (Elf_Addr **)tcb;
dtv = tls[0];
__je_bootstrap_free(dtv);
libc_free_aligned(get_tls_block_ptr(tcb, tcbsize));
}
/*
* Allocate Static TLS using the Variant I method.
*
* To handle all above requirements, we setup the following layout for
* TLS block:
* (whole memory block is aligned with MAX(TLS_TCB_ALIGN, tls_init_align))
*
* +----------+--------------+--------------+-----------+------------------+
* | pre gap | extended TCB | TCB | post gap | TLS segment |
* | pre_size | extra_size | TLS_TCB_SIZE | post_size | tls_static_space |
* +----------+--------------+--------------+-----------+------------------+
*
* where:
* extra_size is tcbsize - TLS_TCB_SIZE
* post_size is used to adjust TCB to TLS alignment for first version of TLS
* layout and is always 0 for second version.
* pre_size is used to adjust TCB alignment for first version and to adjust
* TLS alignment for second version.
*
*/
void *
__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign)
{
Elf_Addr *dtv, **tcb;
char *tls_block, *tls;
size_t extra_size, maxalign, post_size, pre_size, tls_block_size;
if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE)
return (oldtcb);
tls_assert(tcbalign >= TLS_TCB_ALIGN);
maxalign = MAX(tcbalign, libc_tls_init_align);
/* Compute fragmets sizes. */
extra_size = tcbsize - TLS_TCB_SIZE;
#if defined(__aarch64__) || defined(__arm__)
post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE;
#else
post_size = 0;
#endif
tls_block_size = tcbsize + post_size;
pre_size = roundup2(tls_block_size, libc_tls_init_align) -
tls_block_size;
tls_block_size += pre_size + libc_tls_static_space;
/* Allocate whole TLS block */
tls_block = libc_malloc_aligned(tls_block_size, maxalign);
if (tls_block == NULL) {
tls_msg("__libc_allocate_tls: Out of memory.\n");
abort();
}
memset(tls_block, 0, tls_block_size);
tcb = (Elf_Addr **)(tls_block + pre_size + extra_size);
tls = (char *)tcb + TLS_TCB_SIZE + post_size;
if (oldtcb != NULL) {
memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize),
tls_block_size);
libc_free_aligned(oldtcb);
/* Adjust the DTV. */
dtv = tcb[0];
dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET);
} else {
dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr));
if (dtv == NULL) {
tls_msg("__libc_allocate_tls: Out of memory.\n");
abort();
}
/* Build the DTV. */
tcb[0] = dtv;
dtv[0] = 1; /* Generation. */
dtv[1] = 1; /* Segments count. */
dtv[2] = (Elf_Addr)(tls + TLS_DTV_OFFSET);
if (libc_tls_init_size > 0)
memcpy(tls, libc_tls_init, libc_tls_init_size);
}
return (tcb);
}
#endif
#ifdef TLS_VARIANT_II
/*
* Free Static TLS using the Variant II method.
*/
void
__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign)
{
size_t size;
Elf_Addr* dtv;
Elf_Addr tlsstart, tlsend;
/*
* Figure out the size of the initial TLS block so that we can
* find stuff which ___tls_get_addr() allocated dynamically.
*/
tcbalign = MAX(tcbalign, libc_tls_init_align);
size = roundup2(libc_tls_static_space, tcbalign);
dtv = ((Elf_Addr**)tcb)[1];
tlsend = (Elf_Addr) tcb;
tlsstart = tlsend - size;
libc_free_aligned((void*)tlsstart);
__je_bootstrap_free(dtv);
}
/*
* Allocate Static TLS using the Variant II method.
*/
void *
__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign)
{
size_t size;
char *tls;
Elf_Addr *dtv;
Elf_Addr segbase, oldsegbase;
tcbalign = MAX(tcbalign, libc_tls_init_align);
size = roundup2(libc_tls_static_space, tcbalign);
if (tcbsize < 2 * sizeof(Elf_Addr))
tcbsize = 2 * sizeof(Elf_Addr);
tls = libc_malloc_aligned(size + tcbsize, tcbalign);
if (tls == NULL) {
tls_msg("__libc_allocate_tls: Out of memory.\n");
abort();
}
memset(tls, 0, size + tcbsize);
dtv = __je_bootstrap_malloc(3 * sizeof(Elf_Addr));
if (dtv == NULL) {
tls_msg("__libc_allocate_tls: Out of memory.\n");
abort();
}
segbase = (Elf_Addr)(tls + size);
((Elf_Addr*)segbase)[0] = segbase;
((Elf_Addr*)segbase)[1] = (Elf_Addr) dtv;
dtv[0] = 1;
dtv[1] = 1;
dtv[2] = segbase - libc_tls_static_space;
if (oldtls) {
/*
* Copy the static TLS block over whole.
*/
oldsegbase = (Elf_Addr) oldtls;
memcpy((void *)(segbase - libc_tls_static_space),
(const void *)(oldsegbase - libc_tls_static_space),
libc_tls_static_space);
/*
* We assume that this block was the one we created with
* allocate_initial_tls().
*/
_rtld_free_tls(oldtls, 2*sizeof(Elf_Addr), sizeof(Elf_Addr));
} else {
memcpy((void *)(segbase - libc_tls_static_space),
libc_tls_init, libc_tls_init_size);
memset((void *)(segbase - libc_tls_static_space +
libc_tls_init_size), 0,
libc_tls_static_space - libc_tls_init_size);
}
return (void*) segbase;
}
#endif /* TLS_VARIANT_II */
#else
void *
__libc_allocate_tls(void *oldtls __unused, size_t tcbsize __unused,
size_t tcbalign __unused)
{
return (0);
}
void
__libc_free_tls(void *tcb __unused, size_t tcbsize __unused,
size_t tcbalign __unused)
{
}
#endif /* PIC */
void
_init_tls(void)
{
#ifndef PIC
Elf_Addr *sp;
Elf_Auxinfo *aux, *auxp;
Elf_Phdr *phdr;
size_t phent, phnum;
int i;
void *tls;
sp = (Elf_Addr *) environ;
while (*sp++ != 0)
;
aux = (Elf_Auxinfo *) sp;
phdr = NULL;
phent = phnum = 0;
for (auxp = aux; auxp->a_type != AT_NULL; auxp++) {
switch (auxp->a_type) {
case AT_PHDR:
phdr = auxp->a_un.a_ptr;
break;
case AT_PHENT:
phent = auxp->a_un.a_val;
break;
case AT_PHNUM:
phnum = auxp->a_un.a_val;
break;
}
}
if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0)
return;
for (i = 0; (unsigned) i < phnum; i++) {
if (phdr[i].p_type == PT_TLS) {
libc_tls_static_space = roundup2(phdr[i].p_memsz,
phdr[i].p_align);
libc_tls_init_size = phdr[i].p_filesz;
libc_tls_init_align = phdr[i].p_align;
libc_tls_init = (void *)phdr[i].p_vaddr;
break;
}
}
tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN);
_tcb_set(tls);
#endif
}
diff --git a/lib/libc/gen/trivial-getcontextx.c b/lib/libc/gen/trivial-getcontextx.c
index 512e8d17e1c4..b9d4522d96ee 100644
--- a/lib/libc/gen/trivial-getcontextx.c
+++ b/lib/libc/gen/trivial-getcontextx.c
@@ -1,74 +1,73 @@
/*
* Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/ucontext.h>
#include <errno.h>
#include <stdlib.h>
int
__getcontextx_size(void)
{
return (sizeof(ucontext_t));
}
int
__fillcontextx2(char *ctx)
{
return (0);
}
int
__fillcontextx(char *ctx)
{
ucontext_t *ucp;
ucp = (ucontext_t *)ctx;
return (getcontext(ucp));
}
__weak_reference(__getcontextx, getcontextx);
ucontext_t *
__getcontextx(void)
{
char *ctx;
int error;
ctx = malloc(__getcontextx_size());
if (ctx == NULL)
return (NULL);
if (__fillcontextx(ctx) == -1) {
error = errno;
free(ctx);
errno = error;
return (NULL);
}
return ((ucontext_t *)ctx);
}
diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c
index e831f6970295..4c4c73bffea3 100644
--- a/lib/libc/gen/utxdb.c
+++ b/lib/libc/gen/utxdb.c
@@ -1,175 +1,174 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/endian.h>
#include <sys/param.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include <utmpx.h>
#include "utxdb.h"
#include "un-namespace.h"
#define UTOF_STRING(ut, fu, field) do { \
strncpy((fu)->fu_ ## field, (ut)->ut_ ## field, \
MIN(sizeof (fu)->fu_ ## field, sizeof (ut)->ut_ ## field)); \
} while (0)
#define UTOF_ID(ut, fu) do { \
memcpy((fu)->fu_id, (ut)->ut_id, \
MIN(sizeof (fu)->fu_id, sizeof (ut)->ut_id)); \
} while (0)
#define UTOF_PID(ut, fu) do { \
(fu)->fu_pid = htobe32((ut)->ut_pid); \
} while (0)
#define UTOF_TYPE(ut, fu) do { \
(fu)->fu_type = (ut)->ut_type; \
} while (0)
#define UTOF_TV(fu) do { \
struct timeval tv; \
gettimeofday(&tv, NULL); \
(fu)->fu_tv = htobe64((uint64_t)tv.tv_sec * 1000000 + \
(uint64_t)tv.tv_usec); \
} while (0)
void
utx_to_futx(const struct utmpx *ut, struct futx *fu)
{
memset(fu, 0, sizeof *fu);
switch (ut->ut_type) {
case BOOT_TIME:
case OLD_TIME:
case NEW_TIME:
/* Extension: shutdown time. */
case SHUTDOWN_TIME:
break;
case USER_PROCESS:
UTOF_ID(ut, fu);
UTOF_STRING(ut, fu, user);
UTOF_STRING(ut, fu, line);
/* Extension: host name. */
UTOF_STRING(ut, fu, host);
UTOF_PID(ut, fu);
break;
case INIT_PROCESS:
UTOF_ID(ut, fu);
UTOF_PID(ut, fu);
break;
case LOGIN_PROCESS:
UTOF_ID(ut, fu);
UTOF_STRING(ut, fu, user);
UTOF_STRING(ut, fu, line);
UTOF_PID(ut, fu);
break;
case DEAD_PROCESS:
UTOF_ID(ut, fu);
UTOF_PID(ut, fu);
break;
default:
fu->fu_type = EMPTY;
return;
}
UTOF_TYPE(ut, fu);
UTOF_TV(fu);
}
#define FTOU_STRING(fu, ut, field) do { \
strncpy((ut)->ut_ ## field, (fu)->fu_ ## field, \
MIN(sizeof (ut)->ut_ ## field - 1, sizeof (fu)->fu_ ## field)); \
} while (0)
#define FTOU_ID(fu, ut) do { \
memcpy((ut)->ut_id, (fu)->fu_id, \
MIN(sizeof (ut)->ut_id, sizeof (fu)->fu_id)); \
} while (0)
#define FTOU_PID(fu, ut) do { \
(ut)->ut_pid = be32toh((fu)->fu_pid); \
} while (0)
#define FTOU_TYPE(fu, ut) do { \
(ut)->ut_type = (fu)->fu_type; \
} while (0)
#define FTOU_TV(fu, ut) do { \
uint64_t t; \
t = be64toh((fu)->fu_tv); \
(ut)->ut_tv.tv_sec = t / 1000000; \
(ut)->ut_tv.tv_usec = t % 1000000; \
} while (0)
struct utmpx *
futx_to_utx(const struct futx *fu)
{
static _Thread_local struct utmpx *ut;
if (ut == NULL) {
ut = calloc(1, sizeof *ut);
if (ut == NULL)
return (NULL);
} else
memset(ut, 0, sizeof *ut);
switch (fu->fu_type) {
case BOOT_TIME:
case OLD_TIME:
case NEW_TIME:
/* Extension: shutdown time. */
case SHUTDOWN_TIME:
break;
case USER_PROCESS:
FTOU_ID(fu, ut);
FTOU_STRING(fu, ut, user);
FTOU_STRING(fu, ut, line);
/* Extension: host name. */
FTOU_STRING(fu, ut, host);
FTOU_PID(fu, ut);
break;
case INIT_PROCESS:
FTOU_ID(fu, ut);
FTOU_PID(fu, ut);
break;
case LOGIN_PROCESS:
FTOU_ID(fu, ut);
FTOU_STRING(fu, ut, user);
FTOU_STRING(fu, ut, line);
FTOU_PID(fu, ut);
break;
case DEAD_PROCESS:
FTOU_ID(fu, ut);
FTOU_PID(fu, ut);
break;
default:
ut->ut_type = EMPTY;
return (ut);
}
FTOU_TYPE(fu, ut);
FTOU_TV(fu, ut);
return (ut);
}
diff --git a/lib/libc/gen/waitid.c b/lib/libc/gen/waitid.c
index 018f2a2c8f94..8690105ba147 100644
--- a/lib/libc/gen/waitid.c
+++ b/lib/libc/gen/waitid.c
@@ -1,70 +1,69 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Jukka A. Ukkonen
* All rights reserved.
*
* This software was developed by Jukka Ukkonen for FreeBSD.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <stddef.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include "un-namespace.h"
#include "libc_private.h"
int __waitid(idtype_t, id_t, siginfo_t *, int);
int
__waitid(idtype_t idtype, id_t id, siginfo_t *info, int flags)
{
int status;
pid_t ret;
ret = ((pid_t (*)(idtype_t, id_t, int *, int, struct __wrusage *,
siginfo_t *))__libc_interposing[INTERPOS_wait6])(idtype, id,
&status, flags, NULL, info);
/*
* According to SUSv4, waitid() shall not return a PID when a
* process is found, but only 0. If a process was actually
* found, siginfo_t fields si_signo and si_pid will be
* non-zero. In case WNOHANG was set in the flags and no
* process was found those fields are set to zero using
* memset() below.
*/
if (ret == 0 && info != NULL)
memset(info, 0, sizeof(*info));
else if (ret > 0)
ret = 0;
return (ret);
}
__weak_reference(__waitid, waitid);
__weak_reference(__waitid, _waitid);
diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c
index 0902814eb04f..f1437e30bbe2 100644
--- a/lib/libc/gen/wordexp.c
+++ b/lib/libc/gen/wordexp.c
@@ -1,409 +1,408 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "namespace.h"
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wordexp.h>
#include "un-namespace.h"
#include "libc_private.h"
static int we_askshell(const char *, wordexp_t *, int);
static int we_check(const char *);
/*
* wordexp --
* Perform shell word expansion on `words' and place the resulting list
* of words in `we'. See wordexp(3).
*
* Specified by IEEE Std. 1003.1-2001.
*/
int
wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags)
{
int error;
if (flags & WRDE_REUSE)
wordfree(we);
if ((flags & WRDE_APPEND) == 0) {
we->we_wordc = 0;
we->we_wordv = NULL;
we->we_strings = NULL;
we->we_nbytes = 0;
}
if ((error = we_check(words)) != 0) {
wordfree(we);
return (error);
}
if ((error = we_askshell(words, we, flags)) != 0) {
wordfree(we);
return (error);
}
return (0);
}
static size_t
we_read_fully(int fd, char *buffer, size_t len)
{
size_t done;
ssize_t nread;
done = 0;
do {
nread = _read(fd, buffer + done, len - done);
if (nread == -1 && errno == EINTR)
continue;
if (nread <= 0)
break;
done += nread;
} while (done != len);
return done;
}
static bool
we_write_fully(int fd, const char *buffer, size_t len)
{
size_t done;
ssize_t nwritten;
done = 0;
do {
nwritten = _write(fd, buffer + done, len - done);
if (nwritten == -1 && errno == EINTR)
continue;
if (nwritten <= 0)
return (false);
done += nwritten;
} while (done != len);
return (true);
}
/*
* we_askshell --
* Use the `freebsd_wordexp' /bin/sh builtin function to do most of the
* work in expanding the word string. This function is complicated by
* memory management.
*/
static int
we_askshell(const char *words, wordexp_t *we, int flags)
{
int pdesw[2]; /* Pipe for writing words */
int pdes[2]; /* Pipe for reading output */
char wfdstr[sizeof(int) * 3 + 1];
char buf[35]; /* Buffer for byte and word count */
long nwords, nbytes; /* Number of words, bytes from child */
long i; /* Handy integer */
size_t sofs; /* Offset into we->we_strings */
size_t vofs; /* Offset into we->we_wordv */
pid_t pid; /* Process ID of child */
pid_t wpid; /* waitpid return value */
int status; /* Child exit status */
int error; /* Our return value */
int serrno; /* errno to return */
char *np, *p; /* Handy pointers */
char *nstrings; /* Temporary for realloc() */
char **nwv; /* Temporary for realloc() */
sigset_t newsigblock, oldsigblock;
const char *ifs;
serrno = errno;
ifs = getenv("IFS");
if (pipe2(pdesw, O_CLOEXEC) < 0)
return (WRDE_NOSPACE); /* XXX */
snprintf(wfdstr, sizeof(wfdstr), "%d", pdesw[0]);
if (pipe2(pdes, O_CLOEXEC) < 0) {
_close(pdesw[0]);
_close(pdesw[1]);
return (WRDE_NOSPACE); /* XXX */
}
(void)sigemptyset(&newsigblock);
(void)sigaddset(&newsigblock, SIGCHLD);
(void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
if ((pid = fork()) < 0) {
serrno = errno;
_close(pdesw[0]);
_close(pdesw[1]);
_close(pdes[0]);
_close(pdes[1]);
(void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
errno = serrno;
return (WRDE_NOSPACE); /* XXX */
}
else if (pid == 0) {
/*
* We are the child; make /bin/sh expand `words'.
*/
(void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
if ((pdes[1] != STDOUT_FILENO ?
_dup2(pdes[1], STDOUT_FILENO) :
_fcntl(pdes[1], F_SETFD, 0)) < 0)
_exit(1);
if (_fcntl(pdesw[0], F_SETFD, 0) < 0)
_exit(1);
execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u",
"-c", "IFS=$1;eval \"$2\";"
"freebsd_wordexp -f \"$3\" ${4:+\"$4\"}",
"",
ifs != NULL ? ifs : " \t\n",
flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null",
wfdstr,
flags & WRDE_NOCMD ? "-p" : "",
(char *)NULL);
_exit(1);
}
/*
* We are the parent; write the words.
*/
_close(pdes[1]);
_close(pdesw[0]);
if (!we_write_fully(pdesw[1], words, strlen(words))) {
_close(pdesw[1]);
error = WRDE_SYNTAX;
goto cleanup;
}
_close(pdesw[1]);
/*
* Read the output of the shell wordexp function,
* which is a byte indicating that the words were parsed successfully,
* a 64-bit hexadecimal word count, a dummy byte, a 64-bit hexadecimal
* byte count (not including terminating null bytes), followed by the
* expanded words separated by nulls.
*/
switch (we_read_fully(pdes[0], buf, 34)) {
case 1:
error = buf[0] == 'C' ? WRDE_CMDSUB : WRDE_BADVAL;
serrno = errno;
goto cleanup;
case 34:
break;
default:
error = WRDE_SYNTAX;
serrno = errno;
goto cleanup;
}
buf[17] = '\0';
nwords = strtol(buf + 1, NULL, 16);
buf[34] = '\0';
nbytes = strtol(buf + 18, NULL, 16) + nwords;
/*
* Allocate or reallocate (when flags & WRDE_APPEND) the word vector
* and string storage buffers for the expanded words we're about to
* read from the child.
*/
sofs = we->we_nbytes;
vofs = we->we_wordc;
if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND))
vofs += we->we_offs;
we->we_wordc += nwords;
we->we_nbytes += nbytes;
if ((nwv = reallocarray(we->we_wordv, (we->we_wordc + 1 +
(flags & WRDE_DOOFFS ? we->we_offs : 0)),
sizeof(char *))) == NULL) {
error = WRDE_NOSPACE;
goto cleanup;
}
we->we_wordv = nwv;
if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) {
error = WRDE_NOSPACE;
goto cleanup;
}
for (i = 0; i < vofs; i++)
if (we->we_wordv[i] != NULL)
we->we_wordv[i] += nstrings - we->we_strings;
we->we_strings = nstrings;
if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) {
error = WRDE_NOSPACE; /* abort for unknown reason */
serrno = errno;
goto cleanup;
}
error = 0;
cleanup:
_close(pdes[0]);
do
wpid = _waitpid(pid, &status, 0);
while (wpid < 0 && errno == EINTR);
(void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
if (error != 0) {
errno = serrno;
return (error);
}
if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
return (WRDE_NOSPACE); /* abort for unknown reason */
/*
* Break the null-terminated expanded word strings out into
* the vector.
*/
if (vofs == 0 && flags & WRDE_DOOFFS)
while (vofs < we->we_offs)
we->we_wordv[vofs++] = NULL;
p = we->we_strings + sofs;
while (nwords-- != 0) {
we->we_wordv[vofs++] = p;
if ((np = memchr(p, '\0', nbytes)) == NULL)
return (WRDE_NOSPACE); /* XXX */
nbytes -= np - p + 1;
p = np + 1;
}
we->we_wordv[vofs] = NULL;
return (0);
}
/*
* we_check --
* Check that the string contains none of the following unquoted
* special characters: <newline> |&;<>(){}
* This mainly serves for {} which are normally legal in sh.
* It deliberately does not attempt to model full sh syntax.
*/
static int
we_check(const char *words)
{
char c;
/* Saw \ or $, possibly not special: */
bool quote = false, dollar = false;
/* Saw ', ", ${, ` or $(, possibly not special: */
bool have_sq = false, have_dq = false, have_par_begin = false;
bool have_cmd = false;
/* Definitely saw a ', ", ${, ` or $(, need a closing character: */
bool need_sq = false, need_dq = false, need_par_end = false;
bool need_cmd_old = false, need_cmd_new = false;
while ((c = *words++) != '\0') {
switch (c) {
case '\\':
quote = !quote;
continue;
case '$':
if (quote)
quote = false;
else
dollar = !dollar;
continue;
case '\'':
if (!quote && !have_sq && !have_dq)
need_sq = true;
else
need_sq = false;
have_sq = true;
break;
case '"':
if (!quote && !have_sq && !have_dq)
need_dq = true;
else
need_dq = false;
have_dq = true;
break;
case '`':
if (!quote && !have_sq && !have_cmd)
need_cmd_old = true;
else
need_cmd_old = false;
have_cmd = true;
break;
case '{':
if (!quote && !dollar && !have_sq && !have_dq &&
!have_cmd)
return (WRDE_BADCHAR);
if (dollar) {
if (!quote && !have_sq)
need_par_end = true;
have_par_begin = true;
}
break;
case '}':
if (!quote && !have_sq && !have_dq && !have_par_begin &&
!have_cmd)
return (WRDE_BADCHAR);
need_par_end = false;
break;
case '(':
if (!quote && !dollar && !have_sq && !have_dq &&
!have_cmd)
return (WRDE_BADCHAR);
if (dollar) {
if (!quote && !have_sq)
need_cmd_new = true;
have_cmd = true;
}
break;
case ')':
if (!quote && !have_sq && !have_dq && !have_cmd)
return (WRDE_BADCHAR);
need_cmd_new = false;
break;
case '|': case '&': case ';': case '<': case '>': case '\n':
if (!quote && !have_sq && !have_dq && !have_cmd)
return (WRDE_BADCHAR);
break;
default:
break;
}
quote = dollar = false;
}
if (quote || dollar || need_sq || need_dq || need_par_end ||
need_cmd_old || need_cmd_new)
return (WRDE_SYNTAX);
return (0);
}
/*
* wordfree --
* Free the result of wordexp(). See wordexp(3).
*
* Specified by IEEE Std. 1003.1-2001.
*/
void
wordfree(wordexp_t *we)
{
if (we == NULL)
return;
free(we->we_wordv);
free(we->we_strings);
we->we_wordv = NULL;
we->we_strings = NULL;
we->we_nbytes = 0;
we->we_wordc = 0;
}
diff --git a/lib/libc/gmon/gmon.c b/lib/libc/gmon/gmon.c
index b165ec394bbe..db1dcf50ed1d 100644
--- a/lib/libc/gmon/gmon.c
+++ b/lib/libc/gmon/gmon.c
@@ -1,246 +1,245 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gmon.c 8.1 (Berkeley) 6/4/93";
#endif
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/time.h>
#include <sys/gmon.h>
#include <sys/mman.h>
#include <sys/sysctl.h>
#include <err.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
struct gmonparam _gmonparam = { GMON_PROF_OFF };
static int s_scale;
/* See profil(2) where this is described (incorrectly). */
#define SCALE_SHIFT 16
#define ERR(s) _write(2, s, sizeof(s))
void moncontrol(int);
static int hertz(void);
void _mcleanup(void);
void
monstartup(u_long lowpc, u_long highpc)
{
int o;
char *cp;
struct gmonparam *p = &_gmonparam;
/*
* round lowpc and highpc to multiples of the density we're using
* so the rest of the scaling (here and in gprof) stays in ints.
*/
p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
p->textsize = p->highpc - p->lowpc;
p->kcountsize = p->textsize / HISTFRACTION;
p->hashfraction = HASHFRACTION;
p->fromssize = p->textsize / HASHFRACTION;
p->tolimit = p->textsize * ARCDENSITY / 100;
if (p->tolimit < MINARCS)
p->tolimit = MINARCS;
else if (p->tolimit > MAXARCS)
p->tolimit = MAXARCS;
p->tossize = p->tolimit * sizeof(struct tostruct);
cp = mmap(NULL, p->kcountsize + p->fromssize + p->tossize,
PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
if (cp == MAP_FAILED) {
ERR("monstartup: out of memory\n");
return;
}
#ifdef notdef
bzero(cp, p->kcountsize + p->fromssize + p->tossize);
#endif
p->tos = (struct tostruct *)cp;
cp += p->tossize;
p->kcount = (u_short *)cp;
cp += p->kcountsize;
p->froms = (u_short *)cp;
p->tos[0].link = 0;
o = p->highpc - p->lowpc;
s_scale = (p->kcountsize < o) ?
((uintmax_t)p->kcountsize << SCALE_SHIFT) / o : (1 << SCALE_SHIFT);
moncontrol(1);
}
void
_mcleanup(void)
{
int fd;
int fromindex;
int endfrom;
u_long frompc;
int toindex;
struct rawarc rawarc;
struct gmonparam *p = &_gmonparam;
struct gmonhdr gmonhdr, *hdr;
struct clockinfo clockinfo;
char outname[128];
int mib[2];
size_t size;
#ifdef DEBUG
int log, len;
char buf[200];
#endif
if (p->state == GMON_PROF_ERROR)
ERR("_mcleanup: tos overflow\n");
size = sizeof(clockinfo);
mib[0] = CTL_KERN;
mib[1] = KERN_CLOCKRATE;
if (sysctl(mib, 2, &clockinfo, &size, NULL, 0) < 0) {
/*
* Best guess
*/
clockinfo.profhz = hertz();
} else if (clockinfo.profhz == 0) {
if (clockinfo.hz != 0)
clockinfo.profhz = clockinfo.hz;
else
clockinfo.profhz = hertz();
}
moncontrol(0);
if (getenv("PROFIL_USE_PID"))
snprintf(outname, sizeof(outname), "%s.%d.gmon",
_getprogname(), getpid());
else
snprintf(outname, sizeof(outname), "%s.gmon", _getprogname());
fd = _open(outname, O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0666);
if (fd < 0) {
_warn("_mcleanup: %s", outname);
return;
}
#ifdef DEBUG
log = _open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY|O_CLOEXEC, 0664);
if (log < 0) {
_warn("_mcleanup: gmon.log");
return;
}
len = sprintf(buf, "[mcleanup1] kcount 0x%p ssiz %lu\n",
p->kcount, p->kcountsize);
_write(log, buf, len);
#endif
hdr = (struct gmonhdr *)&gmonhdr;
bzero(hdr, sizeof(*hdr));
hdr->lpc = p->lowpc;
hdr->hpc = p->highpc;
hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
hdr->version = GMONVERSION;
hdr->profrate = clockinfo.profhz;
_write(fd, (char *)hdr, sizeof *hdr);
_write(fd, p->kcount, p->kcountsize);
endfrom = p->fromssize / sizeof(*p->froms);
for (fromindex = 0; fromindex < endfrom; fromindex++) {
if (p->froms[fromindex] == 0)
continue;
frompc = p->lowpc;
frompc += fromindex * p->hashfraction * sizeof(*p->froms);
for (toindex = p->froms[fromindex]; toindex != 0;
toindex = p->tos[toindex].link) {
#ifdef DEBUG
len = sprintf(buf,
"[mcleanup2] frompc 0x%lx selfpc 0x%lx count %lu\n" ,
frompc, p->tos[toindex].selfpc,
p->tos[toindex].count);
_write(log, buf, len);
#endif
rawarc.raw_frompc = frompc;
rawarc.raw_selfpc = p->tos[toindex].selfpc;
rawarc.raw_count = p->tos[toindex].count;
_write(fd, &rawarc, sizeof rawarc);
}
}
_close(fd);
}
/*
* Control profiling
* profiling is what mcount checks to see if
* all the data structures are ready.
*/
void
moncontrol(int mode)
{
struct gmonparam *p = &_gmonparam;
if (mode) {
/* start */
profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale);
p->state = GMON_PROF_ON;
} else {
/* stop */
profil((char *)0, 0, 0, 0);
p->state = GMON_PROF_OFF;
}
}
/*
* discover the tick frequency of the machine
* if something goes wrong, we return 0, an impossible hertz.
*/
static int
hertz(void)
{
struct itimerval tim;
tim.it_interval.tv_sec = 0;
tim.it_interval.tv_usec = 1;
tim.it_value.tv_sec = 0;
tim.it_value.tv_usec = 0;
setitimer(ITIMER_REAL, &tim, 0);
setitimer(ITIMER_REAL, 0, &tim);
if (tim.it_interval.tv_usec < 2)
return(0);
return (1000000 / tim.it_interval.tv_usec);
}
diff --git a/lib/libc/gmon/mcount.c b/lib/libc/gmon/mcount.c
index df87973e27f9..81ebf7b7bb08 100644
--- a/lib/libc/gmon/mcount.c
+++ b/lib/libc/gmon/mcount.c
@@ -1,320 +1,319 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if !defined(_KERNEL) && defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mcount.c 8.1 (Berkeley) 6/4/93";
#endif
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/gmon.h>
#ifdef _KERNEL
#include <sys/systm.h>
#include <vm/vm.h>
#include <vm/vm_param.h>
#include <vm/pmap.h>
void bintr(void);
void btrap(void);
void eintr(void);
void user(void);
#endif
#include <machine/atomic.h>
/*
* mcount is called on entry to each function compiled with the profiling
* switch set. _mcount(), which is declared in a machine-dependent way
* with _MCOUNT_DECL, does the actual work and is either inlined into a
* C routine or called by an assembly stub. In any case, this magic is
* taken care of by the MCOUNT definition in <machine/profile.h>.
*
* _mcount updates data structures that represent traversals of the
* program's call graph edges. frompc and selfpc are the return
* address and function address that represents the given call graph edge.
*
* Note: the original BSD code used the same variable (frompcindex) for
* both frompcindex and frompc. Any reasonable, modern compiler will
* perform this optimization.
*/
/* _mcount; may be static, inline, etc */
_MCOUNT_DECL(uintfptr_t frompc, uintfptr_t selfpc)
{
#ifdef GUPROF
u_int delta;
#endif
fptrdiff_t frompci;
u_short *frompcindex;
struct tostruct *top, *prevtop;
struct gmonparam *p;
long toindex;
#ifdef _KERNEL
MCOUNT_DECL(s)
#endif
p = &_gmonparam;
#ifndef GUPROF /* XXX */
/*
* check that we are profiling
* and that we aren't recursively invoked.
*/
if (p->state != GMON_PROF_ON)
return;
#endif
#ifdef _KERNEL
MCOUNT_ENTER(s);
#else
if (!atomic_cmpset_acq_int(&p->state, GMON_PROF_ON, GMON_PROF_BUSY))
return;
#endif
frompci = frompc - p->lowpc;
#ifdef _KERNEL
/*
* When we are called from an exception handler, frompci may be
* for a user address. Convert such frompci's to the index of
* user() to merge all user counts.
*/
if (frompci >= p->textsize) {
if (frompci + p->lowpc
>= (uintfptr_t)(VM_MAXUSER_ADDRESS + UPAGES * PAGE_SIZE))
goto done;
frompci = (uintfptr_t)user - p->lowpc;
if (frompci >= p->textsize)
goto done;
}
#endif
#ifdef GUPROF
if (p->state != GMON_PROF_HIRES)
goto skip_guprof_stuff;
/*
* Look at the clock and add the count of clock cycles since the
* clock was last looked at to a counter for frompc. This
* solidifies the count for the function containing frompc and
* effectively starts another clock for the current function.
* The count for the new clock will be solidified when another
* function call is made or the function returns.
*
* We use the usual sampling counters since they can be located
* efficiently. 4-byte counters are usually necessary.
*
* There are many complications for subtracting the profiling
* overheads from the counts for normal functions and adding
* them to the counts for mcount(), mexitcount() and cputime().
* We attempt to handle fractional cycles, but the overheads
* are usually underestimated because they are calibrated for
* a simpler than usual setup.
*/
delta = cputime() - p->mcount_overhead;
p->cputime_overhead_resid += p->cputime_overhead_frac;
p->mcount_overhead_resid += p->mcount_overhead_frac;
if ((int)delta < 0)
*p->mcount_count += delta + p->mcount_overhead
- p->cputime_overhead;
else if (delta != 0) {
if (p->cputime_overhead_resid >= CALIB_SCALE) {
p->cputime_overhead_resid -= CALIB_SCALE;
++*p->cputime_count;
--delta;
}
if (delta != 0) {
if (p->mcount_overhead_resid >= CALIB_SCALE) {
p->mcount_overhead_resid -= CALIB_SCALE;
++*p->mcount_count;
--delta;
}
KCOUNT(p, frompci) += delta;
}
*p->mcount_count += p->mcount_overhead_sub;
}
*p->cputime_count += p->cputime_overhead;
skip_guprof_stuff:
#endif /* GUPROF */
#ifdef _KERNEL
/*
* When we are called from an exception handler, frompc is faked
* to be for where the exception occurred. We've just solidified
* the count for there. Now convert frompci to the index of btrap()
* for trap handlers and bintr() for interrupt handlers to make
* exceptions appear in the call graph as calls from btrap() and
* bintr() instead of calls from all over.
*/
if ((uintfptr_t)selfpc >= (uintfptr_t)btrap
&& (uintfptr_t)selfpc < (uintfptr_t)eintr) {
if ((uintfptr_t)selfpc >= (uintfptr_t)bintr)
frompci = (uintfptr_t)bintr - p->lowpc;
else
frompci = (uintfptr_t)btrap - p->lowpc;
}
#endif
/*
* check that frompc is a reasonable pc value.
* for example: signal catchers get called from the stack,
* not from text space. too bad.
*/
if (frompci >= p->textsize)
goto done;
frompcindex = &p->froms[frompci / (p->hashfraction * sizeof(*p->froms))];
toindex = *frompcindex;
if (toindex == 0) {
/*
* first time traversing this arc
*/
toindex = ++p->tos[0].link;
if (toindex >= p->tolimit)
/* halt further profiling */
goto overflow;
*frompcindex = toindex;
top = &p->tos[toindex];
top->selfpc = selfpc;
top->count = 1;
top->link = 0;
goto done;
}
top = &p->tos[toindex];
if (top->selfpc == selfpc) {
/*
* arc at front of chain; usual case.
*/
top->count++;
goto done;
}
/*
* have to go looking down chain for it.
* top points to what we are looking at,
* prevtop points to previous top.
* we know it is not at the head of the chain.
*/
for (; /* goto done */; ) {
if (top->link == 0) {
/*
* top is end of the chain and none of the chain
* had top->selfpc == selfpc.
* so we allocate a new tostruct
* and link it to the head of the chain.
*/
toindex = ++p->tos[0].link;
if (toindex >= p->tolimit)
goto overflow;
top = &p->tos[toindex];
top->selfpc = selfpc;
top->count = 1;
top->link = *frompcindex;
*frompcindex = toindex;
goto done;
}
/*
* otherwise, check the next arc on the chain.
*/
prevtop = top;
top = &p->tos[top->link];
if (top->selfpc == selfpc) {
/*
* there it is.
* increment its count
* move it to the head of the chain.
*/
top->count++;
toindex = prevtop->link;
prevtop->link = top->link;
top->link = *frompcindex;
*frompcindex = toindex;
goto done;
}
}
done:
#ifdef _KERNEL
MCOUNT_EXIT(s);
#else
atomic_store_rel_int(&p->state, GMON_PROF_ON);
#endif
return;
overflow:
atomic_store_rel_int(&p->state, GMON_PROF_ERROR);
#ifdef _KERNEL
MCOUNT_EXIT(s);
#endif
return;
}
/*
* Actual definition of mcount function. Defined in <machine/profile.h>,
* which is included by <sys/gmon.h>.
*/
MCOUNT
#ifdef GUPROF
void
mexitcount(uintfptr_t selfpc)
{
struct gmonparam *p;
uintfptr_t selfpcdiff;
p = &_gmonparam;
selfpcdiff = selfpc - (uintfptr_t)p->lowpc;
if (selfpcdiff < p->textsize) {
u_int delta;
/*
* Solidify the count for the current function.
*/
delta = cputime() - p->mexitcount_overhead;
p->cputime_overhead_resid += p->cputime_overhead_frac;
p->mexitcount_overhead_resid += p->mexitcount_overhead_frac;
if ((int)delta < 0)
*p->mexitcount_count += delta + p->mexitcount_overhead
- p->cputime_overhead;
else if (delta != 0) {
if (p->cputime_overhead_resid >= CALIB_SCALE) {
p->cputime_overhead_resid -= CALIB_SCALE;
++*p->cputime_count;
--delta;
}
if (delta != 0) {
if (p->mexitcount_overhead_resid
>= CALIB_SCALE) {
p->mexitcount_overhead_resid
-= CALIB_SCALE;
++*p->mexitcount_count;
--delta;
}
KCOUNT(p, selfpcdiff) += delta;
}
*p->mexitcount_count += p->mexitcount_overhead_sub;
}
*p->cputime_count += p->cputime_overhead;
}
}
#endif /* GUPROF */
diff --git a/lib/libc/i386/gen/flt_rounds.c b/lib/libc/i386/gen/flt_rounds.c
index 6212dbf20918..cebd8e1eb098 100644
--- a/lib/libc/i386/gen/flt_rounds.c
+++ b/lib/libc/i386/gen/flt_rounds.c
@@ -1,23 +1,22 @@
/*
* Written by J.T. Conklin, Apr 10, 1995
* Public domain.
*/
-#include <sys/cdefs.h>
#include <float.h>
static const int map[] = {
1, /* round to nearest */
3, /* round to zero */
2, /* round to negative infinity */
0 /* round to positive infinity */
};
int
__flt_rounds(void)
{
int x;
__asm("fnstcw %0" : "=m" (x));
return (map[(x >> 10) & 0x03]);
}
diff --git a/lib/libc/i386/gen/infinity.c b/lib/libc/i386/gen/infinity.c
index b9db2fc84efa..bc05708abd2b 100644
--- a/lib/libc/i386/gen/infinity.c
+++ b/lib/libc/i386/gen/infinity.c
@@ -1,12 +1,11 @@
/*
* infinity.c
*/
-#include <sys/cdefs.h>
#include <math.h>
/* bytes for +Infinity on a 387 */
const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
/* bytes for NaN */
const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/i386/gen/makecontext.c b/lib/libc/i386/gen/makecontext.c
index b710a7136788..7b4845ac6bee 100644
--- a/lib/libc/i386/gen/makecontext.c
+++ b/lib/libc/i386/gen/makecontext.c
@@ -1,163 +1,162 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Daniel M. Eischen <deischen@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
/* Prototypes */
extern void _ctx_start(ucontext_t *, int argc, ...);
__weak_reference(__makecontext, makecontext);
void
_ctx_done (ucontext_t *ucp)
{
if (ucp->uc_link == NULL)
exit(0);
else {
/*
* Since this context has finished, don't allow it
* to be restarted without being reinitialized (via
* setcontext or swapcontext).
*/
ucp->uc_mcontext.mc_len = 0;
/* Set context to next one in link */
/* XXX - what to do for error, abort? */
setcontext((const ucontext_t *)ucp->uc_link);
abort(); /* should never get here */
}
}
void
__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
{
va_list ap;
char *stack_top;
intptr_t *argp;
int i;
if (ucp == NULL)
return;
else if ((ucp->uc_stack.ss_sp == NULL) ||
(ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
/*
* This should really return -1 with errno set to ENOMEM
* or something, but the spec says that makecontext is
* a void function. At least make sure that the context
* isn't valid so it can't be used without an error.
*/
ucp->uc_mcontext.mc_len = 0;
}
/* XXX - Do we want to sanity check argc? */
else if (argc < 0) {
ucp->uc_mcontext.mc_len = 0;
}
/* Make sure the context is valid. */
else if (ucp->uc_mcontext.mc_len == sizeof(mcontext_t)) {
/*
* Arrange the stack as follows:
*
* _ctx_start() - context start wrapper
* start() - user start routine
* arg1 - first argument, aligned(16)
* ...
* argn
* ucp - this context, %ebp points here
*
* When the context is started, control will return to
* the context start wrapper which will pop the user
* start routine from the top of the stack. After that,
* the top of the stack will be setup with all arguments
* necessary for calling the start routine. When the
* start routine returns, the context wrapper then sets
* the stack pointer to %ebp which was setup to point to
* the base of the stack (and where ucp is stored). It
* will then call _ctx_done() to swap in the next context
* (uc_link != 0) or exit the program (uc_link == 0).
*/
stack_top = (char *)(ucp->uc_stack.ss_sp +
ucp->uc_stack.ss_size - sizeof(intptr_t));
/*
* Adjust top of stack to allow for 3 pointers (return
* address, _ctx_start, and ucp) and argc arguments.
* We allow the arguments to be pointers also. The first
* argument to the user function must be properly aligned.
*/
stack_top = stack_top - (sizeof(intptr_t) * (1 + argc));
stack_top = (char *)((unsigned)stack_top & ~15);
stack_top = stack_top - (2 * sizeof(intptr_t));
argp = (intptr_t *)stack_top;
/*
* Setup the top of the stack with the user start routine
* followed by all of its aguments and the pointer to the
* ucontext. We need to leave a spare spot at the top of
* the stack because setcontext will move eip to the top
* of the stack before returning.
*/
*argp = (intptr_t)_ctx_start; /* overwritten with same value */
argp++;
*argp = (intptr_t)start;
argp++;
/* Add all the arguments: */
va_start(ap, argc);
for (i = 0; i < argc; i++) {
*argp = va_arg(ap, intptr_t);
argp++;
}
va_end(ap);
/* The ucontext is placed at the bottom of the stack. */
*argp = (intptr_t)ucp;
/*
* Set the machine context to point to the top of the
* stack and the program counter to the context start
* wrapper. Note that setcontext() pushes the return
* address onto the top of the stack, so allow for this
* by adjusting the stack downward 1 slot. Also set
* %esi to point to the base of the stack where ucp
* is stored.
*/
ucp->uc_mcontext.mc_esi = (int)argp;
ucp->uc_mcontext.mc_ebp = 0;
ucp->uc_mcontext.mc_esp = (int)stack_top + sizeof(caddr_t);
ucp->uc_mcontext.mc_eip = (int)_ctx_start;
}
}
diff --git a/lib/libc/i386/gen/signalcontext.c b/lib/libc/i386/gen/signalcontext.c
index 1e77ffe1a1a2..38b306501c3c 100644
--- a/lib/libc/i386/gen/signalcontext.c
+++ b/lib/libc/i386/gen/signalcontext.c
@@ -1,79 +1,78 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Jonathan Mini <mini@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ucontext.h>
#include <machine/psl.h>
#include <machine/sigframe.h>
#include <signal.h>
#include <strings.h>
__weak_reference(__signalcontext, signalcontext);
extern void _ctx_start(ucontext_t *, int argc, ...);
int
__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
{
register_t *p;
struct sigframe *sfp;
/*-
* Set up stack.
* (n = sizeof(int))
* 2n+sizeof(struct sigframe) ucp
* 2n struct sigframe
* 1n &func
* 0n &_ctx_start
*/
p = (register_t *)(void *)(intptr_t)ucp->uc_mcontext.mc_esp;
*--p = (register_t)(intptr_t)ucp;
p = (register_t *)((u_register_t)p & ~0xF); /* Align to 16 bytes. */
p = (register_t *)((u_register_t)p - sizeof(struct sigframe));
sfp = (struct sigframe *)p;
bzero(sfp, sizeof(struct sigframe));
sfp->sf_signum = sig;
sfp->sf_siginfo = (register_t)(intptr_t)&sfp->sf_si;
sfp->sf_ucontext = (register_t)(intptr_t)&sfp->sf_uc;
sfp->sf_ahu.sf_action = (__siginfohandler_t *)func;
bcopy(ucp, &sfp->sf_uc, sizeof(ucontext_t));
sfp->sf_si.si_signo = sig;
*--p = (register_t)(intptr_t)func;
/*
* Set up ucontext_t.
*/
ucp->uc_mcontext.mc_esi = ucp->uc_mcontext.mc_esp - sizeof(int);
ucp->uc_mcontext.mc_esp = (register_t)(intptr_t)p;
ucp->uc_mcontext.mc_eip = (register_t)(intptr_t)_ctx_start;
ucp->uc_mcontext.mc_eflags &= ~PSL_T;
ucp->uc_link = &sfp->sf_uc;
sigdelset(&ucp->uc_sigmask, sig);
return (0);
}
diff --git a/lib/libc/i386/sys/i386_clr_watch.c b/lib/libc/i386/sys/i386_clr_watch.c
index 07b85795fba4..f01b340d81e0 100644
--- a/lib/libc/i386/sys/i386_clr_watch.c
+++ b/lib/libc/i386/sys/i386_clr_watch.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2000 Brian S. Dean <bsd@bsdhome.com>
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/reg.h>
#include <machine/sysarch.h>
int
i386_clr_watch(int watchnum, struct dbreg * d)
{
if (watchnum < 0 || watchnum >= 4)
return -1;
DBREG_DRX(d,7) = DBREG_DRX(d,7) & ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
DBREG_DRX(d,watchnum) = 0;
return 0;
}
diff --git a/lib/libc/i386/sys/i386_get_fsbase.c b/lib/libc/i386/sys/i386_get_fsbase.c
index f12a2383cc3e..b60c6af5ff55 100644
--- a/lib/libc/i386/sys/i386_get_fsbase.c
+++ b/lib/libc/i386/sys/i386_get_fsbase.c
@@ -1,37 +1,36 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Peter Wemm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
int
i386_get_fsbase(void **addr)
{
return (sysarch(I386_GET_FSBASE, addr));
}
diff --git a/lib/libc/i386/sys/i386_get_gsbase.c b/lib/libc/i386/sys/i386_get_gsbase.c
index efe43d383b4f..fd8187d83437 100644
--- a/lib/libc/i386/sys/i386_get_gsbase.c
+++ b/lib/libc/i386/sys/i386_get_gsbase.c
@@ -1,37 +1,36 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Peter Wemm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
int
i386_get_gsbase(void **addr)
{
return (sysarch(I386_GET_GSBASE, addr));
}
diff --git a/lib/libc/i386/sys/i386_get_ioperm.c b/lib/libc/i386/sys/i386_get_ioperm.c
index 9d8e8d31862b..6adfe2bedf6c 100644
--- a/lib/libc/i386/sys/i386_get_ioperm.c
+++ b/lib/libc/i386/sys/i386_get_ioperm.c
@@ -1,48 +1,47 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998 Jonathan Lemon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
int
i386_get_ioperm(unsigned int start, unsigned int *length, int *enable)
{
struct i386_ioperm_args p;
int error;
p.start = start;
p.length = *length;
p.enable = *enable;
error = sysarch(I386_GET_IOPERM, &p);
*length = p.length;
*enable = p.enable;
return (error);
}
diff --git a/lib/libc/i386/sys/i386_get_ldt.c b/lib/libc/i386/sys/i386_get_ldt.c
index 52daefd85de5..8021476434d6 100644
--- a/lib/libc/i386/sys/i386_get_ldt.c
+++ b/lib/libc/i386/sys/i386_get_ldt.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1993 John Brezak
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/cdefs.h>
#include <machine/segments.h>
#include <machine/sysarch.h>
int
i386_get_ldt(int start, union descriptor *descs, int num)
{
struct i386_ldt_args p;
p.start = start;
p.descs = descs;
p.num = num;
return sysarch(I386_GET_LDT, &p);
}
diff --git a/lib/libc/i386/sys/i386_set_fsbase.c b/lib/libc/i386/sys/i386_set_fsbase.c
index 81a4ed761a7e..8420f492a5d5 100644
--- a/lib/libc/i386/sys/i386_set_fsbase.c
+++ b/lib/libc/i386/sys/i386_set_fsbase.c
@@ -1,37 +1,36 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Peter Wemm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
int
i386_set_fsbase(void *addr)
{
return (sysarch(I386_SET_FSBASE, &addr));
}
diff --git a/lib/libc/i386/sys/i386_set_gsbase.c b/lib/libc/i386/sys/i386_set_gsbase.c
index 8a584435e4c7..779b2e74eb3f 100644
--- a/lib/libc/i386/sys/i386_set_gsbase.c
+++ b/lib/libc/i386/sys/i386_set_gsbase.c
@@ -1,37 +1,36 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Peter Wemm
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
int
i386_set_gsbase(void *addr)
{
return (sysarch(I386_SET_GSBASE, &addr));
}
diff --git a/lib/libc/i386/sys/i386_set_ioperm.c b/lib/libc/i386/sys/i386_set_ioperm.c
index dead1cae262a..b65f62fe44bb 100644
--- a/lib/libc/i386/sys/i386_set_ioperm.c
+++ b/lib/libc/i386/sys/i386_set_ioperm.c
@@ -1,42 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998 Jonathan Lemon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
int
i386_set_ioperm(unsigned int start, unsigned int length, int enable)
{
struct i386_ioperm_args p;
p.start = start;
p.length = length;
p.enable = enable;
return (sysarch(I386_SET_IOPERM, &p));
}
diff --git a/lib/libc/i386/sys/i386_set_ldt.c b/lib/libc/i386/sys/i386_set_ldt.c
index 578b7f4d2f06..ac363e45d769 100644
--- a/lib/libc/i386/sys/i386_set_ldt.c
+++ b/lib/libc/i386/sys/i386_set_ldt.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1993 John Brezak
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/cdefs.h>
#include <machine/segments.h>
#include <machine/sysarch.h>
int
i386_set_ldt(int start, union descriptor *descs, int num)
{
struct i386_ldt_args p;
p.start = start;
p.descs = descs;
p.num = num;
return sysarch(I386_SET_LDT, &p);
}
diff --git a/lib/libc/i386/sys/i386_set_watch.c b/lib/libc/i386/sys/i386_set_watch.c
index 7b341e099c6b..acdcd79720e3 100644
--- a/lib/libc/i386/sys/i386_set_watch.c
+++ b/lib/libc/i386/sys/i386_set_watch.c
@@ -1,84 +1,83 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2000 Brian S. Dean <bsd@bsdhome.com>
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY BRIAN S. DEAN ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BRIAN S. DEAN BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/reg.h>
#include <machine/sysarch.h>
int
i386_set_watch(int watchnum, unsigned int watchaddr, int size,
int access, struct dbreg * d)
{
int i;
unsigned int mask;
if (watchnum == -1) {
for (i = 0, mask = 0x3; i < 4; i++, mask <<= 2)
if ((DBREG_DRX(d,7) & mask) == 0)
break;
if (i < 4)
watchnum = i;
else
return -1;
}
switch (access) {
case DBREG_DR7_EXEC:
size = 1; /* size must be 1 for an execution breakpoint */
/* fall through */
case DBREG_DR7_WRONLY:
case DBREG_DR7_RDWR:
break;
default : return -1; break;
}
/*
* we can watch a 1, 2, or 4 byte sized location
*/
switch (size) {
case 1 : mask = 0x00; break;
case 2 : mask = 0x01 << 2; break;
case 4 : mask = 0x03 << 2; break;
default : return -1; break;
}
mask |= access;
/* clear the bits we are about to affect */
DBREG_DRX(d,7) &= ~((0x3 << (watchnum*2)) | (0x0f << (watchnum*4+16)));
/* set drN register to the address, N=watchnum */
DBREG_DRX(d,watchnum) = watchaddr;
/* enable the watchpoint */
DBREG_DRX(d,7) |= (0x2 << (watchnum*2)) | (mask << (watchnum*4+16));
return watchnum;
}
diff --git a/lib/libc/i386/sys/i386_vm86.c b/lib/libc/i386/sys/i386_vm86.c
index e5d942d37131..fab2a3080ccd 100644
--- a/lib/libc/i386/sys/i386_vm86.c
+++ b/lib/libc/i386/sys/i386_vm86.c
@@ -1,41 +1,40 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998 Jonathan Lemon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/sysarch.h>
int
i386_vm86(int fcn, void *data)
{
struct i386_vm86_args p;
p.sub_op = fcn;
p.sub_args = (char *)data;
return (sysarch(I386_VM86, &p));
}
diff --git a/lib/libc/iconv/bsd_iconv.c b/lib/libc/iconv/bsd_iconv.c
index fe2491d665dd..d3da6fd1a271 100644
--- a/lib/libc/iconv/bsd_iconv.c
+++ b/lib/libc/iconv/bsd_iconv.c
@@ -1,310 +1,309 @@
/* $NetBSD: iconv.c,v 1.11 2009/03/03 16:22:33 explorer Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Citrus Project,
* Copyright (c) 2009, 2010 Gabor Kovesdan <gabor@FreeBSD.org>,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/queue.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <iconv.h>
#include <limits.h>
#include <paths.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_types.h"
#include "citrus_module.h"
#include "citrus_esdb.h"
#include "citrus_hash.h"
#include "citrus_iconv.h"
#include "iconv-internal.h"
#define ISBADF(_h_) (!(_h_) || (_h_) == (iconv_t)-1)
static iconv_t
__bsd___iconv_open(const char *out, const char *in, struct _citrus_iconv *handle)
{
int ret;
/*
* Remove anything following a //, as these are options (like
* //ignore, //translate, etc) and we just don't handle them.
* This is for compatibility with software that uses these
* blindly.
*/
ret = _citrus_iconv_open(&handle, in, out);
if (ret) {
errno = ret == ENOENT ? EINVAL : ret;
return ((iconv_t)-1);
}
handle->cv_shared->ci_discard_ilseq = strcasestr(out, "//IGNORE");
return ((iconv_t)(void *)handle);
}
iconv_t
__bsd_iconv_open(const char *out, const char *in)
{
return (__bsd___iconv_open(out, in, NULL));
}
int
__bsd_iconv_open_into(const char *out, const char *in, iconv_allocation_t *ptr)
{
struct _citrus_iconv *handle;
handle = (struct _citrus_iconv *)ptr;
return ((__bsd___iconv_open(out, in, handle) == (iconv_t)-1) ? -1 : 0);
}
int
__bsd_iconv_close(iconv_t handle)
{
if (ISBADF(handle)) {
errno = EBADF;
return (-1);
}
_citrus_iconv_close((struct _citrus_iconv *)(void *)handle);
return (0);
}
size_t
__bsd_iconv(iconv_t handle, char **in, size_t *szin, char **out, size_t *szout)
{
size_t ret;
int err;
if (ISBADF(handle)) {
errno = EBADF;
return ((size_t)-1);
}
err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
in, szin, out, szout, 0, &ret);
if (err) {
errno = err;
ret = (size_t)-1;
}
return (ret);
}
size_t
__bsd___iconv(iconv_t handle, char **in, size_t *szin, char **out,
size_t *szout, uint32_t flags, size_t *invalids)
{
size_t ret;
int err;
if (ISBADF(handle)) {
errno = EBADF;
return ((size_t)-1);
}
err = _citrus_iconv_convert((struct _citrus_iconv *)(void *)handle,
in, szin, out, szout, flags, &ret);
if (invalids)
*invalids = ret;
if (err) {
errno = err;
ret = (size_t)-1;
}
return (ret);
}
int
__bsd___iconv_get_list(char ***rlist, size_t *rsz, bool sorted)
{
int ret;
ret = _citrus_esdb_get_list(rlist, rsz, sorted);
if (ret) {
errno = ret;
return (-1);
}
return (0);
}
void
__bsd___iconv_free_list(char **list, size_t sz)
{
_citrus_esdb_free_list(list, sz);
}
/*
* GNU-compatibile non-standard interfaces.
*/
static int
qsort_helper(const void *first, const void *second)
{
const char * const *s1;
const char * const *s2;
s1 = first;
s2 = second;
return (strcmp(*s1, *s2));
}
void
__bsd_iconvlist(int (*do_one) (unsigned int, const char * const *,
void *), void *data)
{
char **list, **names;
const char * const *np;
char *curitem, *curkey, *slashpos;
size_t sz;
unsigned int i, j, n;
i = 0;
names = NULL;
if (__bsd___iconv_get_list(&list, &sz, true)) {
list = NULL;
goto out;
}
qsort((void *)list, sz, sizeof(char *), qsort_helper);
while (i < sz) {
j = 0;
slashpos = strchr(list[i], '/');
names = malloc(sz * sizeof(char *));
if (names == NULL)
goto out;
curkey = strndup(list[i], slashpos - list[i]);
if (curkey == NULL)
goto out;
names[j++] = curkey;
for (; (i < sz) && (memcmp(curkey, list[i], strlen(curkey)) == 0); i++) {
slashpos = strchr(list[i], '/');
if (strcmp(curkey, &slashpos[1]) == 0)
continue;
curitem = strdup(&slashpos[1]);
if (curitem == NULL)
goto out;
names[j++] = curitem;
}
np = (const char * const *)names;
do_one(j, np, data);
for (n = 0; n < j; n++)
free(names[n]);
free(names);
names = NULL;
}
out:
if (names != NULL) {
for (n = 0; n < j; n++)
free(names[n]);
free(names);
}
if (list != NULL)
__bsd___iconv_free_list(list, sz);
}
__inline const char *
__bsd_iconv_canonicalize(const char *name)
{
return (_citrus_iconv_canonicalize(name));
}
int
__bsd_iconvctl(iconv_t cd, int request, void *argument)
{
struct _citrus_iconv *cv;
struct iconv_hooks *hooks;
const char *convname;
char *dst;
int *i;
size_t srclen;
cv = (struct _citrus_iconv *)(void *)cd;
hooks = (struct iconv_hooks *)argument;
i = (int *)argument;
if (ISBADF(cd)) {
errno = EBADF;
return (-1);
}
switch (request) {
case ICONV_TRIVIALP:
convname = cv->cv_shared->ci_convname;
dst = strchr(convname, '/');
srclen = dst - convname;
dst++;
*i = (srclen == strlen(dst)) && !memcmp(convname, dst, srclen);
return (0);
case ICONV_GET_TRANSLITERATE:
*i = 1;
return (0);
case ICONV_SET_TRANSLITERATE:
return ((*i == 1) ? 0 : -1);
case ICONV_GET_DISCARD_ILSEQ:
*i = cv->cv_shared->ci_discard_ilseq ? 1 : 0;
return (0);
case ICONV_SET_DISCARD_ILSEQ:
cv->cv_shared->ci_discard_ilseq = *i;
return (0);
case ICONV_SET_HOOKS:
cv->cv_shared->ci_hooks = hooks;
return (0);
case ICONV_SET_FALLBACKS:
errno = EOPNOTSUPP;
return (-1);
case ICONV_GET_ILSEQ_INVALID:
*i = cv->cv_shared->ci_ilseq_invalid ? 1 : 0;
return (0);
case ICONV_SET_ILSEQ_INVALID:
cv->cv_shared->ci_ilseq_invalid = *i;
return (0);
default:
errno = EINVAL;
return (-1);
}
}
void
__bsd_iconv_set_relocation_prefix(const char *orig_prefix __unused,
const char *curr_prefix __unused)
{
}
diff --git a/lib/libc/iconv/citrus_bcs.c b/lib/libc/iconv/citrus_bcs.c
index 9e7cb8c0749f..8409e1fbac7b 100644
--- a/lib/libc/iconv/citrus_bcs.c
+++ b/lib/libc/iconv/citrus_bcs.c
@@ -1,169 +1,168 @@
/* $NetBSD: citrus_bcs.c,v 1.5 2005/05/14 17:55:42 tshiozak Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdlib.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
/*
* case insensitive comparison between two C strings.
*/
int
_citrus_bcs_strcasecmp(const char * __restrict str1,
const char * __restrict str2)
{
int c1, c2;
c1 = c2 = 1;
while (c1 && c2 && c1 == c2) {
c1 = _bcs_toupper(*str1++);
c2 = _bcs_toupper(*str2++);
}
return ((c1 == c2) ? 0 : ((c1 > c2) ? 1 : -1));
}
/*
* case insensitive comparison between two C strings with limitation of length.
*/
int
_citrus_bcs_strncasecmp(const char * __restrict str1,
const char * __restrict str2, size_t sz)
{
int c1, c2;
c1 = c2 = 1;
while (c1 && c2 && c1 == c2 && sz != 0) {
c1 = _bcs_toupper(*str1++);
c2 = _bcs_toupper(*str2++);
sz--;
}
return ((c1 == c2) ? 0 : ((c1 > c2) ? 1 : -1));
}
/*
* skip white space characters.
*/
const char *
_citrus_bcs_skip_ws(const char *p)
{
while (*p && _bcs_isspace(*p))
p++;
return (p);
}
/*
* skip non white space characters.
*/
const char *
_citrus_bcs_skip_nonws(const char *p)
{
while (*p && !_bcs_isspace(*p))
p++;
return (p);
}
/*
* skip white space characters with limitation of length.
*/
const char *
_citrus_bcs_skip_ws_len(const char * __restrict p, size_t * __restrict len)
{
while (*len > 0 && *p && _bcs_isspace(*p)) {
p++;
(*len)--;
}
return (p);
}
/*
* skip non white space characters with limitation of length.
*/
const char *
_citrus_bcs_skip_nonws_len(const char * __restrict p, size_t * __restrict len)
{
while (*len > 0 && *p && !_bcs_isspace(*p)) {
p++;
(*len)--;
}
return (p);
}
/*
* truncate trailing white space characters.
*/
void
_citrus_bcs_trunc_rws_len(const char * __restrict p, size_t * __restrict len)
{
while (*len > 0 && _bcs_isspace(p[*len - 1]))
(*len)--;
}
/*
* destructive transliterate to lowercase.
*/
void
_citrus_bcs_convert_to_lower(char *s)
{
while (*s) {
*s = _bcs_tolower(*s);
s++;
}
}
/*
* destructive transliterate to uppercase.
*/
void
_citrus_bcs_convert_to_upper(char *s)
{
while (*s) {
*s = _bcs_toupper(*s);
s++;
}
}
diff --git a/lib/libc/iconv/citrus_bcs_strtol.c b/lib/libc/iconv/citrus_bcs_strtol.c
index c1273acba344..55d4d1ca565d 100644
--- a/lib/libc/iconv/citrus_bcs_strtol.c
+++ b/lib/libc/iconv/citrus_bcs_strtol.c
@@ -1,58 +1,57 @@
/* $NetBSD: citrus_bcs_strtol.c,v 1.4 2013/04/26 21:20:47 joerg Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 The DragonFly Project. All rights reserved.
* Copyright (c) 2003, 2008 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#define _FUNCNAME _bcs_strtol
#define __INT long int
#undef isspace
#define isspace(c) _bcs_isspace(c)
#undef isdigit
#define isdigit(c) _bcs_isdigit(c)
#undef isalpha
#define isalpha(c) _bcs_isalpha(c)
#undef isupper
#define isupper(c) _bcs_isupper(c)
#include "_strtol.h"
diff --git a/lib/libc/iconv/citrus_bcs_strtoul.c b/lib/libc/iconv/citrus_bcs_strtoul.c
index 0ea896d90b0e..280397a72428 100644
--- a/lib/libc/iconv/citrus_bcs_strtoul.c
+++ b/lib/libc/iconv/citrus_bcs_strtoul.c
@@ -1,58 +1,57 @@
/* $NetBSD: citrus_bcs_strtoul.c,v 1.5 2013/04/26 21:20:48 joerg Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 The DragonFly Project. All rights reserved.
* Copyright (c) 2003, 2008 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#define _FUNCNAME _bcs_strtoul
#define __UINT unsigned long int
#undef isspace
#define isspace(c) _bcs_isspace(c)
#undef isdigit
#define isdigit(c) _bcs_isdigit(c)
#undef isalpha
#define isalpha(c) _bcs_isalpha(c)
#undef isupper
#define isupper(c) _bcs_isupper(c)
#include "_strtoul.h"
diff --git a/lib/libc/iconv/citrus_csmapper.c b/lib/libc/iconv/citrus_csmapper.c
index e59ccfb3f02a..642abafbe9a2 100644
--- a/lib/libc/iconv/citrus_csmapper.c
+++ b/lib/libc/iconv/citrus_csmapper.c
@@ -1,387 +1,386 @@
/* $NetBSD: citrus_csmapper.c,v 1.11 2011/11/20 07:43:52 tnozaki Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/endian.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_bcs.h"
#include "citrus_region.h"
#include "citrus_lock.h"
#include "citrus_memstream.h"
#include "citrus_mmap.h"
#include "citrus_module.h"
#include "citrus_hash.h"
#include "citrus_mapper.h"
#include "citrus_csmapper.h"
#include "citrus_pivot_file.h"
#include "citrus_db.h"
#include "citrus_db_hash.h"
#include "citrus_lookup.h"
static struct _citrus_mapper_area *maparea = NULL;
static pthread_rwlock_t ma_lock = PTHREAD_RWLOCK_INITIALIZER;
#define CS_ALIAS _PATH_CSMAPPER "/charset.alias"
#define CS_PIVOT _PATH_CSMAPPER "/charset.pivot"
/* ---------------------------------------------------------------------- */
static int
get32(struct _region *r, uint32_t *rval)
{
if (_region_size(r) != 4)
return (EFTYPE);
memcpy(rval, _region_head(r), (size_t)4);
*rval = be32toh(*rval);
return (0);
}
static int
open_subdb(struct _citrus_db **subdb, struct _citrus_db *db, const char *src)
{
struct _region r;
int ret;
ret = _db_lookup_by_s(db, src, &r, NULL);
if (ret)
return (ret);
ret = _db_open(subdb, &r, _CITRUS_PIVOT_SUB_MAGIC, _db_hash_std, NULL);
if (ret)
return (ret);
return (0);
}
#define NO_SUCH_FILE EOPNOTSUPP
static int
find_best_pivot_pvdb(const char *src, const char *dst, char *pivot,
size_t pvlen, unsigned long *rnorm)
{
struct _citrus_db *db1, *db2, *db3;
struct _region fr, r1, r2;
char buf[LINE_MAX];
uint32_t val32;
unsigned long norm;
int i, num, ret;
ret = _map_file(&fr, CS_PIVOT ".pvdb");
if (ret) {
if (ret == ENOENT)
ret = NO_SUCH_FILE;
return (ret);
}
ret = _db_open(&db1, &fr, _CITRUS_PIVOT_MAGIC, _db_hash_std, NULL);
if (ret)
goto quit1;
ret = open_subdb(&db2, db1, src);
if (ret)
goto quit2;
num = _db_get_num_entries(db2);
*rnorm = ULONG_MAX;
for (i = 0; i < num; i++) {
/* iterate each pivot */
ret = _db_get_entry(db2, i, &r1, &r2);
if (ret)
goto quit3;
/* r1:pivot name, r2:norm among src and pivot */
ret = get32(&r2, &val32);
if (ret)
goto quit3;
norm = val32;
snprintf(buf, sizeof(buf), "%.*s",
(int)_region_size(&r1), (char *)_region_head(&r1));
/* buf: pivot name */
ret = open_subdb(&db3, db1, buf);
if (ret)
goto quit3;
if (_db_lookup_by_s(db3, dst, &r2, NULL) != 0)
/* don't break the loop, test all src/dst pairs. */
goto quit4;
/* r2: norm among pivot and dst */
ret = get32(&r2, &val32);
if (ret)
goto quit4;
norm += val32;
/* judge minimum norm */
if (norm < *rnorm) {
*rnorm = norm;
strlcpy(pivot, buf, pvlen);
}
quit4:
_db_close(db3);
if (ret)
goto quit3;
}
quit3:
_db_close(db2);
quit2:
_db_close(db1);
quit1:
_unmap_file(&fr);
if (ret)
return (ret);
if (*rnorm == ULONG_MAX)
return (ENOENT);
return (0);
}
/* ---------------------------------------------------------------------- */
struct zone {
const char *begin, *end;
};
struct parse_arg {
char dst[PATH_MAX];
unsigned long norm;
};
static int
parse_line(struct parse_arg *pa, struct _region *r)
{
struct zone z1, z2;
char buf[20];
size_t len;
len = _region_size(r);
z1.begin = _bcs_skip_ws_len(_region_head(r), &len);
if (len == 0)
return (EFTYPE);
z1.end = _bcs_skip_nonws_len(z1.begin, &len);
if (len == 0)
return (EFTYPE);
z2.begin = _bcs_skip_ws_len(z1.end, &len);
if (len == 0)
return (EFTYPE);
z2.end = _bcs_skip_nonws_len(z2.begin, &len);
/* z1 : dst name, z2 : norm */
snprintf(pa->dst, sizeof(pa->dst),
"%.*s", (int)(z1.end-z1.begin), z1.begin);
snprintf(buf, sizeof(buf),
"%.*s", (int)(z2.end-z2.begin), z2.begin);
pa->norm = _bcs_strtoul(buf, NULL, 0);
return (0);
}
static int
find_dst(struct parse_arg *pasrc, const char *dst)
{
struct _lookup *cl;
struct parse_arg padst;
struct _region data;
int ret;
ret = _lookup_seq_open(&cl, CS_PIVOT, _LOOKUP_CASE_IGNORE);
if (ret)
return (ret);
ret = _lookup_seq_lookup(cl, pasrc->dst, &data);
while (ret == 0) {
ret = parse_line(&padst, &data);
if (ret)
break;
if (strcmp(dst, padst.dst) == 0) {
pasrc->norm += padst.norm;
break;
}
ret = _lookup_seq_next(cl, NULL, &data);
}
_lookup_seq_close(cl);
return (ret);
}
static int
find_best_pivot_lookup(const char *src, const char *dst, char *pivot,
size_t pvlen, unsigned long *rnorm)
{
struct _lookup *cl;
struct _region data;
struct parse_arg pa;
char pivot_min[PATH_MAX];
unsigned long norm_min;
int ret;
ret = _lookup_seq_open(&cl, CS_PIVOT, _LOOKUP_CASE_IGNORE);
if (ret)
return (ret);
norm_min = ULONG_MAX;
/* find pivot code */
ret = _lookup_seq_lookup(cl, src, &data);
while (ret == 0) {
ret = parse_line(&pa, &data);
if (ret)
break;
ret = find_dst(&pa, dst);
if (ret)
break;
if (pa.norm < norm_min) {
norm_min = pa.norm;
strlcpy(pivot_min, pa.dst, sizeof(pivot_min));
}
ret = _lookup_seq_next(cl, NULL, &data);
}
_lookup_seq_close(cl);
if (ret != ENOENT)
return (ret);
if (norm_min == ULONG_MAX)
return (ENOENT);
strlcpy(pivot, pivot_min, pvlen);
if (rnorm)
*rnorm = norm_min;
return (0);
}
static int
find_best_pivot(const char *src, const char *dst, char *pivot, size_t pvlen,
unsigned long *rnorm)
{
int ret;
ret = find_best_pivot_pvdb(src, dst, pivot, pvlen, rnorm);
if (ret == NO_SUCH_FILE)
ret = find_best_pivot_lookup(src, dst, pivot, pvlen, rnorm);
return (ret);
}
static __inline int
open_serial_mapper(struct _citrus_mapper_area *__restrict ma,
struct _citrus_mapper * __restrict * __restrict rcm,
const char *src, const char *pivot, const char *dst)
{
char buf[PATH_MAX];
snprintf(buf, sizeof(buf), "%s/%s,%s/%s", src, pivot, pivot, dst);
return (_mapper_open_direct(ma, rcm, "mapper_serial", buf));
}
static struct _citrus_csmapper *csm_none = NULL;
static int
get_none(struct _citrus_mapper_area *__restrict ma,
struct _citrus_csmapper *__restrict *__restrict rcsm)
{
int ret;
WLOCK(&ma_lock);
if (csm_none) {
*rcsm = csm_none;
ret = 0;
goto quit;
}
ret = _mapper_open_direct(ma, &csm_none, "mapper_none", "");
if (ret)
goto quit;
_mapper_set_persistent(csm_none);
*rcsm = csm_none;
ret = 0;
quit:
UNLOCK(&ma_lock);
return (ret);
}
int
_citrus_csmapper_open(struct _citrus_csmapper * __restrict * __restrict rcsm,
const char * __restrict src, const char * __restrict dst, uint32_t flags,
unsigned long *rnorm)
{
const char *realsrc, *realdst;
char buf1[PATH_MAX], buf2[PATH_MAX], key[PATH_MAX], pivot[PATH_MAX];
unsigned long norm;
int ret;
norm = 0;
ret = _citrus_mapper_create_area(&maparea, _PATH_CSMAPPER);
if (ret)
return (ret);
realsrc = _lookup_alias(CS_ALIAS, src, buf1, sizeof(buf1),
_LOOKUP_CASE_IGNORE);
realdst = _lookup_alias(CS_ALIAS, dst, buf2, sizeof(buf2),
_LOOKUP_CASE_IGNORE);
if (!strcmp(realsrc, realdst)) {
ret = get_none(maparea, rcsm);
if (ret == 0 && rnorm != NULL)
*rnorm = 0;
return (ret);
}
snprintf(key, sizeof(key), "%s/%s", realsrc, realdst);
ret = _mapper_open(maparea, rcsm, key);
if (ret == 0) {
if (rnorm != NULL)
*rnorm = 0;
return (0);
}
if (ret != ENOENT || (flags & _CSMAPPER_F_PREVENT_PIVOT)!=0)
return (ret);
ret = find_best_pivot(realsrc, realdst, pivot, sizeof(pivot), &norm);
if (ret)
return (ret);
ret = open_serial_mapper(maparea, rcsm, realsrc, pivot, realdst);
if (ret == 0 && rnorm != NULL)
*rnorm = norm;
return (ret);
}
diff --git a/lib/libc/iconv/citrus_db.c b/lib/libc/iconv/citrus_db.c
index 4a89a9cb86f4..bb74668a2d4c 100644
--- a/lib/libc/iconv/citrus_db.c
+++ b/lib/libc/iconv/citrus_db.c
@@ -1,332 +1,331 @@
/* $NetBSD: citrus_db.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/endian.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#include "citrus_region.h"
#include "citrus_memstream.h"
#include "citrus_mmap.h"
#include "citrus_db.h"
#include "citrus_db_factory.h"
#include "citrus_db_file.h"
struct _citrus_db {
struct _region db_region;
_citrus_db_hash_func_t db_hashfunc;
void *db_hashfunc_closure;
};
int
_citrus_db_open(struct _citrus_db **rdb, struct _region *r, const char *magic,
_citrus_db_hash_func_t hashfunc, void *hashfunc_closure)
{
struct _citrus_db *db;
struct _citrus_db_header_x *dhx;
struct _memstream ms;
_memstream_bind(&ms, r);
/* sanity check */
dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
if (dhx == NULL)
return (EFTYPE);
if (strncmp(dhx->dhx_magic, magic, _CITRUS_DB_MAGIC_SIZE) != 0)
return (EFTYPE);
if (_memstream_seek(&ms, be32toh(dhx->dhx_entry_offset), SEEK_SET))
return (EFTYPE);
if (be32toh(dhx->dhx_num_entries)*_CITRUS_DB_ENTRY_SIZE >
_memstream_remainder(&ms))
return (EFTYPE);
db = malloc(sizeof(*db));
if (db == NULL)
return (errno);
db->db_region = *r;
db->db_hashfunc = hashfunc;
db->db_hashfunc_closure = hashfunc_closure;
*rdb = db;
return (0);
}
void
_citrus_db_close(struct _citrus_db *db)
{
free(db);
}
int
_citrus_db_lookup(struct _citrus_db *db, struct _citrus_region *key,
struct _citrus_region *data, struct _citrus_db_locator *dl)
{
struct _citrus_db_entry_x *dex;
struct _citrus_db_header_x *dhx;
struct _citrus_region r;
struct _memstream ms;
uint32_t hashval, num_entries;
size_t offset;
_memstream_bind(&ms, &db->db_region);
dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
num_entries = be32toh(dhx->dhx_num_entries);
if (num_entries == 0)
return (ENOENT);
if (dl != NULL && dl->dl_offset>0) {
hashval = dl->dl_hashval;
offset = dl->dl_offset;
if (offset >= _region_size(&db->db_region))
return (ENOENT);
} else {
hashval = db->db_hashfunc(key)%num_entries;
offset = be32toh(dhx->dhx_entry_offset) +
hashval * _CITRUS_DB_ENTRY_SIZE;
if (dl)
dl->dl_hashval = hashval;
}
do {
/* seek to the next entry */
if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
return (EFTYPE);
/* get the entry record */
dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
if (dex == NULL)
return (EFTYPE);
/* jump to next entry having the same hash value. */
offset = be32toh(dex->dex_next_offset);
/* save the current position */
if (dl) {
dl->dl_offset = offset;
if (offset == 0)
dl->dl_offset = _region_size(&db->db_region);
}
/* compare hash value. */
if (be32toh(dex->dex_hash_value) != hashval)
/* not found */
break;
/* compare key length */
if (be32toh(dex->dex_key_size) == _region_size(key)) {
/* seek to the head of the key. */
if (_memstream_seek(&ms, be32toh(dex->dex_key_offset),
SEEK_SET))
return (EFTYPE);
/* get the region of the key */
if (_memstream_getregion(&ms, &r,
_region_size(key)) == NULL)
return (EFTYPE);
/* compare key byte stream */
if (memcmp(_region_head(&r), _region_head(key),
_region_size(key)) == 0) {
/* match */
if (_memstream_seek(
&ms, be32toh(dex->dex_data_offset),
SEEK_SET))
return (EFTYPE);
if (_memstream_getregion(
&ms, data,
be32toh(dex->dex_data_size)) == NULL)
return (EFTYPE);
return (0);
}
}
} while (offset != 0);
return (ENOENT);
}
int
_citrus_db_lookup_by_string(struct _citrus_db *db, const char *key,
struct _citrus_region *data, struct _citrus_db_locator *dl)
{
struct _region r;
_region_init(&r, __DECONST(void *, key), strlen(key));
return (_citrus_db_lookup(db, &r, data, dl));
}
int
_citrus_db_lookup8_by_string(struct _citrus_db *db, const char *key,
uint8_t *rval, struct _citrus_db_locator *dl)
{
struct _region r;
int ret;
ret = _citrus_db_lookup_by_string(db, key, &r, dl);
if (ret)
return (ret);
if (_region_size(&r) != 1)
return (EFTYPE);
if (rval)
memcpy(rval, _region_head(&r), 1);
return (0);
}
int
_citrus_db_lookup16_by_string(struct _citrus_db *db, const char *key,
uint16_t *rval, struct _citrus_db_locator *dl)
{
struct _region r;
int ret;
uint16_t val;
ret = _citrus_db_lookup_by_string(db, key, &r, dl);
if (ret)
return (ret);
if (_region_size(&r) != 2)
return (EFTYPE);
if (rval) {
memcpy(&val, _region_head(&r), 2);
*rval = be16toh(val);
}
return (0);
}
int
_citrus_db_lookup32_by_string(struct _citrus_db *db, const char *key,
uint32_t *rval, struct _citrus_db_locator *dl)
{
struct _region r;
uint32_t val;
int ret;
ret = _citrus_db_lookup_by_string(db, key, &r, dl);
if (ret)
return (ret);
if (_region_size(&r) != 4)
return (EFTYPE);
if (rval) {
memcpy(&val, _region_head(&r), 4);
*rval = be32toh(val);
}
return (0);
}
int
_citrus_db_lookup_string_by_string(struct _citrus_db *db, const char *key,
const char **rdata, struct _citrus_db_locator *dl)
{
struct _region r;
int ret;
ret = _citrus_db_lookup_by_string(db, key, &r, dl);
if (ret)
return (ret);
/* check whether the string is null terminated */
if (_region_size(&r) == 0)
return (EFTYPE);
if (*((const char*)_region_head(&r)+_region_size(&r)-1) != '\0')
return (EFTYPE);
if (rdata)
*rdata = _region_head(&r);
return (0);
}
int
_citrus_db_get_number_of_entries(struct _citrus_db *db)
{
struct _citrus_db_header_x *dhx;
struct _memstream ms;
_memstream_bind(&ms, &db->db_region);
dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
return ((int)be32toh(dhx->dhx_num_entries));
}
int
_citrus_db_get_entry(struct _citrus_db *db, int idx, struct _region *key,
struct _region *data)
{
struct _citrus_db_entry_x *dex;
struct _citrus_db_header_x *dhx;
struct _memstream ms;
uint32_t num_entries;
size_t offset;
_memstream_bind(&ms, &db->db_region);
dhx = _memstream_getregion(&ms, NULL, sizeof(*dhx));
num_entries = be32toh(dhx->dhx_num_entries);
if (idx < 0 || (uint32_t)idx >= num_entries)
return (EINVAL);
/* seek to the next entry */
offset = be32toh(dhx->dhx_entry_offset) + idx * _CITRUS_DB_ENTRY_SIZE;
if (_citrus_memory_stream_seek(&ms, offset, SEEK_SET))
return (EFTYPE);
/* get the entry record */
dex = _memstream_getregion(&ms, NULL, _CITRUS_DB_ENTRY_SIZE);
if (dex == NULL)
return (EFTYPE);
/* seek to the head of the key. */
if (_memstream_seek(&ms, be32toh(dex->dex_key_offset), SEEK_SET))
return (EFTYPE);
/* get the region of the key. */
if (_memstream_getregion(&ms, key, be32toh(dex->dex_key_size))==NULL)
return (EFTYPE);
/* seek to the head of the data. */
if (_memstream_seek(&ms, be32toh(dex->dex_data_offset), SEEK_SET))
return (EFTYPE);
/* get the region of the data. */
if (_memstream_getregion(&ms, data, be32toh(dex->dex_data_size))==NULL)
return (EFTYPE);
return (0);
}
diff --git a/lib/libc/iconv/citrus_db_factory.c b/lib/libc/iconv/citrus_db_factory.c
index 589c1f43a60b..c1753195c767 100644
--- a/lib/libc/iconv/citrus_db_factory.c
+++ b/lib/libc/iconv/citrus_db_factory.c
@@ -1,338 +1,337 @@
/* $NetBSD: citrus_db_factory.c,v 1.10 2013/09/14 13:05:51 joerg Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_region.h"
#include "citrus_db_file.h"
#include "citrus_db_factory.h"
struct _citrus_db_factory_entry {
STAILQ_ENTRY(_citrus_db_factory_entry) de_entry;
struct _citrus_db_factory_entry *de_next;
uint32_t de_hashvalue;
struct _region de_key;
int de_key_free;
struct _region de_data;
int de_data_free;
int de_idx;
};
struct _citrus_db_factory {
size_t df_num_entries;
STAILQ_HEAD(, _citrus_db_factory_entry) df_entries;
size_t df_total_key_size;
size_t df_total_data_size;
uint32_t (*df_hashfunc)(struct _citrus_region *);
void *df_hashfunc_closure;
};
#define DB_ALIGN 16
int
_citrus_db_factory_create(struct _citrus_db_factory **rdf,
_citrus_db_hash_func_t hashfunc, void *hashfunc_closure)
{
struct _citrus_db_factory *df;
df = malloc(sizeof(*df));
if (df == NULL)
return (errno);
df->df_num_entries = 0;
df->df_total_key_size = df->df_total_data_size = 0;
STAILQ_INIT(&df->df_entries);
df->df_hashfunc = hashfunc;
df->df_hashfunc_closure = hashfunc_closure;
*rdf = df;
return (0);
}
void
_citrus_db_factory_free(struct _citrus_db_factory *df)
{
struct _citrus_db_factory_entry *de;
while ((de = STAILQ_FIRST(&df->df_entries)) != NULL) {
STAILQ_REMOVE_HEAD(&df->df_entries, de_entry);
if (de->de_key_free)
free(_region_head(&de->de_key));
if (de->de_data_free)
free(_region_head(&de->de_data));
free(de);
}
free(df);
}
static __inline size_t
ceilto(size_t sz)
{
return ((sz + DB_ALIGN - 1) & ~(DB_ALIGN - 1));
}
int
_citrus_db_factory_add(struct _citrus_db_factory *df, struct _region *key,
int keyfree, struct _region *data, int datafree)
{
struct _citrus_db_factory_entry *de;
de = malloc(sizeof(*de));
if (de == NULL)
return (-1);
de->de_hashvalue = df->df_hashfunc(key);
de->de_key = *key;
de->de_key_free = keyfree;
de->de_data = *data;
de->de_data_free = datafree;
de->de_idx = -1;
STAILQ_INSERT_TAIL(&df->df_entries, de, de_entry);
df->df_total_key_size += _region_size(key);
df->df_total_data_size += ceilto(_region_size(data));
df->df_num_entries++;
return (0);
}
int
_citrus_db_factory_add_by_string(struct _citrus_db_factory *df,
const char *key, struct _citrus_region *data, int datafree)
{
struct _region r;
char *tmp;
tmp = strdup(key);
if (tmp == NULL)
return (errno);
_region_init(&r, tmp, strlen(key));
return _citrus_db_factory_add(df, &r, 1, data, datafree);
}
int
_citrus_db_factory_add8_by_string(struct _citrus_db_factory *df,
const char *key, uint8_t val)
{
struct _region r;
uint8_t *p;
p = malloc(sizeof(*p));
if (p == NULL)
return (errno);
*p = val;
_region_init(&r, p, 1);
return (_citrus_db_factory_add_by_string(df, key, &r, 1));
}
int
_citrus_db_factory_add16_by_string(struct _citrus_db_factory *df,
const char *key, uint16_t val)
{
struct _region r;
uint16_t *p;
p = malloc(sizeof(*p));
if (p == NULL)
return (errno);
*p = htons(val);
_region_init(&r, p, 2);
return (_citrus_db_factory_add_by_string(df, key, &r, 1));
}
int
_citrus_db_factory_add32_by_string(struct _citrus_db_factory *df,
const char *key, uint32_t val)
{
struct _region r;
uint32_t *p;
p = malloc(sizeof(*p));
if (p == NULL)
return (errno);
*p = htonl(val);
_region_init(&r, p, 4);
return (_citrus_db_factory_add_by_string(df, key, &r, 1));
}
int
_citrus_db_factory_add_string_by_string(struct _citrus_db_factory *df,
const char *key, const char *data)
{
char *p;
struct _region r;
p = strdup(data);
if (p == NULL)
return (errno);
_region_init(&r, p, strlen(p) + 1);
return (_citrus_db_factory_add_by_string(df, key, &r, 1));
}
size_t
_citrus_db_factory_calc_size(struct _citrus_db_factory *df)
{
size_t sz;
sz = ceilto(_CITRUS_DB_HEADER_SIZE);
sz += ceilto(_CITRUS_DB_ENTRY_SIZE * df->df_num_entries);
sz += ceilto(df->df_total_key_size);
sz += df->df_total_data_size;
return (sz);
}
static __inline void
put8(struct _region *r, size_t *rofs, uint8_t val)
{
*(uint8_t *)_region_offset(r, *rofs) = val;
*rofs += 1;
}
static __inline void
put32(struct _region *r, size_t *rofs, uint32_t val)
{
val = htonl(val);
memcpy(_region_offset(r, *rofs), &val, 4);
*rofs += 4;
}
static __inline void
putpad(struct _region *r, size_t *rofs)
{
size_t i;
for (i = ceilto(*rofs) - *rofs; i > 0; i--)
put8(r, rofs, 0);
}
static __inline void
dump_header(struct _region *r, const char *magic, size_t *rofs,
size_t num_entries)
{
while (*rofs<_CITRUS_DB_MAGIC_SIZE)
put8(r, rofs, *magic++);
put32(r, rofs, num_entries);
put32(r, rofs, _CITRUS_DB_HEADER_SIZE);
}
int
_citrus_db_factory_serialize(struct _citrus_db_factory *df, const char *magic,
struct _region *r)
{
struct _citrus_db_factory_entry *de, **depp, *det;
size_t dataofs, i, keyofs, nextofs, ofs;
ofs = 0;
/* check whether more than 0 entries exist */
if (df->df_num_entries == 0) {
dump_header(r, magic, &ofs, 0);
return (0);
}
/* allocate hash table */
depp = calloc(df->df_num_entries, sizeof(*depp));
if (depp == NULL)
return (-1);
/* step1: store the entries which are not conflicting */
STAILQ_FOREACH(de, &df->df_entries, de_entry) {
de->de_hashvalue %= df->df_num_entries;
de->de_idx = -1;
de->de_next = NULL;
if (depp[de->de_hashvalue] == NULL) {
depp[de->de_hashvalue] = de;
de->de_idx = (int)de->de_hashvalue;
}
}
/* step2: resolve conflicts */
i = 0;
STAILQ_FOREACH(de, &df->df_entries, de_entry) {
if (de->de_idx == -1) {
det = depp[de->de_hashvalue];
while (det->de_next != NULL)
det = det->de_next;
det->de_next = de;
while (depp[i] != NULL)
i++;
depp[i] = de;
de->de_idx = (int)i;
}
}
keyofs = _CITRUS_DB_HEADER_SIZE +
ceilto(df->df_num_entries*_CITRUS_DB_ENTRY_SIZE);
dataofs = keyofs + ceilto(df->df_total_key_size);
/* dump header */
dump_header(r, magic, &ofs, df->df_num_entries);
/* dump entries */
for (i = 0; i < df->df_num_entries; i++) {
de = depp[i];
nextofs = 0;
if (de->de_next) {
nextofs = _CITRUS_DB_HEADER_SIZE +
de->de_next->de_idx * _CITRUS_DB_ENTRY_SIZE;
}
put32(r, &ofs, de->de_hashvalue);
put32(r, &ofs, nextofs);
put32(r, &ofs, keyofs);
put32(r, &ofs, _region_size(&de->de_key));
put32(r, &ofs, dataofs);
put32(r, &ofs, _region_size(&de->de_data));
memcpy(_region_offset(r, keyofs),
_region_head(&de->de_key), _region_size(&de->de_key));
keyofs += _region_size(&de->de_key);
memcpy(_region_offset(r, dataofs),
_region_head(&de->de_data), _region_size(&de->de_data));
dataofs += _region_size(&de->de_data);
putpad(r, &dataofs);
}
putpad(r, &ofs);
putpad(r, &keyofs);
free(depp);
return (0);
}
diff --git a/lib/libc/iconv/citrus_db_hash.c b/lib/libc/iconv/citrus_db_hash.c
index 9e9918e38655..24b7213ee268 100644
--- a/lib/libc/iconv/citrus_db_hash.c
+++ b/lib/libc/iconv/citrus_db_hash.c
@@ -1,65 +1,64 @@
/* $NetBSD: citrus_db_hash.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_bcs.h"
#include "citrus_region.h"
#include "citrus_db_hash.h"
uint32_t
_citrus_db_hash_std(struct _region *r)
{
const uint8_t *p;
uint32_t hash, tmp;
size_t i;
hash = 0;
p = _region_head(r);
for (i = _region_size(r); i > 0; i--) {
hash <<= 4;
hash += _bcs_tolower(*p);
tmp = hash & 0xF0000000;
if (tmp != 0) {
hash ^= tmp;
hash ^= tmp >> 24;
}
p++;
}
return (hash);
}
diff --git a/lib/libc/iconv/citrus_esdb.c b/lib/libc/iconv/citrus_esdb.c
index 15c107566101..65b518f838c6 100644
--- a/lib/libc/iconv/citrus_esdb.c
+++ b/lib/libc/iconv/citrus_esdb.c
@@ -1,367 +1,366 @@
/* $NetBSD: citrus_esdb.c,v 1.5 2008/02/09 14:56:20 junyoung Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_bcs.h"
#include "citrus_region.h"
#include "citrus_memstream.h"
#include "citrus_mmap.h"
#include "citrus_lookup.h"
#include "citrus_db.h"
#include "citrus_db_hash.h"
#include "citrus_esdb.h"
#include "citrus_esdb_file.h"
#define ESDB_DIR "esdb.dir"
#define ESDB_ALIAS "esdb.alias"
/*
* _citrus_esdb_alias:
* resolve encoding scheme name aliases.
*/
const char *
_citrus_esdb_alias(const char *esname, char *buf, size_t bufsize)
{
return (_lookup_alias(_PATH_ESDB "/" ESDB_ALIAS, esname, buf, bufsize,
_LOOKUP_CASE_IGNORE));
}
/*
* conv_esdb:
* external representation -> local structure.
*/
static int
conv_esdb(struct _citrus_esdb *esdb, struct _region *fr)
{
struct _citrus_db *db;
const char *str;
char buf[100];
uint32_t csid, i, num_charsets, tmp, version;
int ret;
/* open db */
ret = _db_open(&db, fr, _CITRUS_ESDB_MAGIC, &_db_hash_std, NULL);
if (ret)
goto err0;
/* check version */
ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_VERSION, &version, NULL);
if (ret)
goto err1;
switch (version) {
case 0x00000001:
/* current version */
/* initial version */
break;
default:
ret = EFTYPE;
goto err1;
}
/* get encoding/variable */
ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_ENCODING, &str, NULL);
if (ret)
goto err1;
esdb->db_encname = strdup(str);
if (esdb->db_encname == NULL) {
ret = errno;
goto err1;
}
esdb->db_len_variable = 0;
esdb->db_variable = NULL;
ret = _db_lookupstr_by_s(db, _CITRUS_ESDB_SYM_VARIABLE, &str, NULL);
if (ret == 0) {
esdb->db_len_variable = strlen(str) + 1;
esdb->db_variable = strdup(str);
if (esdb->db_variable == NULL) {
ret = errno;
goto err2;
}
} else if (ret != ENOENT)
goto err2;
/* get number of charsets */
ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_NUM_CHARSETS,
&num_charsets, NULL);
if (ret)
goto err3;
esdb->db_num_charsets = num_charsets;
/* get invalid character */
ret = _db_lookup32_by_s(db, _CITRUS_ESDB_SYM_INVALID, &tmp, NULL);
if (ret == 0) {
esdb->db_use_invalid = 1;
esdb->db_invalid = tmp;
} else if (ret == ENOENT)
esdb->db_use_invalid = 0;
else
goto err3;
/* get charsets */
esdb->db_charsets = malloc(num_charsets * sizeof(*esdb->db_charsets));
if (esdb->db_charsets == NULL) {
ret = errno;
goto err3;
}
for (i = 0; i < num_charsets; i++) {
snprintf(buf, sizeof(buf),
_CITRUS_ESDB_SYM_CSID_PREFIX "%d", i);
ret = _db_lookup32_by_s(db, buf, &csid, NULL);
if (ret)
goto err4;
esdb->db_charsets[i].ec_csid = csid;
snprintf(buf, sizeof(buf),
_CITRUS_ESDB_SYM_CSNAME_PREFIX "%d", i);
ret = _db_lookupstr_by_s(db, buf, &str, NULL);
if (ret)
goto err4;
esdb->db_charsets[i].ec_csname = strdup(str);
if (esdb->db_charsets[i].ec_csname == NULL) {
ret = errno;
goto err4;
}
}
_db_close(db);
return (0);
err4:
for (; i > 0; i--)
free(esdb->db_charsets[i - 1].ec_csname);
free(esdb->db_charsets);
err3:
free(esdb->db_variable);
err2:
free(esdb->db_encname);
err1:
_db_close(db);
if (ret == ENOENT)
ret = EFTYPE;
err0:
return (ret);
}
/*
* _citrus_esdb_open:
* open an ESDB file.
*/
int
_citrus_esdb_open(struct _citrus_esdb *db, const char *esname)
{
struct _region fr;
const char *realname, *encfile;
char buf1[PATH_MAX], buf2[PATH_MAX], path[PATH_MAX];
int ret;
snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_ALIAS);
realname = _lookup_alias(path, esname, buf1, sizeof(buf1),
_LOOKUP_CASE_IGNORE);
snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, ESDB_DIR);
encfile = _lookup_simple(path, realname, buf2, sizeof(buf2),
_LOOKUP_CASE_IGNORE);
if (encfile == NULL)
return (ENOENT);
/* open file */
snprintf(path, sizeof(path), "%s/%s", _PATH_ESDB, encfile);
ret = _map_file(&fr, path);
if (ret)
return (ret);
ret = conv_esdb(db, &fr);
_unmap_file(&fr);
return (ret);
}
/*
* _citrus_esdb_close:
* free an ESDB.
*/
void
_citrus_esdb_close(struct _citrus_esdb *db)
{
for (int i = 0; i < db->db_num_charsets; i++)
free(db->db_charsets[i].ec_csname);
db->db_num_charsets = 0;
free(db->db_charsets); db->db_charsets = NULL;
free(db->db_encname); db->db_encname = NULL;
db->db_len_variable = 0;
free(db->db_variable); db->db_variable = NULL;
}
/*
* _citrus_esdb_free_list:
* free the list.
*/
void
_citrus_esdb_free_list(char **list, size_t num)
{
for (size_t i = 0; i < num; i++)
free(list[i]);
free(list);
}
/*
* _citrus_esdb_get_list:
* get esdb entries.
*/
int
_citrus_esdb_get_list(char ***rlist, size_t *rnum, bool sorted)
{
struct _citrus_lookup *cla, *cld;
struct _region key, data;
char **list, **q;
char buf[PATH_MAX];
size_t num;
int ret;
ret = _lookup_seq_open(&cla, _PATH_ESDB "/" ESDB_ALIAS,
_LOOKUP_CASE_IGNORE);
if (ret)
goto quit0;
ret = _lookup_seq_open(&cld, _PATH_ESDB "/" ESDB_DIR,
_LOOKUP_CASE_IGNORE);
if (ret)
goto quit1;
/* count number of entries */
num = _lookup_get_num_entries(cla) + _lookup_get_num_entries(cld);
_lookup_seq_rewind(cla);
_lookup_seq_rewind(cld);
/* allocate list pointer space */
list = malloc(num * sizeof(char *));
num = 0;
if (list == NULL) {
ret = errno;
goto quit3;
}
/* get alias entries */
while ((ret = _lookup_seq_next(cla, &key, &data)) == 0) {
/* XXX: sorted? */
snprintf(buf, sizeof(buf), "%.*s/%.*s",
(int)_region_size(&data),
(const char *)_region_head(&data),
(int)_region_size(&key),
(const char *)_region_head(&key));
_bcs_convert_to_upper(buf);
list[num] = strdup(buf);
if (list[num] == NULL) {
ret = errno;
goto quit3;
}
num++;
}
if (ret != ENOENT)
goto quit3;
/* get dir entries */
while ((ret = _lookup_seq_next(cld, &key, &data)) == 0) {
if (!sorted)
snprintf(buf, sizeof(buf), "%.*s",
(int)_region_size(&key),
(const char *)_region_head(&key));
else {
/* check duplicated entry */
char *p;
char buf1[PATH_MAX];
snprintf(buf1, sizeof(buf1), "%.*s",
(int)_region_size(&data),
(const char *)_region_head(&data));
if ((p = strchr(buf1, '/')) != NULL)
memmove(buf1, p + 1, strlen(p) - 1);
if ((p = strstr(buf1, ".esdb")) != NULL)
*p = '\0';
snprintf(buf, sizeof(buf), "%s/%.*s", buf1,
(int)_region_size(&key),
(const char *)_region_head(&key));
}
_bcs_convert_to_upper(buf);
ret = _lookup_seq_lookup(cla, buf, NULL);
if (ret) {
if (ret != ENOENT)
goto quit3;
/* not duplicated */
list[num] = strdup(buf);
if (list[num] == NULL) {
ret = errno;
goto quit3;
}
num++;
}
}
if (ret != ENOENT)
goto quit3;
ret = 0;
/* XXX: why reallocing the list space posteriorly?
shouldn't be done earlier? */
q = reallocarray(list, num, sizeof(char *));
if (!q) {
ret = ENOMEM;
goto quit3;
}
list = q;
*rlist = list;
*rnum = num;
quit3:
if (ret)
_citrus_esdb_free_list(list, num);
_lookup_seq_close(cld);
quit1:
_lookup_seq_close(cla);
quit0:
return (ret);
}
diff --git a/lib/libc/iconv/citrus_hash.c b/lib/libc/iconv/citrus_hash.c
index 9dcf86354b3d..3a34efde3044 100644
--- a/lib/libc/iconv/citrus_hash.c
+++ b/lib/libc/iconv/citrus_hash.c
@@ -1,52 +1,51 @@
/* $NetBSD: citrus_hash.c,v 1.3 2008/02/09 14:56:20 junyoung Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_region.h"
#include "citrus_hash.h"
#include "citrus_db_hash.h"
int
_citrus_string_hash_func(const char *key, int hashsize)
{
struct _region r;
_region_init(&r, __DECONST(void *, key), strlen(key));
return ((int)(_db_hash_std(&r) % (uint32_t)hashsize));
}
diff --git a/lib/libc/iconv/citrus_iconv.c b/lib/libc/iconv/citrus_iconv.c
index a2ff7b5177c8..e785e6721968 100644
--- a/lib/libc/iconv/citrus_iconv.c
+++ b/lib/libc/iconv/citrus_iconv.c
@@ -1,372 +1,371 @@
/* $NetBSD: citrus_iconv.c,v 1.10 2011/11/19 18:34:21 tnozaki Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <iconv.h>
#include <langinfo.h>
#include <limits.h>
#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#include "citrus_esdb.h"
#include "citrus_region.h"
#include "citrus_memstream.h"
#include "citrus_mmap.h"
#include "citrus_module.h"
#include "citrus_lock.h"
#include "citrus_lookup.h"
#include "citrus_hash.h"
#include "citrus_iconv.h"
#define _CITRUS_ICONV_DIR "iconv.dir"
#define _CITRUS_ICONV_ALIAS "iconv.alias"
#define CI_HASH_SIZE 101
#define CI_INITIAL_MAX_REUSE 5
#define CI_ENV_MAX_REUSE "ICONV_MAX_REUSE"
static bool isinit = false;
static int shared_max_reuse, shared_num_unused;
static _CITRUS_HASH_HEAD(, _citrus_iconv_shared, CI_HASH_SIZE) shared_pool;
static TAILQ_HEAD(, _citrus_iconv_shared) shared_unused;
static pthread_rwlock_t ci_lock = PTHREAD_RWLOCK_INITIALIZER;
static __inline void
init_cache(void)
{
WLOCK(&ci_lock);
if (!isinit) {
_CITRUS_HASH_INIT(&shared_pool, CI_HASH_SIZE);
TAILQ_INIT(&shared_unused);
shared_max_reuse = -1;
if (secure_getenv(CI_ENV_MAX_REUSE) != NULL)
shared_max_reuse =
atoi(secure_getenv(CI_ENV_MAX_REUSE));
if (shared_max_reuse < 0)
shared_max_reuse = CI_INITIAL_MAX_REUSE;
isinit = true;
}
UNLOCK(&ci_lock);
}
static __inline void
close_shared(struct _citrus_iconv_shared *ci)
{
if (ci) {
if (ci->ci_module) {
if (ci->ci_ops) {
if (ci->ci_closure)
(*ci->ci_ops->io_uninit_shared)(ci);
free(ci->ci_ops);
}
_citrus_unload_module(ci->ci_module);
}
free(ci);
}
}
static __inline int
open_shared(struct _citrus_iconv_shared * __restrict * __restrict rci,
const char * __restrict convname, const char * __restrict src,
const char * __restrict dst)
{
struct _citrus_iconv_shared *ci;
_citrus_iconv_getops_t getops;
const char *module;
size_t len_convname;
int ret;
#ifdef INCOMPATIBLE_WITH_GNU_ICONV
/*
* Sadly, the gnu tools expect iconv to actually parse the
* byte stream and don't allow for a pass-through when
* the (src,dest) encodings are the same.
* See gettext-0.18.3+ NEWS:
* msgfmt now checks PO file headers more strictly with less
* false-positives.
* NetBSD, also, doesn't do the below pass-through.
*
* Also note that this currently falls short if dst options have been
* specified. It may be the case that we want to ignore EILSEQ, in which
* case we should also select iconv_std anyways. This trick, while
* clever, may not be worth it.
*/
module = (strcmp(src, dst) != 0) ? "iconv_std" : "iconv_none";
#else
module = "iconv_std";
#endif
/* initialize iconv handle */
len_convname = strlen(convname);
ci = calloc(1, sizeof(*ci) + len_convname + 1);
if (!ci) {
ret = errno;
goto err;
}
ci->ci_convname = (void *)&ci[1];
memcpy(ci->ci_convname, convname, len_convname + 1);
/* load module */
ret = _citrus_load_module(&ci->ci_module, module);
if (ret)
goto err;
/* get operators */
getops = (_citrus_iconv_getops_t)_citrus_find_getops(ci->ci_module,
module, "iconv");
if (!getops) {
ret = EOPNOTSUPP;
goto err;
}
ci->ci_ops = malloc(sizeof(*ci->ci_ops));
if (!ci->ci_ops) {
ret = errno;
goto err;
}
ret = (*getops)(ci->ci_ops);
if (ret)
goto err;
if (ci->ci_ops->io_init_shared == NULL ||
ci->ci_ops->io_uninit_shared == NULL ||
ci->ci_ops->io_init_context == NULL ||
ci->ci_ops->io_uninit_context == NULL ||
ci->ci_ops->io_convert == NULL) {
ret = EINVAL;
goto err;
}
/* initialize the converter */
ret = (*ci->ci_ops->io_init_shared)(ci, src, dst);
if (ret)
goto err;
*rci = ci;
return (0);
err:
close_shared(ci);
return (ret);
}
static __inline int
hash_func(const char *key)
{
return (_string_hash_func(key, CI_HASH_SIZE));
}
static __inline int
match_func(struct _citrus_iconv_shared * __restrict ci,
const char * __restrict key)
{
return (strcmp(ci->ci_convname, key));
}
static int
get_shared(struct _citrus_iconv_shared * __restrict * __restrict rci,
const char *src, const char *dst)
{
struct _citrus_iconv_shared * ci;
char convname[PATH_MAX];
int hashval, ret = 0;
snprintf(convname, sizeof(convname), "%s/%s", src, dst);
WLOCK(&ci_lock);
/* lookup alread existing entry */
hashval = hash_func(convname);
_CITRUS_HASH_SEARCH(&shared_pool, ci, ci_hash_entry, match_func,
convname, hashval);
if (ci != NULL) {
/* found */
if (ci->ci_used_count == 0) {
TAILQ_REMOVE(&shared_unused, ci, ci_tailq_entry);
shared_num_unused--;
}
ci->ci_used_count++;
*rci = ci;
goto quit;
}
/* create new entry */
ret = open_shared(&ci, convname, src, dst);
if (ret)
goto quit;
_CITRUS_HASH_INSERT(&shared_pool, ci, ci_hash_entry, hashval);
ci->ci_used_count = 1;
*rci = ci;
quit:
UNLOCK(&ci_lock);
return (ret);
}
static void
release_shared(struct _citrus_iconv_shared * __restrict ci)
{
WLOCK(&ci_lock);
ci->ci_used_count--;
if (ci->ci_used_count == 0) {
/* put it into unused list */
shared_num_unused++;
TAILQ_INSERT_TAIL(&shared_unused, ci, ci_tailq_entry);
/* flood out */
while (shared_num_unused > shared_max_reuse) {
ci = TAILQ_FIRST(&shared_unused);
TAILQ_REMOVE(&shared_unused, ci, ci_tailq_entry);
_CITRUS_HASH_REMOVE(ci, ci_hash_entry);
shared_num_unused--;
close_shared(ci);
}
}
UNLOCK(&ci_lock);
}
/*
* _citrus_iconv_open:
* open a converter for the specified in/out codes.
*/
int
_citrus_iconv_open(struct _citrus_iconv * __restrict * __restrict rcv,
const char * __restrict src, const char * __restrict dst)
{
struct _citrus_iconv *cv = NULL;
struct _citrus_iconv_shared *ci = NULL;
char realdst[PATH_MAX], realsrc[PATH_MAX], *slashes;
#ifdef _PATH_ICONV
char buf[PATH_MAX], path[PATH_MAX];
#endif
int ret;
init_cache();
/* GNU behaviour, using locale encoding if "" or "char" is specified */
if ((strcmp(src, "") == 0) || (strcmp(src, "char") == 0))
src = nl_langinfo(CODESET);
if ((strcmp(dst, "") == 0) || (strcmp(dst, "char") == 0))
dst = nl_langinfo(CODESET);
strlcpy(realsrc, src, (size_t)PATH_MAX);
if ((slashes = strstr(realsrc, "//")) != NULL)
*slashes = '\0';
strlcpy(realdst, dst, (size_t)PATH_MAX);
if ((slashes = strstr(realdst, "//")) != NULL)
*slashes = '\0';
/* resolve codeset name aliases */
#ifdef _PATH_ICONV
/*
* Note that the below reads from realsrc and realdst while it's
* repopulating (writing to) realsrc and realdst, but it's done so with
* a trip through `buf`.
*/
snprintf(path, sizeof(path), "%s/%s", _PATH_ICONV, _CITRUS_ICONV_ALIAS);
strlcpy(realsrc, _lookup_alias(path, realsrc, buf, (size_t)PATH_MAX,
_LOOKUP_CASE_IGNORE), (size_t)PATH_MAX);
strlcpy(realdst, _lookup_alias(path, realdst, buf, (size_t)PATH_MAX,
_LOOKUP_CASE_IGNORE), (size_t)PATH_MAX);
#endif
/* sanity check */
if (strchr(realsrc, '/') != NULL || strchr(realdst, '/'))
return (EINVAL);
/* get shared record */
ret = get_shared(&ci, realsrc, realdst);
if (ret)
return (ret);
/* create/init context */
if (*rcv == NULL) {
cv = malloc(sizeof(*cv));
if (cv == NULL) {
ret = errno;
release_shared(ci);
return (ret);
}
*rcv = cv;
}
(*rcv)->cv_shared = ci;
ret = (*ci->ci_ops->io_init_context)(*rcv);
if (ret) {
release_shared(ci);
free(cv);
return (ret);
}
return (0);
}
/*
* _citrus_iconv_close:
* close the specified converter.
*/
void
_citrus_iconv_close(struct _citrus_iconv *cv)
{
if (cv) {
(*cv->cv_shared->ci_ops->io_uninit_context)(cv);
release_shared(cv->cv_shared);
free(cv);
}
}
const char
*_citrus_iconv_canonicalize(const char *name)
{
char *buf;
if ((buf = calloc((size_t)PATH_MAX, sizeof(*buf))) == NULL)
return (NULL);
_citrus_esdb_alias(name, buf, (size_t)PATH_MAX);
return (buf);
}
diff --git a/lib/libc/iconv/citrus_lookup.c b/lib/libc/iconv/citrus_lookup.c
index 4d66a7d53ef2..ed224001bffb 100644
--- a/lib/libc/iconv/citrus_lookup.c
+++ b/lib/libc/iconv/citrus_lookup.c
@@ -1,363 +1,362 @@
/* $NetBSD: citrus_lookup.c,v 1.7 2012/05/04 16:45:05 joerg Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#include "citrus_region.h"
#include "citrus_memstream.h"
#include "citrus_mmap.h"
#include "citrus_db.h"
#include "citrus_db_hash.h"
#include "citrus_lookup.h"
#include "citrus_lookup_file.h"
struct _citrus_lookup {
union {
struct {
struct _citrus_db *db;
struct _citrus_region file;
int num, idx;
struct _db_locator locator;
} db;
struct {
struct _region r;
struct _memstream ms;
} plain;
} u;
#define cl_db u.db.db
#define cl_dbidx u.db.idx
#define cl_dbfile u.db.file
#define cl_dbnum u.db.num
#define cl_dblocator u.db.locator
#define cl_plainr u.plain.r
#define cl_plainms u.plain.ms
int cl_ignore_case;
int cl_rewind;
char *cl_key;
size_t cl_keylen;
int (*cl_next)(struct _citrus_lookup *, struct _region *,
struct _region *);
int (*cl_lookup)(struct _citrus_lookup *, const char *,
struct _region *);
int (*cl_num_entries)(struct _citrus_lookup *);
void (*cl_close)(struct _citrus_lookup *);
};
static int
seq_get_num_entries_db(struct _citrus_lookup *cl)
{
return (cl->cl_dbnum);
}
static int
seq_next_db(struct _citrus_lookup *cl, struct _region *key,
struct _region *data)
{
if (cl->cl_key) {
if (key)
_region_init(key, cl->cl_key, cl->cl_keylen);
return (_db_lookup_by_s(cl->cl_db, cl->cl_key, data,
&cl->cl_dblocator));
}
if (cl->cl_rewind) {
cl->cl_dbidx = 0;
}
cl->cl_rewind = 0;
if (cl->cl_dbidx >= cl->cl_dbnum)
return (ENOENT);
return (_db_get_entry(cl->cl_db, cl->cl_dbidx++, key, data));
}
static int
seq_lookup_db(struct _citrus_lookup *cl, const char *key, struct _region *data)
{
cl->cl_rewind = 0;
free(cl->cl_key);
cl->cl_key = strdup(key);
if (cl->cl_ignore_case)
_bcs_convert_to_lower(cl->cl_key);
cl->cl_keylen = strlen(cl->cl_key);
_db_locator_init(&cl->cl_dblocator);
return (_db_lookup_by_s(cl->cl_db, cl->cl_key, data,
&cl->cl_dblocator));
}
static void
seq_close_db(struct _citrus_lookup *cl)
{
_db_close(cl->cl_db);
_unmap_file(&cl->cl_dbfile);
}
static int
seq_open_db(struct _citrus_lookup *cl, const char *name)
{
struct _region r;
char path[PATH_MAX];
int ret;
snprintf(path, sizeof(path), "%s.db", name);
ret = _map_file(&r, path);
if (ret)
return (ret);
ret = _db_open(&cl->cl_db, &r, _CITRUS_LOOKUP_MAGIC,
_db_hash_std, NULL);
if (ret) {
_unmap_file(&r);
return (ret);
}
cl->cl_dbfile = r;
cl->cl_dbnum = _db_get_num_entries(cl->cl_db);
cl->cl_dbidx = 0;
cl->cl_rewind = 1;
cl->cl_lookup = &seq_lookup_db;
cl->cl_next = &seq_next_db;
cl->cl_num_entries = &seq_get_num_entries_db;
cl->cl_close = &seq_close_db;
return (0);
}
#define T_COMM '#'
static int
seq_next_plain(struct _citrus_lookup *cl, struct _region *key,
struct _region *data)
{
const char *p, *q;
size_t len;
if (cl->cl_rewind)
_memstream_bind(&cl->cl_plainms, &cl->cl_plainr);
cl->cl_rewind = 0;
retry:
p = _memstream_getln(&cl->cl_plainms, &len);
if (p == NULL)
return (ENOENT);
/* ignore comment */
q = memchr(p, T_COMM, len);
if (q) {
len = q - p;
}
/* ignore trailing spaces */
_bcs_trunc_rws_len(p, &len);
p = _bcs_skip_ws_len(p, &len);
q = _bcs_skip_nonws_len(p, &len);
if (p == q)
goto retry;
if (cl->cl_key && ((size_t)(q - p) != cl->cl_keylen ||
memcmp(p, cl->cl_key, (size_t)(q - p)) != 0))
goto retry;
/* found a entry */
if (key)
_region_init(key, __DECONST(void *, p), (size_t)(q - p));
p = _bcs_skip_ws_len(q, &len);
if (data)
_region_init(data, len ? __DECONST(void *, p) : NULL, len);
return (0);
}
static int
seq_get_num_entries_plain(struct _citrus_lookup *cl)
{
int num;
num = 0;
while (seq_next_plain(cl, NULL, NULL) == 0)
num++;
return (num);
}
static int
seq_lookup_plain(struct _citrus_lookup *cl, const char *key,
struct _region *data)
{
size_t len;
const char *p;
cl->cl_rewind = 0;
free(cl->cl_key);
cl->cl_key = strdup(key);
if (cl->cl_ignore_case)
_bcs_convert_to_lower(cl->cl_key);
cl->cl_keylen = strlen(cl->cl_key);
_memstream_bind(&cl->cl_plainms, &cl->cl_plainr);
p = _memstream_matchline(&cl->cl_plainms, cl->cl_key, &len, 0);
if (p == NULL)
return (ENOENT);
if (data)
_region_init(data, __DECONST(void *, p), len);
return (0);
}
static void
seq_close_plain(struct _citrus_lookup *cl)
{
_unmap_file(&cl->cl_plainr);
}
static int
seq_open_plain(struct _citrus_lookup *cl, const char *name)
{
int ret;
/* open read stream */
ret = _map_file(&cl->cl_plainr, name);
if (ret)
return (ret);
cl->cl_rewind = 1;
cl->cl_next = &seq_next_plain;
cl->cl_lookup = &seq_lookup_plain;
cl->cl_num_entries = &seq_get_num_entries_plain;
cl->cl_close = &seq_close_plain;
return (0);
}
int
_citrus_lookup_seq_open(struct _citrus_lookup **rcl, const char *name,
int ignore_case)
{
int ret;
struct _citrus_lookup *cl;
cl = malloc(sizeof(*cl));
if (cl == NULL)
return (errno);
cl->cl_key = NULL;
cl->cl_keylen = 0;
cl->cl_ignore_case = ignore_case;
ret = seq_open_db(cl, name);
if (ret == ENOENT)
ret = seq_open_plain(cl, name);
if (!ret)
*rcl = cl;
else
free(cl);
return (ret);
}
void
_citrus_lookup_seq_rewind(struct _citrus_lookup *cl)
{
cl->cl_rewind = 1;
free(cl->cl_key);
cl->cl_key = NULL;
cl->cl_keylen = 0;
}
int
_citrus_lookup_seq_next(struct _citrus_lookup *cl,
struct _region *key, struct _region *data)
{
return ((*cl->cl_next)(cl, key, data));
}
int
_citrus_lookup_seq_lookup(struct _citrus_lookup *cl, const char *key,
struct _region *data)
{
return ((*cl->cl_lookup)(cl, key, data));
}
int
_citrus_lookup_get_number_of_entries(struct _citrus_lookup *cl)
{
return ((*cl->cl_num_entries)(cl));
}
void
_citrus_lookup_seq_close(struct _citrus_lookup *cl)
{
free(cl->cl_key);
(*cl->cl_close)(cl);
free(cl);
}
char *
_citrus_lookup_simple(const char *name, const char *key,
char *linebuf, size_t linebufsize, int ignore_case)
{
struct _citrus_lookup *cl;
struct _region data;
int ret;
ret = _citrus_lookup_seq_open(&cl, name, ignore_case);
if (ret)
return (NULL);
ret = _citrus_lookup_seq_lookup(cl, key, &data);
if (ret) {
_citrus_lookup_seq_close(cl);
return (NULL);
}
snprintf(linebuf, linebufsize, "%.*s", (int)_region_size(&data),
(const char *)_region_head(&data));
_citrus_lookup_seq_close(cl);
return (linebuf);
}
diff --git a/lib/libc/iconv/citrus_lookup_factory.c b/lib/libc/iconv/citrus_lookup_factory.c
index c2afe1d869b8..59b119e24872 100644
--- a/lib/libc/iconv/citrus_lookup_factory.c
+++ b/lib/libc/iconv/citrus_lookup_factory.c
@@ -1,122 +1,121 @@
/* $NetBSD: citrus_lookup_factory.c,v 1.4 2003/10/27 00:12:42 lukem Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_region.h"
#include "citrus_bcs.h"
#include "citrus_db_factory.h"
#include "citrus_db_hash.h"
#include "citrus_lookup_factory.h"
#include "citrus_lookup_file.h"
#define T_COMM '#'
static int
convert_line(struct _citrus_db_factory *df, const char *line, size_t len)
{
const char *p;
char data[LINE_MAX], key[LINE_MAX];
/* cut off trailing comment */
p = memchr(line, T_COMM, len);
if (p)
len = p - line;
/* key */
line = _bcs_skip_ws_len(line, &len);
if (len == 0)
return (0);
p = _bcs_skip_nonws_len(line, &len);
if (p == line)
return (0);
snprintf(key, sizeof(key), "%.*s", (int)(p-line), line);
_bcs_convert_to_lower(key);
/* data */
line = _bcs_skip_ws_len(p, &len);
_bcs_trunc_rws_len(line, &len);
snprintf(data, sizeof(data), "%.*s", (int)len, line);
return (_db_factory_addstr_by_s(df, key, data));
}
static int
dump_db(struct _citrus_db_factory *df, struct _region *r)
{
void *ptr;
size_t size;
size = _db_factory_calc_size(df);
ptr = malloc(size);
if (ptr == NULL)
return (errno);
_region_init(r, ptr, size);
return (_db_factory_serialize(df, _CITRUS_LOOKUP_MAGIC, r));
}
int
_citrus_lookup_factory_convert(FILE *out, FILE *in)
{
struct _citrus_db_factory *df;
struct _region r;
char *line;
size_t size;
int ret;
ret = _db_factory_create(&df, &_db_hash_std, NULL);
if (ret)
return (ret);
while ((line = fgetln(in, &size)) != NULL)
if ((ret = convert_line(df, line, size))) {
_db_factory_free(df);
return (ret);
}
ret = dump_db(df, &r);
_db_factory_free(df);
if (ret)
return (ret);
if (fwrite(_region_head(&r), _region_size(&r), 1, out) != 1)
return (errno);
return (0);
}
diff --git a/lib/libc/iconv/citrus_mapper.c b/lib/libc/iconv/citrus_mapper.c
index 5b919a9e9c92..45ea2d65de48 100644
--- a/lib/libc/iconv/citrus_mapper.c
+++ b/lib/libc/iconv/citrus_mapper.c
@@ -1,406 +1,405 @@
/* $NetBSD: citrus_mapper.c,v 1.10 2012/06/08 07:49:42 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/queue.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_region.h"
#include "citrus_lock.h"
#include "citrus_memstream.h"
#include "citrus_bcs.h"
#include "citrus_mmap.h"
#include "citrus_module.h"
#include "citrus_hash.h"
#include "citrus_mapper.h"
#define _CITRUS_MAPPER_DIR "mapper.dir"
#define CM_HASH_SIZE 101
#define REFCOUNT_PERSISTENT -1
static pthread_rwlock_t cm_lock = PTHREAD_RWLOCK_INITIALIZER;
struct _citrus_mapper_area {
_CITRUS_HASH_HEAD(, _citrus_mapper, CM_HASH_SIZE) ma_cache;
char *ma_dir;
};
/*
* _citrus_mapper_create_area:
* create mapper area
*/
int
_citrus_mapper_create_area(
struct _citrus_mapper_area *__restrict *__restrict rma,
const char *__restrict area)
{
struct _citrus_mapper_area *ma;
struct stat st;
char path[PATH_MAX];
int ret;
WLOCK(&cm_lock);
if (*rma != NULL) {
ret = 0;
goto quit;
}
snprintf(path, (size_t)PATH_MAX, "%s/%s", area, _CITRUS_MAPPER_DIR);
ret = stat(path, &st);
if (ret)
goto quit;
ma = malloc(sizeof(*ma));
if (ma == NULL) {
ret = errno;
goto quit;
}
ma->ma_dir = strdup(area);
if (ma->ma_dir == NULL) {
ret = errno;
free(ma);
goto quit;
}
_CITRUS_HASH_INIT(&ma->ma_cache, CM_HASH_SIZE);
*rma = ma;
ret = 0;
quit:
UNLOCK(&cm_lock);
return (ret);
}
/*
* lookup_mapper_entry:
* lookup mapper.dir entry in the specified directory.
*
* line format of iconv.dir file:
* mapper module arg
* mapper : mapper name.
* module : mapper module name.
* arg : argument for the module (generally, description file name)
*/
static int
lookup_mapper_entry(const char *dir, const char *mapname, void *linebuf,
size_t linebufsize, const char **module, const char **variable)
{
struct _region r;
struct _memstream ms;
const char *cp, *cq;
char *p;
char path[PATH_MAX];
size_t len;
int ret;
/* create mapper.dir path */
snprintf(path, (size_t)PATH_MAX, "%s/%s", dir, _CITRUS_MAPPER_DIR);
/* open read stream */
ret = _map_file(&r, path);
if (ret)
return (ret);
_memstream_bind(&ms, &r);
/* search the line matching to the map name */
cp = _memstream_matchline(&ms, mapname, &len, 0);
if (!cp) {
ret = ENOENT;
goto quit;
}
if (!len || len > linebufsize - 1) {
ret = EINVAL;
goto quit;
}
p = linebuf;
/* get module name */
*module = p;
cq = _bcs_skip_nonws_len(cp, &len);
strlcpy(p, cp, (size_t)(cq - cp + 1));
p += cq - cp + 1;
/* get variable */
*variable = p;
cp = _bcs_skip_ws_len(cq, &len);
strlcpy(p, cp, len + 1);
ret = 0;
quit:
_unmap_file(&r);
return (ret);
}
/*
* mapper_close:
* simply close a mapper. (without handling hash)
*/
static void
mapper_close(struct _citrus_mapper *cm)
{
if (cm->cm_module) {
if (cm->cm_ops) {
if (cm->cm_closure)
(*cm->cm_ops->mo_uninit)(cm);
free(cm->cm_ops);
}
_citrus_unload_module(cm->cm_module);
}
free(cm->cm_traits);
free(cm);
}
/*
* mapper_open:
* simply open a mapper. (without handling hash)
*/
static int
mapper_open(struct _citrus_mapper_area *__restrict ma,
struct _citrus_mapper * __restrict * __restrict rcm,
const char * __restrict module,
const char * __restrict variable)
{
struct _citrus_mapper *cm;
_citrus_mapper_getops_t getops;
int ret;
/* initialize mapper handle */
cm = malloc(sizeof(*cm));
if (!cm)
return (errno);
cm->cm_module = NULL;
cm->cm_ops = NULL;
cm->cm_closure = NULL;
cm->cm_traits = NULL;
cm->cm_refcount = 0;
cm->cm_key = NULL;
/* load module */
ret = _citrus_load_module(&cm->cm_module, module);
if (ret)
goto err;
/* get operators */
getops = (_citrus_mapper_getops_t)
_citrus_find_getops(cm->cm_module, module, "mapper");
if (!getops) {
ret = EOPNOTSUPP;
goto err;
}
cm->cm_ops = malloc(sizeof(*cm->cm_ops));
if (!cm->cm_ops) {
ret = errno;
goto err;
}
ret = (*getops)(cm->cm_ops);
if (ret)
goto err;
if (!cm->cm_ops->mo_init ||
!cm->cm_ops->mo_uninit ||
!cm->cm_ops->mo_convert ||
!cm->cm_ops->mo_init_state) {
ret = EINVAL;
goto err;
}
/* allocate traits structure */
cm->cm_traits = malloc(sizeof(*cm->cm_traits));
if (cm->cm_traits == NULL) {
ret = errno;
goto err;
}
/* initialize the mapper */
ret = (*cm->cm_ops->mo_init)(ma, cm, ma->ma_dir,
(const void *)variable, strlen(variable) + 1,
cm->cm_traits, sizeof(*cm->cm_traits));
if (ret)
goto err;
*rcm = cm;
return (0);
err:
mapper_close(cm);
return (ret);
}
/*
* _citrus_mapper_open_direct:
* open a mapper.
*/
int
_citrus_mapper_open_direct(struct _citrus_mapper_area *__restrict ma,
struct _citrus_mapper * __restrict * __restrict rcm,
const char * __restrict module, const char * __restrict variable)
{
return (mapper_open(ma, rcm, module, variable));
}
/*
* hash_func
*/
static __inline int
hash_func(const char *key)
{
return (_string_hash_func(key, CM_HASH_SIZE));
}
/*
* match_func
*/
static __inline int
match_func(struct _citrus_mapper *cm, const char *key)
{
return (strcmp(cm->cm_key, key));
}
/*
* _citrus_mapper_open:
* open a mapper with looking up "mapper.dir".
*/
int
_citrus_mapper_open(struct _citrus_mapper_area *__restrict ma,
struct _citrus_mapper * __restrict * __restrict rcm,
const char * __restrict mapname)
{
struct _citrus_mapper *cm;
char linebuf[PATH_MAX];
const char *module, *variable;
int hashval, ret;
variable = NULL;
WLOCK(&cm_lock);
/* search in the cache */
hashval = hash_func(mapname);
_CITRUS_HASH_SEARCH(&ma->ma_cache, cm, cm_entry, match_func, mapname,
hashval);
if (cm) {
/* found */
cm->cm_refcount++;
*rcm = cm;
ret = 0;
goto quit;
}
/* search mapper entry */
ret = lookup_mapper_entry(ma->ma_dir, mapname, linebuf,
(size_t)PATH_MAX, &module, &variable);
if (ret)
goto quit;
/* open mapper */
UNLOCK(&cm_lock);
ret = mapper_open(ma, &cm, module, variable);
WLOCK(&cm_lock);
if (ret)
goto quit;
cm->cm_key = strdup(mapname);
if (cm->cm_key == NULL) {
ret = errno;
_mapper_close(cm);
goto quit;
}
/* insert to the cache */
cm->cm_refcount = 1;
_CITRUS_HASH_INSERT(&ma->ma_cache, cm, cm_entry, hashval);
*rcm = cm;
ret = 0;
quit:
UNLOCK(&cm_lock);
return (ret);
}
/*
* _citrus_mapper_close:
* close the specified mapper.
*/
void
_citrus_mapper_close(struct _citrus_mapper *cm)
{
if (cm) {
WLOCK(&cm_lock);
if (cm->cm_refcount == REFCOUNT_PERSISTENT)
goto quit;
if (cm->cm_refcount > 0) {
if (--cm->cm_refcount > 0)
goto quit;
_CITRUS_HASH_REMOVE(cm, cm_entry);
free(cm->cm_key);
}
UNLOCK(&cm_lock);
mapper_close(cm);
return;
quit:
UNLOCK(&cm_lock);
}
}
/*
* _citrus_mapper_set_persistent:
* set persistent count.
*/
void
_citrus_mapper_set_persistent(struct _citrus_mapper * __restrict cm)
{
WLOCK(&cm_lock);
cm->cm_refcount = REFCOUNT_PERSISTENT;
UNLOCK(&cm_lock);
}
diff --git a/lib/libc/iconv/citrus_memstream.c b/lib/libc/iconv/citrus_memstream.c
index 25ab088ee413..10918bf2c5e0 100644
--- a/lib/libc/iconv/citrus_memstream.c
+++ b/lib/libc/iconv/citrus_memstream.c
@@ -1,148 +1,147 @@
/* $NetBSD: citrus_memstream.c,v 1.5 2012/03/13 21:13:31 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_region.h"
#include "citrus_memstream.h"
#include "citrus_bcs.h"
const char *
_citrus_memory_stream_getln(struct _citrus_memory_stream * __restrict ms,
size_t * __restrict rlen)
{
const uint8_t *h, *p;
size_t i, ret;
if (ms->ms_pos>=_region_size(&ms->ms_region))
return (NULL);
h = p = (uint8_t *)_region_offset(&ms->ms_region, ms->ms_pos);
ret = 0;
for (i = _region_size(&ms->ms_region) - ms->ms_pos; i > 0; i--) {
ret++;
if (_bcs_iseol(*p))
break;
p++;
}
ms->ms_pos += ret;
*rlen = ret;
return ((const char *)h);
}
#define T_COMM '#'
const char *
_citrus_memory_stream_matchline(struct _citrus_memory_stream * __restrict ms,
const char * __restrict key, size_t * __restrict rlen, int iscasesensitive)
{
const char *p, *q;
size_t keylen, len;
keylen = strlen(key);
for(;;) {
p = _citrus_memory_stream_getln(ms, &len);
if (p == NULL)
return (NULL);
/* ignore comment */
q = memchr(p, T_COMM, len);
if (q) {
len = q - p;
}
/* ignore trailing white space and newline */
_bcs_trunc_rws_len(p, &len);
if (len == 0)
continue; /* ignore null line */
/* skip white spaces at the head of the line */
p = _bcs_skip_ws_len(p, &len);
q = _bcs_skip_nonws_len(p, &len);
if ((size_t)(q - p) == keylen) {
if (iscasesensitive) {
if (memcmp(key, p, keylen) == 0)
break; /* match */
} else {
if (_bcs_strncasecmp(key, p, keylen) == 0)
break; /* match */
}
}
}
p = _bcs_skip_ws_len(q, &len);
*rlen = len;
return (p);
}
void *
_citrus_memory_stream_chr(struct _citrus_memory_stream *ms,
struct _citrus_region *r, char ch)
{
void *chr, *head;
size_t sz;
if (ms->ms_pos >= _region_size(&ms->ms_region))
return (NULL);
head = _region_offset(&ms->ms_region, ms->ms_pos);
chr = memchr(head, ch, _memstream_remainder(ms));
if (chr == NULL) {
_region_init(r, head, _memstream_remainder(ms));
ms->ms_pos = _region_size(&ms->ms_region);
return (NULL);
}
sz = (char *)chr - (char *)head;
_region_init(r, head, sz);
ms->ms_pos += sz + 1;
return (chr);
}
void
_citrus_memory_stream_skip_ws(struct _citrus_memory_stream *ms)
{
int ch;
while ((ch = _memstream_peek(ms)) != EOF) {
if (!_bcs_isspace(ch))
break;
_memstream_getc(ms);
}
}
diff --git a/lib/libc/iconv/citrus_mmap.c b/lib/libc/iconv/citrus_mmap.c
index b48242d94d38..7686a389edec 100644
--- a/lib/libc/iconv/citrus_mmap.c
+++ b/lib/libc/iconv/citrus_mmap.c
@@ -1,96 +1,95 @@
/* $NetBSD: citrus_mmap.c,v 1.4 2011/10/15 23:00:01 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include "namespace.h"
-#include <sys/cdefs.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "citrus_namespace.h"
#include "citrus_region.h"
#include "citrus_mmap.h"
int
_citrus_map_file(struct _citrus_region * __restrict r,
const char * __restrict path)
{
struct stat st;
void *head;
int fd, ret;
ret = 0;
_region_init(r, NULL, 0);
if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1)
return (errno);
if (_fstat(fd, &st) == -1) {
ret = errno;
goto error;
}
if (!S_ISREG(st.st_mode)) {
ret = EOPNOTSUPP;
goto error;
}
head = mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_FILE|MAP_PRIVATE,
fd, (off_t)0);
if (head == MAP_FAILED) {
ret = errno;
goto error;
}
_region_init(r, head, (size_t)st.st_size);
error:
(void)_close(fd);
return (ret);
}
void
_citrus_unmap_file(struct _citrus_region *r)
{
if (_region_head(r) != NULL) {
(void)munmap(_region_head(r), _region_size(r));
_region_init(r, NULL, 0);
}
}
diff --git a/lib/libc/iconv/citrus_module.c b/lib/libc/iconv/citrus_module.c
index 24ad16246be6..1d862ed6ccad 100644
--- a/lib/libc/iconv/citrus_module.c
+++ b/lib/libc/iconv/citrus_module.c
@@ -1,316 +1,315 @@
/* $NetBSD: citrus_module.c,v 1.9 2009/01/11 02:46:24 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)1999, 2000, 2001, 2002 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*-
* Copyright (c) 1998 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Paul Kranenburg.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <dirent.h>
#include <dlfcn.h>
#include <errno.h>
#include <limits.h>
#include <paths.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define I18NMODULE_MAJOR 5
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#include "citrus_module.h"
#include "libc_private.h"
static int _getdewey(int[], char *);
static int _cmpndewey(int[], int, int[], int);
static const char *_findshlib(char *, int *, int *);
static const char *_pathI18nModule = NULL;
/* from libexec/ld.aout_so/shlib.c */
#undef major
#undef minor
#define MAXDEWEY 3 /*ELF*/
static int
_getdewey(int dewey[], char *cp)
{
int i, n;
for (n = 0, i = 0; i < MAXDEWEY; i++) {
if (*cp == '\0')
break;
if (*cp == '.') cp++;
if (*cp < '0' || '9' < *cp)
return (0);
dewey[n++] = (int)_bcs_strtol(cp, &cp, 10);
}
return (n);
}
/*
* Compare two dewey arrays.
* Return -1 if `d1' represents a smaller value than `d2'.
* Return 1 if `d1' represents a greater value than `d2'.
* Return 0 if equal.
*/
static int
_cmpndewey(int d1[], int n1, int d2[], int n2)
{
int i;
for (i = 0; i < n1 && i < n2; i++) {
if (d1[i] < d2[i])
return (-1);
if (d1[i] > d2[i])
return (1);
}
if (n1 == n2)
return (0);
if (i == n1)
return (-1);
if (i == n2)
return (1);
/* cannot happen */
return (0);
}
static const char *
_findshlib(char *name, int *majorp, int *minorp)
{
char *lname;
const char *search_dirs[1];
static char path[PATH_MAX];
int dewey[MAXDEWEY], tmp[MAXDEWEY];
int i, len, major, minor, ndewey, n_search_dirs;
n_search_dirs = 1;
major = *majorp;
minor = *minorp;
path[0] = '\0';
search_dirs[0] = _pathI18nModule;
len = strlen(name);
lname = name;
ndewey = 0;
for (i = 0; i < n_search_dirs; i++) {
struct dirent *dp;
DIR *dd = opendir(search_dirs[i]);
int found_dot_a = 0, found_dot_so = 0;
if (dd == NULL)
break;
while ((dp = readdir(dd)) != NULL) {
int n;
if (dp->d_namlen < len + 4)
continue;
if (strncmp(dp->d_name, lname, (size_t)len) != 0)
continue;
if (strncmp(dp->d_name+len, ".so.", 4) != 0)
continue;
if ((n = _getdewey(tmp, dp->d_name+len+4)) == 0)
continue;
if (major != -1 && found_dot_a)
found_dot_a = 0;
/* XXX should verify the library is a.out/ELF? */
if (major == -1 && minor == -1)
goto compare_version;
else if (major != -1 && minor == -1) {
if (tmp[0] == major)
goto compare_version;
} else if (major != -1 && minor != -1) {
if (tmp[0] == major) {
if (n == 1 || tmp[1] >= minor)
goto compare_version;
}
}
/* else, this file does not qualify */
continue;
compare_version:
if (_cmpndewey(tmp, n, dewey, ndewey) <= 0)
continue;
/* We have a better version */
found_dot_so = 1;
snprintf(path, sizeof(path), "%s/%s", search_dirs[i],
dp->d_name);
found_dot_a = 0;
bcopy(tmp, dewey, sizeof(dewey));
ndewey = n;
*majorp = dewey[0];
*minorp = dewey[1];
}
closedir(dd);
if (found_dot_a || found_dot_so)
/*
* There's a lib in this dir; take it.
*/
return (path[0] ? path : NULL);
}
return (path[0] ? path : NULL);
}
void *
_citrus_find_getops(_citrus_module_t handle, const char *modname,
const char *ifname)
{
char name[PATH_MAX];
void *p;
snprintf(name, sizeof(name), "_citrus_%s_%s_getops",
modname, ifname);
p = dlsym((void *)handle, name);
return (p);
}
int
_citrus_load_module(_citrus_module_t *rhandle, const char *encname)
{
const char *p;
char path[PATH_MAX];
void *handle;
int maj, min;
if (_pathI18nModule == NULL) {
p = secure_getenv("PATH_I18NMODULE");
if (p != NULL) {
_pathI18nModule = strdup(p);
if (_pathI18nModule == NULL)
return (ENOMEM);
} else
_pathI18nModule = _PATH_I18NMODULE;
}
(void)snprintf(path, sizeof(path), "lib%s", encname);
maj = I18NMODULE_MAJOR;
min = -1;
p = _findshlib(path, &maj, &min);
if (!p)
return (EINVAL);
handle = libc_dlopen(p, RTLD_LAZY);
if (!handle) {
printf("%s", dlerror());
return (EINVAL);
}
*rhandle = (_citrus_module_t)handle;
return (0);
}
void
_citrus_unload_module(_citrus_module_t handle)
{
if (handle)
dlclose((void *)handle);
}
diff --git a/lib/libc/iconv/citrus_none.c b/lib/libc/iconv/citrus_none.c
index 3ae0a236f8f1..194d78853955 100644
--- a/lib/libc/iconv/citrus_none.c
+++ b/lib/libc/iconv/citrus_none.c
@@ -1,238 +1,237 @@
/* $NetBSD: citrus_none.c,v 1.18 2008/06/14 16:01:07 tnozaki Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Citrus Project,
* Copyright (c) 2010 Gabor Kovesdan <gabor@FreeBSD.org>,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <iconv.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_module.h"
#include "citrus_none.h"
#include "citrus_stdenc.h"
_CITRUS_STDENC_DECLS(NONE);
_CITRUS_STDENC_DEF_OPS(NONE);
struct _citrus_stdenc_traits _citrus_NONE_stdenc_traits = {
0, /* et_state_size */
1, /* mb_cur_max */
};
static int
_citrus_NONE_stdenc_init(struct _citrus_stdenc * __restrict ce,
const void *var __unused, size_t lenvar __unused,
struct _citrus_stdenc_traits * __restrict et)
{
et->et_state_size = 0;
et->et_mb_cur_max = 1;
ce->ce_closure = NULL;
return (0);
}
static void
_citrus_NONE_stdenc_uninit(struct _citrus_stdenc *ce __unused)
{
}
static int
_citrus_NONE_stdenc_init_state(struct _citrus_stdenc * __restrict ce __unused,
void * __restrict ps __unused)
{
return (0);
}
static int
_citrus_NONE_stdenc_mbtocs(struct _citrus_stdenc * __restrict ce __unused,
_csid_t *csid, _index_t *idx, char **s, size_t n,
void *ps __unused, size_t *nresult, struct iconv_hooks *hooks)
{
if (n < 1) {
*nresult = (size_t)-2;
return (0);
}
*csid = 0;
*idx = (_index_t)(unsigned char)*(*s)++;
*nresult = *idx == 0 ? 0 : 1;
if ((hooks != NULL) && (hooks->uc_hook != NULL))
hooks->uc_hook((unsigned int)*idx, hooks->data);
return (0);
}
static int
_citrus_NONE_stdenc_cstomb(struct _citrus_stdenc * __restrict ce __unused,
char *s, size_t n, _csid_t csid, _index_t idx, void *ps __unused,
size_t *nresult, struct iconv_hooks *hooks __unused)
{
if (csid == _CITRUS_CSID_INVALID) {
*nresult = 0;
return (0);
}
if (csid != 0)
return (EILSEQ);
if ((idx & 0x000000FF) == idx) {
if (n < 1) {
*nresult = (size_t)-1;
return (E2BIG);
}
*s = (char)idx;
*nresult = 1;
} else if ((idx & 0x0000FFFF) == idx) {
if (n < 2) {
*nresult = (size_t)-1;
return (E2BIG);
}
s[0] = (char)idx;
/* XXX: might be endian dependent */
s[1] = (char)(idx >> 8);
*nresult = 2;
} else if ((idx & 0x00FFFFFF) == idx) {
if (n < 3) {
*nresult = (size_t)-1;
return (E2BIG);
}
s[0] = (char)idx;
/* XXX: might be endian dependent */
s[1] = (char)(idx >> 8);
s[2] = (char)(idx >> 16);
*nresult = 3;
} else {
if (n < 4) {
*nresult = (size_t)-1;
return (E2BIG);
}
s[0] = (char)idx;
/* XXX: might be endian dependent */
s[1] = (char)(idx >> 8);
s[2] = (char)(idx >> 16);
s[3] = (char)(idx >> 24);
*nresult = 4;
}
return (0);
}
static int
_citrus_NONE_stdenc_mbtowc(struct _citrus_stdenc * __restrict ce __unused,
_wc_t * __restrict pwc, char ** __restrict s, size_t n,
void * __restrict pspriv __unused, size_t * __restrict nresult,
struct iconv_hooks *hooks)
{
if (*s == NULL) {
*nresult = 0;
return (0);
}
if (n == 0) {
*nresult = (size_t)-2;
return (0);
}
if (pwc != NULL)
*pwc = (_wc_t)(unsigned char) **s;
*nresult = **s == '\0' ? 0 : 1;
if ((hooks != NULL) && (hooks->wc_hook != NULL))
hooks->wc_hook(*pwc, hooks->data);
return (0);
}
static int
_citrus_NONE_stdenc_wctomb(struct _citrus_stdenc * __restrict ce __unused,
char * __restrict s, size_t n, _wc_t wc,
void * __restrict pspriv __unused, size_t * __restrict nresult,
struct iconv_hooks *hooks __unused)
{
if ((wc & ~0xFFU) != 0) {
*nresult = (size_t)-1;
return (EILSEQ);
}
if (n == 0) {
*nresult = (size_t)-1;
return (E2BIG);
}
*nresult = 1;
if (s != NULL && n > 0)
*s = (char)wc;
return (0);
}
static int
_citrus_NONE_stdenc_put_state_reset(struct _citrus_stdenc * __restrict ce __unused,
char * __restrict s __unused, size_t n __unused,
void * __restrict pspriv __unused, size_t * __restrict nresult)
{
*nresult = 0;
return (0);
}
static int
_citrus_NONE_stdenc_get_state_desc(struct _stdenc * __restrict ce __unused,
void * __restrict ps __unused, int id,
struct _stdenc_state_desc * __restrict d)
{
int ret = 0;
switch (id) {
case _STDENC_SDID_GENERIC:
d->u.generic.state = _STDENC_SDGEN_INITIAL;
break;
default:
ret = EOPNOTSUPP;
}
return (ret);
}
diff --git a/lib/libc/iconv/citrus_pivot_factory.c b/lib/libc/iconv/citrus_pivot_factory.c
index 8441ae3c5cdb..ed5e6863beab 100644
--- a/lib/libc/iconv/citrus_pivot_factory.c
+++ b/lib/libc/iconv/citrus_pivot_factory.c
@@ -1,226 +1,225 @@
/* $NetBSD: citrus_pivot_factory.c,v 1.7 2009/04/12 14:20:19 lukem Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/queue.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_region.h"
#include "citrus_bcs.h"
#include "citrus_db_factory.h"
#include "citrus_db_hash.h"
#include "citrus_pivot_file.h"
#include "citrus_pivot_factory.h"
struct src_entry {
char *se_name;
struct _citrus_db_factory *se_df;
STAILQ_ENTRY(src_entry) se_entry;
};
STAILQ_HEAD(src_head, src_entry);
static int
find_src(struct src_head *sh, struct src_entry **rse, const char *name)
{
int ret;
struct src_entry *se;
STAILQ_FOREACH(se, sh, se_entry) {
if (_bcs_strcasecmp(se->se_name, name) == 0) {
*rse = se;
return (0);
}
}
se = malloc(sizeof(*se));
if (se == NULL)
return (errno);
se->se_name = strdup(name);
if (se->se_name == NULL) {
ret = errno;
free(se);
return (ret);
}
ret = _db_factory_create(&se->se_df, &_db_hash_std, NULL);
if (ret) {
free(se->se_name);
free(se);
return (ret);
}
STAILQ_INSERT_TAIL(sh, se, se_entry);
*rse = se;
return (0);
}
static void
free_src(struct src_head *sh)
{
struct src_entry *se;
while ((se = STAILQ_FIRST(sh)) != NULL) {
STAILQ_REMOVE_HEAD(sh, se_entry);
_db_factory_free(se->se_df);
free(se->se_name);
free(se);
}
}
#define T_COMM '#'
static int
convert_line(struct src_head *sh, const char *line, size_t len)
{
struct src_entry *se;
const char *p;
char key1[LINE_MAX], key2[LINE_MAX], data[LINE_MAX];
char *ep;
uint32_t val;
int ret;
se = NULL;
/* cut off trailing comment */
p = memchr(line, T_COMM, len);
if (p)
len = p - line;
/* key1 */
line = _bcs_skip_ws_len(line, &len);
if (len == 0)
return (0);
p = _bcs_skip_nonws_len(line, &len);
if (p == line)
return (0);
snprintf(key1, sizeof(key1), "%.*s", (int)(p - line), line);
/* key2 */
line = _bcs_skip_ws_len(p, &len);
if (len == 0)
return (0);
p = _bcs_skip_nonws_len(line, &len);
if (p == line)
return (0);
snprintf(key2, sizeof(key2), "%.*s", (int)(p - line), line);
/* data */
line = _bcs_skip_ws_len(p, &len);
_bcs_trunc_rws_len(line, &len);
snprintf(data, sizeof(data), "%.*s", (int)len, line);
val = strtoul(data, &ep, 0);
if (*ep != '\0')
return (EFTYPE);
/* insert to DB */
ret = find_src(sh, &se, key1);
if (ret)
return (ret);
return (_db_factory_add32_by_s(se->se_df, key2, val));
}
static int
dump_db(struct src_head *sh, struct _region *r)
{
struct _db_factory *df;
struct src_entry *se;
struct _region subr;
void *ptr;
size_t size;
int ret;
ret = _db_factory_create(&df, &_db_hash_std, NULL);
if (ret)
return (ret);
STAILQ_FOREACH(se, sh, se_entry) {
size = _db_factory_calc_size(se->se_df);
ptr = malloc(size);
if (ptr == NULL)
goto quit;
_region_init(&subr, ptr, size);
ret = _db_factory_serialize(se->se_df, _CITRUS_PIVOT_SUB_MAGIC,
&subr);
if (ret)
goto quit;
ret = _db_factory_add_by_s(df, se->se_name, &subr, 1);
if (ret)
goto quit;
}
size = _db_factory_calc_size(df);
ptr = malloc(size);
if (ptr == NULL)
goto quit;
_region_init(r, ptr, size);
ret = _db_factory_serialize(df, _CITRUS_PIVOT_MAGIC, r);
ptr = NULL;
quit:
free(ptr);
_db_factory_free(df);
return (ret);
}
int
_citrus_pivot_factory_convert(FILE *out, FILE *in)
{
struct src_head sh;
struct _region r;
char *line;
size_t size;
int ret;
STAILQ_INIT(&sh);
while ((line = fgetln(in, &size)) != NULL)
if ((ret = convert_line(&sh, line, size))) {
free_src(&sh);
return (ret);
}
ret = dump_db(&sh, &r);
free_src(&sh);
if (ret)
return (ret);
if (fwrite(_region_head(&r), _region_size(&r), 1, out) != 1)
return (errno);
return (0);
}
diff --git a/lib/libc/iconv/citrus_prop.c b/lib/libc/iconv/citrus_prop.c
index 283200f10073..6dadce92e3eb 100644
--- a/lib/libc/iconv/citrus_prop.c
+++ b/lib/libc/iconv/citrus_prop.c
@@ -1,447 +1,446 @@
/* $NetBSD: citrus_prop.c,v 1.4 2011/03/30 08:22:01 jruoho Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2006 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_bcs.h"
#include "citrus_region.h"
#include "citrus_memstream.h"
#include "citrus_prop.h"
typedef struct {
_citrus_prop_type_t type;
union {
const char *str;
int chr;
bool boolean;
uint64_t num;
} u;
} _citrus_prop_object_t;
static __inline void
_citrus_prop_object_init(_citrus_prop_object_t *obj, _citrus_prop_type_t type)
{
obj->type = type;
memset(&obj->u, 0, sizeof(obj->u));
}
static __inline void
_citrus_prop_object_uninit(_citrus_prop_object_t *obj)
{
if (obj->type == _CITRUS_PROP_STR)
free(__DECONST(void *, obj->u.str));
}
static const char *xdigit = "0123456789ABCDEF";
#define _CITRUS_PROP_READ_UINT_COMMON(_func_, _type_, _max_) \
static int \
_citrus_prop_read_##_func_##_common(struct _memstream * __restrict ms, \
_type_ * __restrict result, int base, int neg) \
{ \
_type_ acc, cutoff; \
int ch, cutlim, n; \
char *p; \
\
acc = (_type_)0; \
cutoff = _max_ / base; \
cutlim = _max_ % base; \
for (;;) { \
ch = _memstream_getc(ms); \
p = strchr(xdigit, _bcs_toupper(ch)); \
if (p == NULL || (n = (p - xdigit)) >= base) \
break; \
if (acc > cutoff || (acc == cutoff && n > cutlim)) \
break; \
acc *= base; \
acc += n; \
} \
_memstream_ungetc(ms, ch); \
*result = neg ? -acc : acc; \
return (0); \
}
_CITRUS_PROP_READ_UINT_COMMON(chr, int, UCHAR_MAX)
_CITRUS_PROP_READ_UINT_COMMON(num, uint64_t, UINT64_MAX)
#undef _CITRUS_PROP_READ_UINT_COMMON
#define _CITRUS_PROP_READ_INT(_func_, _type_) \
static int \
_citrus_prop_read_##_func_(struct _memstream * __restrict ms, \
_citrus_prop_object_t * __restrict obj) \
{ \
int base, ch, neg; \
\
_memstream_skip_ws(ms); \
ch = _memstream_getc(ms); \
neg = 0; \
switch (ch) { \
case '-': \
neg = 1; \
case '+': \
ch = _memstream_getc(ms); \
} \
base = 10; \
if (ch == '0') { \
base -= 2; \
ch = _memstream_getc(ms); \
if (ch == 'x' || ch == 'X') { \
ch = _memstream_getc(ms); \
if (_bcs_isxdigit(ch) == 0) { \
_memstream_ungetc(ms, ch); \
obj->u._func_ = 0; \
return (0); \
} \
base += 8; \
} \
} else if (_bcs_isdigit(ch) == 0) \
return (EINVAL); \
_memstream_ungetc(ms, ch); \
return (_citrus_prop_read_##_func_##_common \
(ms, &obj->u._func_, base, neg)); \
}
_CITRUS_PROP_READ_INT(chr, int)
_CITRUS_PROP_READ_INT(num, uint64_t)
#undef _CITRUS_PROP_READ_INT
static int
_citrus_prop_read_character_common(struct _memstream * __restrict ms,
int * __restrict result)
{
int base, ch;
ch = _memstream_getc(ms);
if (ch != '\\')
*result = ch;
else {
ch = _memstream_getc(ms);
base = 16;
switch (ch) {
case 'a':
*result = '\a';
break;
case 'b':
*result = '\b';
break;
case 'f':
*result = '\f';
break;
case 'n':
*result = '\n';
break;
case 'r':
*result = '\r';
break;
case 't':
*result = '\t';
break;
case 'v':
*result = '\v';
break;
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
_memstream_ungetc(ms, ch);
base -= 8;
/*FALLTHROUGH*/
case 'x':
return (_citrus_prop_read_chr_common(ms, result,
base, 0));
/*NOTREACHED*/
default:
/* unknown escape */
*result = ch;
}
}
return (0);
}
static int
_citrus_prop_read_character(struct _memstream * __restrict ms,
_citrus_prop_object_t * __restrict obj)
{
int ch, errnum;
_memstream_skip_ws(ms);
ch = _memstream_getc(ms);
if (ch != '\'') {
_memstream_ungetc(ms, ch);
return (_citrus_prop_read_chr(ms, obj));
}
errnum = _citrus_prop_read_character_common(ms, &ch);
if (errnum != 0)
return (errnum);
obj->u.chr = ch;
ch = _memstream_getc(ms);
if (ch != '\'')
return (EINVAL);
return (0);
}
static int
_citrus_prop_read_bool(struct _memstream * __restrict ms,
_citrus_prop_object_t * __restrict obj)
{
_memstream_skip_ws(ms);
switch (_bcs_tolower(_memstream_getc(ms))) {
case 't':
if (_bcs_tolower(_memstream_getc(ms)) == 'r' &&
_bcs_tolower(_memstream_getc(ms)) == 'u' &&
_bcs_tolower(_memstream_getc(ms)) == 'e') {
obj->u.boolean = true;
return (0);
}
break;
case 'f':
if (_bcs_tolower(_memstream_getc(ms)) == 'a' &&
_bcs_tolower(_memstream_getc(ms)) == 'l' &&
_bcs_tolower(_memstream_getc(ms)) == 's' &&
_bcs_tolower(_memstream_getc(ms)) == 'e') {
obj->u.boolean = false;
return (0);
}
}
return (EINVAL);
}
static int
_citrus_prop_read_str(struct _memstream * __restrict ms,
_citrus_prop_object_t * __restrict obj)
{
int ch, errnum, quot;
char *s, *t;
#define _CITRUS_PROP_STR_BUFSIZ 512
size_t m, n;
m = _CITRUS_PROP_STR_BUFSIZ;
s = malloc(m);
if (s == NULL)
return (ENOMEM);
n = 0;
_memstream_skip_ws(ms);
quot = _memstream_getc(ms);
switch (quot) {
case EOF:
goto done;
/*NOTREACHED*/
case '\\':
_memstream_ungetc(ms, quot);
quot = EOF;
/*FALLTHROUGH*/
case '\"': case '\'':
break;
default:
s[n] = quot;
++n, --m;
quot = EOF;
}
for (;;) {
if (m < 1) {
m = _CITRUS_PROP_STR_BUFSIZ;
t = realloc(s, n + m);
if (t == NULL) {
free(s);
return (ENOMEM);
}
s = t;
}
ch = _memstream_getc(ms);
if (quot == ch || (quot == EOF &&
(ch == ';' || _bcs_isspace(ch)))) {
done:
s[n] = '\0';
obj->u.str = (const char *)s;
return (0);
}
_memstream_ungetc(ms, ch);
errnum = _citrus_prop_read_character_common(ms, &ch);
if (errnum != 0) {
free(s);
return (errnum);
}
s[n] = ch;
++n, --m;
}
free(s);
return (EINVAL);
#undef _CITRUS_PROP_STR_BUFSIZ
}
typedef int (*_citrus_prop_read_type_t)(struct _memstream * __restrict,
_citrus_prop_object_t * __restrict);
static const _citrus_prop_read_type_t readers[] = {
_citrus_prop_read_bool,
_citrus_prop_read_str,
_citrus_prop_read_character,
_citrus_prop_read_num,
};
static __inline int
_citrus_prop_read_symbol(struct _memstream * __restrict ms,
char * __restrict s, size_t n)
{
int ch;
size_t m;
for (m = 0; m < n; ++m) {
ch = _memstream_getc(ms);
if (ch != '_' && _bcs_isalnum(ch) == 0)
goto name_found;
s[m] = ch;
}
ch = _memstream_getc(ms);
if (ch == '_' || _bcs_isalnum(ch) != 0)
return (EINVAL);
name_found:
_memstream_ungetc(ms, ch);
s[m] = '\0';
return (0);
}
static int
_citrus_prop_parse_element(struct _memstream * __restrict ms,
const _citrus_prop_hint_t * __restrict hints, void * __restrict context)
{
int ch, errnum;
#define _CITRUS_PROP_HINT_NAME_LEN_MAX 255
char name[_CITRUS_PROP_HINT_NAME_LEN_MAX + 1];
const _citrus_prop_hint_t *hint;
_citrus_prop_object_t ostart, oend;
errnum = _citrus_prop_read_symbol(ms, name, sizeof(name));
if (errnum != 0)
return (errnum);
for (hint = hints; hint->name != NULL; ++hint)
if (_citrus_bcs_strcasecmp(name, hint->name) == 0)
goto hint_found;
return (EINVAL);
hint_found:
_memstream_skip_ws(ms);
ch = _memstream_getc(ms);
if (ch != '=' && ch != ':')
_memstream_ungetc(ms, ch);
do {
_citrus_prop_object_init(&ostart, hint->type);
_citrus_prop_object_init(&oend, hint->type);
errnum = (*readers[hint->type])(ms, &ostart);
if (errnum != 0)
return (errnum);
_memstream_skip_ws(ms);
ch = _memstream_getc(ms);
switch (hint->type) {
case _CITRUS_PROP_BOOL:
/*FALLTHROUGH*/
case _CITRUS_PROP_STR:
break;
default:
if (ch != '-')
break;
errnum = (*readers[hint->type])(ms, &oend);
if (errnum != 0)
return (errnum);
_memstream_skip_ws(ms);
ch = _memstream_getc(ms);
}
#define CALL0(_func_) \
do { \
errnum = (*hint->cb._func_.func)(context, \
hint->name, ostart.u._func_); \
} while (0)
#define CALL1(_func_) \
do { \
errnum = (*hint->cb._func_.func)(context, \
hint->name, ostart.u._func_, oend.u._func_);\
} while (0)
switch (hint->type) {
case _CITRUS_PROP_BOOL:
CALL0(boolean);
break;
case _CITRUS_PROP_STR:
CALL0(str);
break;
case _CITRUS_PROP_CHR:
CALL1(chr);
break;
case _CITRUS_PROP_NUM:
CALL1(num);
break;
default:
abort();
/*NOTREACHED*/
}
#undef CALL0
#undef CALL1
_citrus_prop_object_uninit(&ostart);
_citrus_prop_object_uninit(&oend);
if (errnum != 0)
return (errnum);
} while (ch == ',');
if (ch != ';')
_memstream_ungetc(ms, ch);
return (0);
}
int
_citrus_prop_parse_variable(const _citrus_prop_hint_t * __restrict hints,
void * __restrict context, const void *var, size_t lenvar)
{
struct _memstream ms;
int ch, errnum;
_memstream_bind_ptr(&ms, __DECONST(void *, var), lenvar);
for (;;) {
_memstream_skip_ws(&ms);
ch = _memstream_getc(&ms);
if (ch == EOF || ch == '\0')
break;
_memstream_ungetc(&ms, ch);
errnum = _citrus_prop_parse_element(&ms, hints, context);
if (errnum != 0)
return (errnum);
}
return (0);
}
diff --git a/lib/libc/iconv/citrus_stdenc.c b/lib/libc/iconv/citrus_stdenc.c
index afb472507c14..c4778132750b 100644
--- a/lib/libc/iconv/citrus_stdenc.c
+++ b/lib/libc/iconv/citrus_stdenc.c
@@ -1,148 +1,147 @@
/* $NetBSD: citrus_stdenc.c,v 1.4 2011/11/19 18:39:58 tnozaki Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c)2003 Citrus Project,
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "citrus_namespace.h"
#include "citrus_types.h"
#include "citrus_module.h"
#include "citrus_none.h"
#include "citrus_stdenc.h"
struct _citrus_stdenc _citrus_stdenc_default = {
&_citrus_NONE_stdenc_ops, /* ce_ops */
NULL, /* ce_closure */
NULL, /* ce_module */
&_citrus_NONE_stdenc_traits, /* ce_traits */
};
int
_citrus_stdenc_open(struct _citrus_stdenc * __restrict * __restrict rce,
char const * __restrict encname, const void * __restrict variable,
size_t lenvar)
{
struct _citrus_stdenc *ce;
_citrus_module_t handle;
_citrus_stdenc_getops_t getops;
int ret;
if (!strcmp(encname, _CITRUS_DEFAULT_STDENC_NAME)) {
*rce = &_citrus_stdenc_default;
return (0);
}
ce = malloc(sizeof(*ce));
if (ce == NULL) {
ret = errno;
goto bad;
}
ce->ce_ops = NULL;
ce->ce_closure = NULL;
ce->ce_module = NULL;
ce->ce_traits = NULL;
ret = _citrus_load_module(&handle, encname);
if (ret)
goto bad;
ce->ce_module = handle;
getops = (_citrus_stdenc_getops_t)_citrus_find_getops(ce->ce_module,
encname, "stdenc");
if (getops == NULL) {
ret = EINVAL;
goto bad;
}
ce->ce_ops = (struct _citrus_stdenc_ops *)malloc(sizeof(*ce->ce_ops));
if (ce->ce_ops == NULL) {
ret = errno;
goto bad;
}
ret = (*getops)(ce->ce_ops, sizeof(*ce->ce_ops));
if (ret)
goto bad;
/* validation check */
if (ce->ce_ops->eo_init == NULL ||
ce->ce_ops->eo_uninit == NULL ||
ce->ce_ops->eo_init_state == NULL ||
ce->ce_ops->eo_mbtocs == NULL ||
ce->ce_ops->eo_cstomb == NULL ||
ce->ce_ops->eo_mbtowc == NULL ||
ce->ce_ops->eo_wctomb == NULL ||
ce->ce_ops->eo_get_state_desc == NULL) {
ret = EINVAL;
goto bad;
}
/* allocate traits */
ce->ce_traits = malloc(sizeof(*ce->ce_traits));
if (ce->ce_traits == NULL) {
ret = errno;
goto bad;
}
/* init and get closure */
ret = (*ce->ce_ops->eo_init)(ce, variable, lenvar, ce->ce_traits);
if (ret)
goto bad;
*rce = ce;
return (0);
bad:
_citrus_stdenc_close(ce);
return (ret);
}
void
_citrus_stdenc_close(struct _citrus_stdenc *ce)
{
if (ce == &_citrus_stdenc_default)
return;
if (ce->ce_module) {
if (ce->ce_ops) {
if (ce->ce_closure && ce->ce_ops->eo_uninit)
(*ce->ce_ops->eo_uninit)(ce);
free(ce->ce_ops);
}
free(ce->ce_traits);
_citrus_unload_module(ce->ce_module);
}
free(ce);
}
diff --git a/lib/libc/include/errlst.h b/lib/libc/include/errlst.h
index d43b14789b86..b71d547bda81 100644
--- a/lib/libc/include/errlst.h
+++ b/lib/libc/include/errlst.h
@@ -1,45 +1,44 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef __ERRLST_H__
#define __ERRLST_H__
-#include <sys/cdefs.h>
#ifdef PIC
/* If the main executable imports these, do not use its copy from libc.so. */
extern const char *const __hidden_sys_errlist[] __hidden;
extern const int __hidden_sys_nerr __hidden;
#else
#define __hidden_sys_errlist sys_errlist
#define __hidden_sys_nerr sys_nerr
#endif
extern const char __uprefix[] __hidden;
#endif /* __ERRLST_H__ */
diff --git a/lib/libc/include/spinlock.h b/lib/libc/include/spinlock.h
index 113dfef81c3b..5dcb961a035f 100644
--- a/lib/libc/include/spinlock.h
+++ b/lib/libc/include/spinlock.h
@@ -1,65 +1,64 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Lock definitions used in both libc and libpthread.
*
*/
#ifndef _SPINLOCK_H_
#define _SPINLOCK_H_
-#include <sys/cdefs.h>
#include <sys/types.h>
/*
* Lock structure with room for debugging information.
*/
struct _spinlock {
long spare1;
long spare2;
void *thr_extra;
int spare3;
};
typedef struct _spinlock spinlock_t;
#define _SPINLOCK_INITIALIZER { 0, 0, 0, 0 }
#define _SPINUNLOCK(_lck) _spinunlock(_lck);
#define _SPINLOCK(_lck) _spinlock(_lck)
/*
* Thread function prototype definitions:
*/
__BEGIN_DECLS
long _atomic_lock(volatile long *);
void _spinlock(spinlock_t *);
void _spinunlock(spinlock_t *);
__END_DECLS
#endif /* _SPINLOCK_H_ */
diff --git a/lib/libc/inet/inet_addr.c b/lib/libc/inet/inet_addr.c
index 69199a3adf61..a0862ac4c66f 100644
--- a/lib/libc/inet/inet_addr.c
+++ b/lib/libc/inet/inet_addr.c
@@ -1,215 +1,214 @@
/*-
* SPDX-License-Identifier: (BSD-3-Clause AND ISC)
*
* Copyright (c) 1983, 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
*/
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
static const char rcsid[] = "$Id: inet_addr.c,v 1.5 2005/04/27 04:56:19 sra Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include "port_after.h"
/*%
* Ascii internet address interpretation routine.
* The value returned is in network order.
*/
in_addr_t /* XXX should be struct in_addr :( */
inet_addr(const char *cp) {
struct in_addr val;
if (inet_aton(cp, &val))
return (val.s_addr);
return (INADDR_NONE);
}
/*%
* Check whether "cp" is a valid ascii representation
* of an Internet address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
* This replaces inet_addr, the return value from which
* cannot distinguish between failure and a local broadcast address.
*/
int
inet_aton(const char *cp, struct in_addr *addr) {
u_long val;
int base, n;
char c;
u_int8_t parts[4];
u_int8_t *pp = parts;
int digit;
c = *cp;
for (;;) {
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, isdigit=decimal.
*/
if (!isdigit((unsigned char)c))
return (0);
val = 0; base = 10; digit = 0;
if (c == '0') {
c = *++cp;
if (c == 'x' || c == 'X')
base = 16, c = *++cp;
else {
base = 8;
digit = 1 ;
}
}
for (;;) {
if (isascii(c) && isdigit((unsigned char)c)) {
if (base == 8 && (c == '8' || c == '9'))
return (0);
val = (val * base) + (c - '0');
c = *++cp;
digit = 1;
} else if (base == 16 && isascii(c) &&
isxdigit((unsigned char)c)) {
val = (val << 4) |
(c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
c = *++cp;
digit = 1;
} else
break;
}
if (c == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3 || val > 0xffU)
return (0);
*pp++ = val;
c = *++cp;
} else
break;
}
/*
* Check for trailing characters.
*/
if (c != '\0' && (!isascii(c) || !isspace((unsigned char)c)))
return (0);
/*
* Did we get a valid digit?
*/
if (!digit)
return (0);
/*
* Concoct the address according to
* the number of parts specified.
*/
n = pp - parts + 1;
switch (n) {
case 1: /*%< a -- 32 bits */
break;
case 2: /*%< a.b -- 8.24 bits */
if (val > 0xffffffU)
return (0);
val |= (uint32_t)parts[0] << 24;
break;
case 3: /*%< a.b.c -- 8.8.16 bits */
if (val > 0xffffU)
return (0);
val |= ((uint32_t)parts[0] << 24) | (parts[1] << 16);
break;
case 4: /*%< a.b.c.d -- 8.8.8.8 bits */
if (val > 0xffU)
return (0);
val |= ((uint32_t)parts[0] << 24) | (parts[1] << 16) |
(parts[2] << 8);
break;
}
if (addr != NULL)
addr->s_addr = htonl(val);
return (1);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_addr
__weak_reference(__inet_addr, inet_addr);
#undef inet_aton
__weak_reference(__inet_aton, inet_aton);
/*! \file */
diff --git a/lib/libc/inet/inet_cidr_ntop.c b/lib/libc/inet/inet_cidr_ntop.c
index 45f441a163ab..a471cb4c325f 100644
--- a/lib/libc/inet/inet_cidr_ntop.c
+++ b/lib/libc/inet/inet_cidr_ntop.c
@@ -1,265 +1,264 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1998,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
static char *
inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);
static char *
inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);
/*%
* char *
* inet_cidr_ntop(af, src, bits, dst, size)
* convert network address from network to presentation format.
* "src"'s size is determined from its "af".
* return:
* pointer to dst, or NULL if an error occurred (check errno).
* note:
* 192.5.5.1/28 has a nonzero host part, which means it isn't a network
* as called for by inet_net_ntop() but it can be a host address with
* an included netmask.
* author:
* Paul Vixie (ISC), October 1998
*/
char *
inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
switch (af) {
case AF_INET:
return (inet_cidr_ntop_ipv4(src, bits, dst, size));
case AF_INET6:
return (inet_cidr_ntop_ipv6(src, bits, dst, size));
default:
errno = EAFNOSUPPORT;
return (NULL);
}
}
static int
decoct(const u_char *src, int bytes, char *dst, size_t size) {
char *odst = dst;
char *t;
int b;
for (b = 1; b <= bytes; b++) {
if (size < sizeof "255.")
return (0);
t = dst;
dst += SPRINTF((dst, "%u", *src++));
if (b != bytes) {
*dst++ = '.';
*dst = '\0';
}
size -= (size_t)(dst - t);
}
return (dst - odst);
}
/*%
* static char *
* inet_cidr_ntop_ipv4(src, bits, dst, size)
* convert IPv4 network address from network to presentation format.
* "src"'s size is determined from its "af".
* return:
* pointer to dst, or NULL if an error occurred (check errno).
* note:
* network byte order assumed. this means 192.5.5.240/28 has
* 0b11110000 in its fourth octet.
* author:
* Paul Vixie (ISC), October 1998
*/
static char *
inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
char *odst = dst;
size_t len = 4;
size_t b;
size_t bytes;
if ((bits < -1) || (bits > 32)) {
errno = EINVAL;
return (NULL);
}
/* Find number of significant bytes in address. */
if (bits == -1)
len = 4;
else
for (len = 1, b = 1 ; b < 4U; b++)
if (*(src + b))
len = b + 1;
/* Format whole octets plus nonzero trailing octets. */
bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
if (len > bytes)
bytes = len;
b = decoct(src, bytes, dst, size);
if (b == 0U)
goto emsgsize;
dst += b;
size -= b;
if (bits != -1) {
/* Format CIDR /width. */
if (size < sizeof "/32")
goto emsgsize;
dst += SPRINTF((dst, "/%u", bits));
}
return (odst);
emsgsize:
errno = EMSGSIZE;
return (NULL);
}
static char *
inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
char *tp;
struct { int base, len; } best, cur;
u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
int i;
if ((bits < -1) || (bits > 128)) {
errno = EINVAL;
return (NULL);
}
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < NS_IN6ADDRSZ; i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
best.len = 0;
cur.base = -1;
cur.len = 0;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 && (best.len == 6 ||
(best.len == 7 && words[7] != 0x0001) ||
(best.len == 5 && words[5] == 0xffff))) {
int n;
if (src[15] || bits == -1 || bits > 120)
n = 4;
else if (src[14] || bits > 112)
n = 3;
else
n = 2;
n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
if (n == 0) {
errno = EMSGSIZE;
return (NULL);
}
tp += strlen(tp);
break;
}
tp += SPRINTF((tp, "%x", words[i]));
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) ==
(NS_IN6ADDRSZ / NS_INT16SZ))
*tp++ = ':';
*tp = '\0';
if (bits != -1)
tp += SPRINTF((tp, "/%u", bits));
/*
* Check for overflow, copy, and we're done.
*/
if ((size_t)(tp - tmp) > size) {
errno = EMSGSIZE;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
/*! \file */
diff --git a/lib/libc/inet/inet_cidr_pton.c b/lib/libc/inet/inet_cidr_pton.c
index 62fada390fed..b21bc7904565 100644
--- a/lib/libc/inet/inet_cidr_pton.c
+++ b/lib/libc/inet/inet_cidr_pton.c
@@ -1,278 +1,277 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1998,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.6 2005/04/27 04:56:19 sra Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
static int inet_cidr_pton_ipv4 (const char *src, u_char *dst, int *bits,
int ipv6);
static int inet_cidr_pton_ipv6 (const char *src, u_char *dst, int *bits);
static int getbits(const char *, int ipv6);
/*%
* int
* inet_cidr_pton(af, src, dst, *bits)
* convert network address from presentation to network format.
* accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
* "dst" is assumed large enough for its "af". "bits" is set to the
* /CIDR prefix length, which can have defaults (like /32 for IPv4).
* return:
* -1 if an error occurred (inspect errno; ENOENT means bad format).
* 0 if successful conversion occurred.
* note:
* 192.5.5.1/28 has a nonzero host part, which means it isn't a network
* as called for by inet_net_pton() but it can be a host address with
* an included netmask.
* author:
* Paul Vixie (ISC), October 1998
*/
int
inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
switch (af) {
case AF_INET:
return (inet_cidr_pton_ipv4(src, dst, bits, 0));
case AF_INET6:
return (inet_cidr_pton_ipv6(src, dst, bits));
default:
errno = EAFNOSUPPORT;
return (-1);
}
}
static const char digits[] = "0123456789";
static int
inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
const u_char *odst = dst;
int n, ch, tmp, bits;
size_t size = 4;
/* Get the mantissa. */
while (ch = *src++, (isascii(ch) && isdigit(ch))) {
tmp = 0;
do {
n = strchr(digits, ch) - digits;
assert(n >= 0 && n <= 9);
tmp *= 10;
tmp += n;
if (tmp > 255)
goto enoent;
} while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
if (size-- == 0U)
goto emsgsize;
*dst++ = (u_char) tmp;
if (ch == '\0' || ch == '/')
break;
if (ch != '.')
goto enoent;
}
/* Get the prefix length if any. */
bits = -1;
if (ch == '/' && dst > odst) {
bits = getbits(src, ipv6);
if (bits == -2)
goto enoent;
} else if (ch != '\0')
goto enoent;
/* Prefix length can default to /32 only if all four octets spec'd. */
if (bits == -1) {
if (dst - odst == 4)
bits = ipv6 ? 128 : 32;
else
goto enoent;
}
/* If nothing was written to the destination, we found no address. */
if (dst == odst)
goto enoent;
/* If prefix length overspecifies mantissa, life is bad. */
if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
goto enoent;
/* Extend address to four octets. */
while (size-- > 0U)
*dst++ = 0;
*pbits = bits;
return (0);
enoent:
errno = ENOENT;
return (-1);
emsgsize:
errno = EMSGSIZE;
return (-1);
}
static int
inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
u_int val;
int bits;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
saw_xdigit = 0;
val = 0;
bits = -1;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (val > 0xffff)
return (0);
saw_xdigit = 1;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
return (0);
colonp = tp;
continue;
} else if (*src == '\0') {
return (0);
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
saw_xdigit = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
break; /*%< '\\0' was seen by inet_pton4(). */
}
if (ch == '/') {
bits = getbits(src, 1);
if (bits == -2)
goto enoent;
break;
}
goto enoent;
}
if (saw_xdigit) {
if (tp + NS_INT16SZ > endp)
goto emsgsize;
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
if (tp == endp)
goto enoent;
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
memcpy(dst, tmp, NS_IN6ADDRSZ);
*pbits = bits;
return (0);
enoent:
errno = ENOENT;
return (-1);
emsgsize:
errno = EMSGSIZE;
return (-1);
}
static int
getbits(const char *src, int ipv6) {
int bits = 0;
char *cp, ch;
if (*src == '\0') /*%< syntax */
return (-2);
do {
ch = *src++;
cp = strchr(digits, ch);
if (cp == NULL) /*%< syntax */
return (-2);
bits *= 10;
bits += cp - digits;
if (bits == 0 && *src != '\0') /*%< no leading zeros */
return (-2);
if (bits > (ipv6 ? 128 : 32)) /*%< range error */
return (-2);
} while (*src != '\0');
return (bits);
}
/*! \file */
diff --git a/lib/libc/inet/inet_lnaof.c b/lib/libc/inet/inet_lnaof.c
index b9cc926327fb..167b56dba1d3 100644
--- a/lib/libc/inet/inet_lnaof.c
+++ b/lib/libc/inet/inet_lnaof.c
@@ -1,69 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_lnaof.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "port_after.h"
/*%
* Return the local network address portion of an
* internet address; handles class a/b/c network
* number formats.
*/
in_addr_t
inet_lnaof(struct in_addr in)
{
in_addr_t i = ntohl(in.s_addr);
if (IN_CLASSA(i))
return ((i)&IN_CLASSA_HOST);
else if (IN_CLASSB(i))
return ((i)&IN_CLASSB_HOST);
else
return ((i)&IN_CLASSC_HOST);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_lnaof
__weak_reference(__inet_lnaof, inet_lnaof);
/*! \file */
diff --git a/lib/libc/inet/inet_makeaddr.c b/lib/libc/inet/inet_makeaddr.c
index 95bb7c6d4628..72e586e76001 100644
--- a/lib/libc/inet/inet_makeaddr.c
+++ b/lib/libc/inet/inet_makeaddr.c
@@ -1,72 +1,71 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_makeaddr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "port_after.h"
/*%
* Formulate an Internet address from network + host. Used in
* building addresses stored in the ifnet structure.
*/
struct in_addr
inet_makeaddr(in_addr_t net, in_addr_t host)
{
struct in_addr a;
if (net < 128U)
a.s_addr = (net << IN_CLASSA_NSHIFT) | (host & IN_CLASSA_HOST);
else if (net < 65536U)
a.s_addr = (net << IN_CLASSB_NSHIFT) | (host & IN_CLASSB_HOST);
else if (net < 16777216L)
a.s_addr = (net << IN_CLASSC_NSHIFT) | (host & IN_CLASSC_HOST);
else
a.s_addr = net | host;
a.s_addr = htonl(a.s_addr);
return (a);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_makeaddr
__weak_reference(__inet_makeaddr, inet_makeaddr);
/*! \file */
diff --git a/lib/libc/inet/inet_net_ntop.c b/lib/libc/inet/inet_net_ntop.c
index f523e460e8bb..b06a7f7d4462 100644
--- a/lib/libc/inet/inet_net_ntop.c
+++ b/lib/libc/inet/inet_net_ntop.c
@@ -1,279 +1,278 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.5 2006/06/20 02:50:14 marka Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
static char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst,
size_t size);
static char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst,
size_t size);
/*%
* char *
* inet_net_ntop(af, src, bits, dst, size)
* convert network number from network to presentation format.
* generates CIDR style result always.
* return:
* pointer to dst, or NULL if an error occurred (check errno).
* author:
* Paul Vixie (ISC), July 1996
*/
char *
inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
{
switch (af) {
case AF_INET:
return (inet_net_ntop_ipv4(src, bits, dst, size));
case AF_INET6:
return (inet_net_ntop_ipv6(src, bits, dst, size));
default:
errno = EAFNOSUPPORT;
return (NULL);
}
}
/*%
* static char *
* inet_net_ntop_ipv4(src, bits, dst, size)
* convert IPv4 network number from network to presentation format.
* generates CIDR style result always.
* return:
* pointer to dst, or NULL if an error occurred (check errno).
* note:
* network byte order assumed. this means 192.5.5.240/28 has
* 0b11110000 in its fourth octet.
* author:
* Paul Vixie (ISC), July 1996
*/
static char *
inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
{
char *odst = dst;
char *t;
u_int m;
int b;
if (bits < 0 || bits > 32) {
errno = EINVAL;
return (NULL);
}
if (bits == 0) {
if (size < sizeof "0")
goto emsgsize;
*dst++ = '0';
size--;
*dst = '\0';
}
/* Format whole octets. */
for (b = bits / 8; b > 0; b--) {
if (size <= sizeof "255.")
goto emsgsize;
t = dst;
dst += SPRINTF((dst, "%u", *src++));
if (b > 1) {
*dst++ = '.';
*dst = '\0';
}
size -= (size_t)(dst - t);
}
/* Format partial octet. */
b = bits % 8;
if (b > 0) {
if (size <= sizeof ".255")
goto emsgsize;
t = dst;
if (dst != odst)
*dst++ = '.';
m = ((1 << b) - 1) << (8 - b);
dst += SPRINTF((dst, "%u", *src & m));
size -= (size_t)(dst - t);
}
/* Format CIDR /width. */
if (size <= sizeof "/32")
goto emsgsize;
dst += SPRINTF((dst, "/%u", bits));
return (odst);
emsgsize:
errno = EMSGSIZE;
return (NULL);
}
/*%
* static char *
* inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
* convert IPv6 network number from network to presentation format.
* generates CIDR style result always. Picks the shortest representation
* unless the IP is really IPv4.
* always prints specified number of bits (bits).
* return:
* pointer to dst, or NULL if an error occurred (check errno).
* note:
* network byte order assumed. this means 192.5.5.240/28 has
* 0b11110000 in its fourth octet.
* author:
* Vadim Kogan (UCB), June 2001
* Original version (IPv4) by Paul Vixie (ISC), July 1996
*/
static char *
inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
u_int m;
int b;
int p;
int zero_s, zero_l, tmp_zero_s, tmp_zero_l;
int i;
int is_ipv4 = 0;
unsigned char inbuf[16];
char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
char *cp;
int words;
u_char *s;
if (bits < 0 || bits > 128) {
errno = EINVAL;
return (NULL);
}
cp = outbuf;
if (bits == 0) {
*cp++ = ':';
*cp++ = ':';
*cp = '\0';
} else {
/* Copy src to private buffer. Zero host part. */
p = (bits + 7) / 8;
memcpy(inbuf, src, p);
memset(inbuf + p, 0, 16 - p);
b = bits % 8;
if (b != 0) {
m = ~0 << (8 - b);
inbuf[p-1] &= m;
}
s = inbuf;
/* how many words need to be displayed in output */
words = (bits + 15) / 16;
if (words == 1)
words = 2;
/* Find the longest substring of zero's */
zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
for (i = 0; i < (words * 2); i += 2) {
if ((s[i] | s[i+1]) == 0) {
if (tmp_zero_l == 0)
tmp_zero_s = i / 2;
tmp_zero_l++;
} else {
if (tmp_zero_l && zero_l < tmp_zero_l) {
zero_s = tmp_zero_s;
zero_l = tmp_zero_l;
tmp_zero_l = 0;
}
}
}
if (tmp_zero_l && zero_l < tmp_zero_l) {
zero_s = tmp_zero_s;
zero_l = tmp_zero_l;
}
if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
is_ipv4 = 1;
/* Format whole words. */
for (p = 0; p < words; p++) {
if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
/* Time to skip some zeros */
if (p == zero_s)
*cp++ = ':';
if (p == words - 1)
*cp++ = ':';
s++;
s++;
continue;
}
if (is_ipv4 && p > 5 ) {
*cp++ = (p == 6) ? ':' : '.';
cp += SPRINTF((cp, "%u", *s++));
/* we can potentially drop the last octet */
if (p != 7 || bits > 120) {
*cp++ = '.';
cp += SPRINTF((cp, "%u", *s++));
}
} else {
if (cp != outbuf)
*cp++ = ':';
cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
s += 2;
}
}
}
/* Format CIDR /width. */
sprintf(cp, "/%u", bits);
if (strlen(outbuf) + 1 > size)
goto emsgsize;
strcpy(dst, outbuf);
return (dst);
emsgsize:
errno = EMSGSIZE;
return (NULL);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_net_ntop
__weak_reference(__inet_net_ntop, inet_net_ntop);
/*! \file */
diff --git a/lib/libc/inet/inet_net_pton.c b/lib/libc/inet/inet_net_pton.c
index 9fe41702738d..970dde8f1f35 100644
--- a/lib/libc/inet/inet_net_pton.c
+++ b/lib/libc/inet/inet_net_pton.c
@@ -1,416 +1,415 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1996, 1998, 1999, 2001, 2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_net_pton.c,v 1.10 2008/11/14 02:36:51 marka Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
/*%
* static int
* inet_net_pton_ipv4(src, dst, size)
* convert IPv4 network number from presentation to network format.
* accepts hex octets, hex strings, decimal octets, and /CIDR.
* "size" is in bytes and describes "dst".
* return:
* number of bits, either imputed classfully or specified with /CIDR,
* or -1 if some failure occurred (check errno). ENOENT means it was
* not an IPv4 network specification.
* note:
* network byte order assumed. this means 192.5.5.240/28 has
* 0b11110000 in its fourth octet.
* author:
* Paul Vixie (ISC), June 1996
*/
static int
inet_net_pton_ipv4(const char *src, u_char *dst, size_t size) {
static const char xdigits[] = "0123456789abcdef";
static const char digits[] = "0123456789";
int n, ch, tmp = 0, dirty, bits;
const u_char *odst = dst;
ch = *src++;
if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
&& isascii((unsigned char)(src[1]))
&& isxdigit((unsigned char)(src[1]))) {
/* Hexadecimal: Eat nybble string. */
if (size <= 0U)
goto emsgsize;
dirty = 0;
src++; /*%< skip x or X. */
while ((ch = *src++) != '\0' && isascii(ch) && isxdigit(ch)) {
if (isupper(ch))
ch = tolower(ch);
n = strchr(xdigits, ch) - xdigits;
assert(n >= 0 && n <= 15);
if (dirty == 0)
tmp = n;
else
tmp = (tmp << 4) | n;
if (++dirty == 2) {
if (size-- <= 0U)
goto emsgsize;
*dst++ = (u_char) tmp;
dirty = 0;
}
}
if (dirty) { /*%< Odd trailing nybble? */
if (size-- <= 0U)
goto emsgsize;
*dst++ = (u_char) (tmp << 4);
}
} else if (isascii(ch) && isdigit(ch)) {
/* Decimal: eat dotted digit string. */
for (;;) {
tmp = 0;
do {
n = strchr(digits, ch) - digits;
assert(n >= 0 && n <= 9);
tmp *= 10;
tmp += n;
if (tmp > 255)
goto enoent;
} while ((ch = *src++) != '\0' &&
isascii(ch) && isdigit(ch));
if (size-- <= 0U)
goto emsgsize;
*dst++ = (u_char) tmp;
if (ch == '\0' || ch == '/')
break;
if (ch != '.')
goto enoent;
ch = *src++;
if (!isascii(ch) || !isdigit(ch))
goto enoent;
}
} else
goto enoent;
bits = -1;
if (ch == '/' && isascii((unsigned char)(src[0])) &&
isdigit((unsigned char)(src[0])) && dst > odst) {
/* CIDR width specifier. Nothing can follow it. */
ch = *src++; /*%< Skip over the /. */
bits = 0;
do {
n = strchr(digits, ch) - digits;
assert(n >= 0 && n <= 9);
bits *= 10;
bits += n;
if (bits > 32)
goto enoent;
} while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
if (ch != '\0')
goto enoent;
}
/* Firey death and destruction unless we prefetched EOS. */
if (ch != '\0')
goto enoent;
/* If nothing was written to the destination, we found no address. */
if (dst == odst)
goto enoent;
/* If no CIDR spec was given, infer width from net class. */
if (bits == -1) {
if (*odst >= 240) /*%< Class E */
bits = 32;
else if (*odst >= 224) /*%< Class D */
bits = 8;
else if (*odst >= 192) /*%< Class C */
bits = 24;
else if (*odst >= 128) /*%< Class B */
bits = 16;
else /*%< Class A */
bits = 8;
/* If imputed mask is narrower than specified octets, widen. */
if (bits < ((dst - odst) * 8))
bits = (dst - odst) * 8;
/*
* If there are no additional bits specified for a class D
* address adjust bits to 4.
*/
if (bits == 8 && *odst == 224)
bits = 4;
}
/* Extend network to cover the actual mask. */
while (bits > ((dst - odst) * 8)) {
if (size-- <= 0U)
goto emsgsize;
*dst++ = '\0';
}
return (bits);
enoent:
errno = ENOENT;
return (-1);
emsgsize:
errno = EMSGSIZE;
return (-1);
}
static int
getbits(const char *src, int *bitsp) {
static const char digits[] = "0123456789";
int n;
int val;
char ch;
val = 0;
n = 0;
while ((ch = *src++) != '\0') {
const char *pch;
pch = strchr(digits, ch);
if (pch != NULL) {
if (n++ != 0 && val == 0) /*%< no leading zeros */
return (0);
val *= 10;
val += (pch - digits);
if (val > 128) /*%< range */
return (0);
continue;
}
return (0);
}
if (n == 0)
return (0);
*bitsp = val;
return (1);
}
static int
getv4(const char *src, u_char *dst, int *bitsp) {
static const char digits[] = "0123456789";
u_char *odst = dst;
int n;
u_int val;
char ch;
val = 0;
n = 0;
while ((ch = *src++) != '\0') {
const char *pch;
pch = strchr(digits, ch);
if (pch != NULL) {
if (n++ != 0 && val == 0) /*%< no leading zeros */
return (0);
val *= 10;
val += (pch - digits);
if (val > 255) /*%< range */
return (0);
continue;
}
if (ch == '.' || ch == '/') {
if (dst - odst > 3) /*%< too many octets? */
return (0);
*dst++ = val;
if (ch == '/')
return (getbits(src, bitsp));
val = 0;
n = 0;
continue;
}
return (0);
}
if (n == 0)
return (0);
if (dst - odst > 3) /*%< too many octets? */
return (0);
*dst++ = val;
return (1);
}
static int
inet_net_pton_ipv6(const char *src, u_char *dst, size_t size) {
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, saw_xdigit;
u_int val;
int digits;
int bits;
size_t bytes;
int words;
int ipv4;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
goto enoent;
curtok = src;
saw_xdigit = 0;
val = 0;
digits = 0;
bits = -1;
ipv4 = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (++digits > 4)
goto enoent;
saw_xdigit = 1;
continue;
}
if (ch == ':') {
curtok = src;
if (!saw_xdigit) {
if (colonp)
goto enoent;
colonp = tp;
continue;
} else if (*src == '\0')
goto enoent;
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
saw_xdigit = 0;
digits = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
getv4(curtok, tp, &bits) > 0) {
tp += NS_INADDRSZ;
saw_xdigit = 0;
ipv4 = 1;
break; /*%< '\\0' was seen by inet_pton4(). */
}
if (ch == '/' && getbits(src, &bits) > 0)
break;
goto enoent;
}
if (saw_xdigit) {
if (tp + NS_INT16SZ > endp)
goto enoent;
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (bits == -1)
bits = 128;
words = (bits + 15) / 16;
if (words < 2)
words = 2;
if (ipv4)
words = 8;
endp = tmp + 2 * words;
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
if (tp == endp)
goto enoent;
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
goto enoent;
bytes = (bits + 7) / 8;
if (bytes > size)
goto emsgsize;
memcpy(dst, tmp, bytes);
return (bits);
enoent:
errno = ENOENT;
return (-1);
emsgsize:
errno = EMSGSIZE;
return (-1);
}
/*%
* int
* inet_net_pton(af, src, dst, size)
* convert network number from presentation to network format.
* accepts hex octets, hex strings, decimal octets, and /CIDR.
* "size" is in bytes and describes "dst".
* return:
* number of bits, either imputed classfully or specified with /CIDR,
* or -1 if some failure occurred (check errno). ENOENT means it was
* not a valid network specification.
* author:
* Paul Vixie (ISC), June 1996
*/
int
inet_net_pton(int af, const char *src, void *dst, size_t size) {
switch (af) {
case AF_INET:
return (inet_net_pton_ipv4(src, dst, size));
case AF_INET6:
return (inet_net_pton_ipv6(src, dst, size));
default:
errno = EAFNOSUPPORT;
return (-1);
}
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_net_pton
__weak_reference(__inet_net_pton, inet_net_pton);
/*! \file */
diff --git a/lib/libc/inet/inet_neta.c b/lib/libc/inet/inet_neta.c
index 19facd2047de..fe3a5bc1a591 100644
--- a/lib/libc/inet/inet_neta.c
+++ b/lib/libc/inet/inet_neta.c
@@ -1,95 +1,94 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_neta.c,v 1.3 2005/04/27 04:56:20 sra Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
/*%
* char *
* inet_neta(src, dst, size)
* format an in_addr_t network number into presentation format.
* return:
* pointer to dst, or NULL if an error occurred (check errno).
* note:
* format of ``src'' is as for inet_network().
* author:
* Paul Vixie (ISC), July 1996
*/
char *
inet_neta(in_addr_t src, char *dst, size_t size)
{
char *odst = dst;
char *tp;
while (src & 0xffffffff) {
u_char b = (src & 0xff000000) >> 24;
src <<= 8;
if (b) {
if (size < sizeof "255.")
goto emsgsize;
tp = dst;
dst += SPRINTF((dst, "%u", b));
if (src != 0L) {
*dst++ = '.';
*dst = '\0';
}
size -= (size_t)(dst - tp);
}
}
if (dst == odst) {
if (size < sizeof "0.0.0.0")
goto emsgsize;
strcpy(dst, "0.0.0.0");
}
return (odst);
emsgsize:
errno = EMSGSIZE;
return (NULL);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_neta
__weak_reference(__inet_neta, inet_neta);
/*! \file */
diff --git a/lib/libc/inet/inet_netof.c b/lib/libc/inet/inet_netof.c
index 0322c6427f3b..3728797a9c13 100644
--- a/lib/libc/inet/inet_netof.c
+++ b/lib/libc/inet/inet_netof.c
@@ -1,68 +1,67 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_netof.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "port_after.h"
/*%
* Return the network number from an internet
* address; handles class a/b/c network #'s.
*/
in_addr_t
inet_netof(struct in_addr in)
{
in_addr_t i = ntohl(in.s_addr);
if (IN_CLASSA(i))
return (((i)&IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
else if (IN_CLASSB(i))
return (((i)&IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
else
return (((i)&IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_netof
__weak_reference(__inet_netof, inet_netof);
/*! \file */
diff --git a/lib/libc/inet/inet_network.c b/lib/libc/inet/inet_network.c
index 98f7e379a82c..49ddcbb87a6a 100644
--- a/lib/libc/inet/inet_network.c
+++ b/lib/libc/inet/inet_network.c
@@ -1,110 +1,109 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_network.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <ctype.h>
#include "port_after.h"
/*%
* Internet network address interpretation routine.
* The library routines call this routine to interpret
* network numbers.
*/
in_addr_t
inet_network(const char *cp)
{
in_addr_t val, base, n;
char c;
in_addr_t parts[4], *pp = parts;
int i, digit;
again:
val = 0; base = 10; digit = 0;
if (*cp == '0')
digit = 1, base = 8, cp++;
if (*cp == 'x' || *cp == 'X')
base = 16, cp++;
while ((c = *cp) != 0) {
if (isdigit((unsigned char)c)) {
if (base == 8U && (c == '8' || c == '9'))
return (INADDR_NONE);
val = (val * base) + (c - '0');
cp++;
digit = 1;
continue;
}
if (base == 16U && isxdigit((unsigned char)c)) {
val = (val << 4) +
(c + 10 - (islower((unsigned char)c) ? 'a' : 'A'));
cp++;
digit = 1;
continue;
}
break;
}
if (!digit)
return (INADDR_NONE);
if (pp >= parts + 4 || val > 0xffU)
return (INADDR_NONE);
if (*cp == '.') {
*pp++ = val, cp++;
goto again;
}
if (*cp && !isspace(*cp&0xff))
return (INADDR_NONE);
*pp++ = val;
n = pp - parts;
if (n > 4U)
return (INADDR_NONE);
for (val = 0, i = 0; i < n; i++) {
val <<= 8;
val |= parts[i] & 0xff;
}
return (val);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_network
__weak_reference(__inet_network, inet_network);
/*! \file */
diff --git a/lib/libc/inet/inet_ntoa.c b/lib/libc/inet/inet_ntoa.c
index abe160ca3ab8..4e4c55b1ac36 100644
--- a/lib/libc/inet/inet_ntoa.c
+++ b/lib/libc/inet/inet_ntoa.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: inet_ntoa.c,v 1.2 2005/04/27 04:56:21 sra Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include "port_after.h"
/*%
* Convert network-format internet address
* to base 256 d.d.d.d representation.
*/
/*const*/ char *
inet_ntoa(struct in_addr in) {
static char ret[18];
strcpy(ret, "[inet_ntoa error]");
(void) inet_ntop(AF_INET, &in, ret, sizeof ret);
return (ret);
}
char *
inet_ntoa_r(struct in_addr in, char *buf, socklen_t size)
{
(void) inet_ntop(AF_INET, &in, buf, size);
return (buf);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_ntoa
__weak_reference(__inet_ntoa, inet_ntoa);
__weak_reference(__inet_ntoa_r, inet_ntoa_r);
/*! \file */
diff --git a/lib/libc/inet/inet_ntop.c b/lib/libc/inet/inet_ntop.c
index bc73761d6728..9bb84a19d52e 100644
--- a/lib/libc/inet/inet_ntop.c
+++ b/lib/libc/inet/inet_ntop.c
@@ -1,204 +1,203 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "port_after.h"
/*%
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static const char *inet_ntop4(const u_char *src, char *dst, socklen_t size);
static const char *inet_ntop6(const u_char *src, char *dst, socklen_t size);
/* const char *
* inet_ntop(af, src, dst, size)
* convert a network format address to presentation format.
* return:
* pointer to presentation format address (`dst'), or NULL (see errno).
* author:
* Paul Vixie, 1996.
*/
const char *
inet_ntop(int af, const void * __restrict src, char * __restrict dst,
socklen_t size)
{
switch (af) {
case AF_INET:
return (inet_ntop4(src, dst, size));
case AF_INET6:
return (inet_ntop6(src, dst, size));
default:
errno = EAFNOSUPPORT;
return (NULL);
}
/* NOTREACHED */
}
/* const char *
* inet_ntop4(src, dst, size)
* format an IPv4 address
* return:
* `dst' (as a const)
* notes:
* (1) uses no statics
* (2) takes a u_char* not an in_addr as input
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop4(const u_char *src, char *dst, socklen_t size)
{
static const char fmt[] = "%u.%u.%u.%u";
char tmp[sizeof "255.255.255.255"];
int l;
l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
if (l <= 0 || (socklen_t) l >= size) {
errno = ENOSPC;
return (NULL);
}
strlcpy(dst, tmp, size);
return (dst);
}
/* const char *
* inet_ntop6(src, dst, size)
* convert IPv6 binary address into presentation (printable) format
* author:
* Paul Vixie, 1996.
*/
static const char *
inet_ntop6(const u_char *src, char *dst, socklen_t size)
{
/*
* Note that int32_t and int16_t need only be "at least" large enough
* to contain a value of the specified size. On some systems, like
* Crays, there is no such thing as an integer variable with 16 bits.
* Keep this in mind if you think this function should have been coded
* to use pointer overlays. All the world's not a VAX.
*/
char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
struct { int base, len; } best, cur;
u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
int i;
/*
* Preprocess:
* Copy the input (bytewise) array into a wordwise array.
* Find the longest run of 0x00's in src[] for :: shorthanding.
*/
memset(words, '\0', sizeof words);
for (i = 0; i < NS_IN6ADDRSZ; i++)
words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
best.base = -1;
best.len = 0;
cur.base = -1;
cur.len = 0;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
if (words[i] == 0) {
if (cur.base == -1)
cur.base = i, cur.len = 1;
else
cur.len++;
} else {
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
cur.base = -1;
}
}
}
if (cur.base != -1) {
if (best.base == -1 || cur.len > best.len)
best = cur;
}
if (best.base != -1 && best.len < 2)
best.base = -1;
/*
* Format the result.
*/
tp = tmp;
for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
/* Are we inside the best run of 0x00's? */
if (best.base != -1 && i >= best.base &&
i < (best.base + best.len)) {
if (i == best.base)
*tp++ = ':';
continue;
}
/* Are we following an initial run of 0x00s or any real hex? */
if (i != 0)
*tp++ = ':';
/* Is this address an encapsulated IPv4? */
if (i == 6 && best.base == 0 && (best.len == 6 ||
(best.len == 7 && words[7] != 0x0001) ||
(best.len == 5 && words[5] == 0xffff))) {
if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) {
errno = ENOSPC;
return (NULL);
}
tp += strlen(tp);
break;
}
tp += sprintf(tp, "%x", words[i]);
}
/* Was it a trailing run of 0x00's? */
if (best.base != -1 && (best.base + best.len) ==
(NS_IN6ADDRSZ / NS_INT16SZ))
*tp++ = ':';
*tp++ = '\0';
/*
* Check for overflow, copy, and we're done.
*/
if ((socklen_t)(tp - tmp) > size) {
errno = ENOSPC;
return (NULL);
}
strcpy(dst, tmp);
return (dst);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_ntop
__weak_reference(__inet_ntop, inet_ntop);
/*! \file */
diff --git a/lib/libc/inet/inet_pton.c b/lib/libc/inet/inet_pton.c
index 53776f15e92e..52c86c68f7ee 100644
--- a/lib/libc/inet/inet_pton.c
+++ b/lib/libc/inet/inet_pton.c
@@ -1,224 +1,223 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <string.h>
#include <errno.h>
#include "port_after.h"
/*%
* WARNING: Don't even consider trying to compile this on a system where
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static int inet_pton4(const char *src, u_char *dst);
static int inet_pton6(const char *src, u_char *dst);
/* int
* inet_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
* 0 if the address wasn't valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* author:
* Paul Vixie, 1996.
*/
int
inet_pton(int af, const char * __restrict src, void * __restrict dst)
{
switch (af) {
case AF_INET:
return (inet_pton4(src, dst));
case AF_INET6:
return (inet_pton6(src, dst));
default:
errno = EAFNOSUPPORT;
return (-1);
}
/* NOTREACHED */
}
/* int
* inet_pton4(src, dst)
* like inet_aton() but without all the hexadecimal and shorthand.
* return:
* 1 if `src' is a valid dotted quad, else 0.
* notice:
* does not touch `dst' unless it's returning 1.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton4(const char *src, u_char *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
u_char tmp[NS_INADDRSZ], *tp;
saw_digit = 0;
octets = 0;
*(tp = tmp) = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr(digits, ch)) != NULL) {
u_int new = *tp * 10 + (pch - digits);
if (saw_digit && *tp == 0)
return (0);
if (new > 255)
return (0);
*tp = new;
if (!saw_digit) {
if (++octets > 4)
return (0);
saw_digit = 1;
}
} else if (ch == '.' && saw_digit) {
if (octets == 4)
return (0);
*++tp = 0;
saw_digit = 0;
} else
return (0);
}
if (octets < 4)
return (0);
memcpy(dst, tmp, NS_INADDRSZ);
return (1);
}
/* int
* inet_pton6(src, dst)
* convert presentation level address to network order binary form.
* return:
* 1 if `src' is a valid [RFC1884 2.2] address, else 0.
* notice:
* (1) does not touch `dst' unless it's returning 1.
* (2) :: in a full address is silently ignored.
* credit:
* inspired by Mark Andrews.
* author:
* Paul Vixie, 1996.
*/
static int
inet_pton6(const char *src, u_char *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
const char *xdigits, *curtok;
int ch, seen_xdigits;
u_int val;
memset((tp = tmp), '\0', NS_IN6ADDRSZ);
endp = tp + NS_IN6ADDRSZ;
colonp = NULL;
/* Leading :: requires some special handling. */
if (*src == ':')
if (*++src != ':')
return (0);
curtok = src;
seen_xdigits = 0;
val = 0;
while ((ch = *src++) != '\0') {
const char *pch;
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
pch = strchr((xdigits = xdigits_u), ch);
if (pch != NULL) {
val <<= 4;
val |= (pch - xdigits);
if (++seen_xdigits > 4)
return (0);
continue;
}
if (ch == ':') {
curtok = src;
if (!seen_xdigits) {
if (colonp)
return (0);
colonp = tp;
continue;
} else if (*src == '\0') {
return (0);
}
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
seen_xdigits = 0;
val = 0;
continue;
}
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
inet_pton4(curtok, tp) > 0) {
tp += NS_INADDRSZ;
seen_xdigits = 0;
break; /*%< '\\0' was seen by inet_pton4(). */
}
return (0);
}
if (seen_xdigits) {
if (tp + NS_INT16SZ > endp)
return (0);
*tp++ = (u_char) (val >> 8) & 0xff;
*tp++ = (u_char) val & 0xff;
}
if (colonp != NULL) {
/*
* Since some memmove()'s erroneously fail to handle
* overlapping regions, we'll do the shift by hand.
*/
const int n = tp - colonp;
int i;
if (tp == endp)
return (0);
for (i = 1; i <= n; i++) {
endp[- i] = colonp[n - i];
colonp[n - i] = 0;
}
tp = endp;
}
if (tp != endp)
return (0);
memcpy(dst, tmp, NS_IN6ADDRSZ);
return (1);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_pton
__weak_reference(__inet_pton, inet_pton);
/*! \file */
diff --git a/lib/libc/inet/nsap_addr.c b/lib/libc/inet/nsap_addr.c
index c3f0a4362277..3fdcab248d19 100644
--- a/lib/libc/inet/nsap_addr.c
+++ b/lib/libc/inet/nsap_addr.c
@@ -1,121 +1,120 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: nsap_addr.c,v 1.5 2005/07/28 06:51:48 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <resolv.h>
#include <resolv_mt.h>
#include "port_after.h"
static char
xtob(int c) {
return (c - (((c >= '0') && (c <= '9')) ? '0' : '7'));
}
u_int
inet_nsap_addr(const char *ascii, u_char *binary, int maxlen) {
u_char c, nib;
u_int len = 0;
if (ascii[0] != '0' || (ascii[1] != 'x' && ascii[1] != 'X'))
return (0);
ascii += 2;
while ((c = *ascii++) != '\0' && len < (u_int)maxlen) {
if (c == '.' || c == '+' || c == '/')
continue;
if (!isascii(c))
return (0);
if (islower(c))
c = toupper(c);
if (isxdigit(c)) {
nib = xtob(c);
c = *ascii++;
if (c != '\0') {
c = toupper(c);
if (isxdigit(c)) {
*binary++ = (nib << 4) | xtob(c);
len++;
} else
return (0);
}
else
return (0);
}
else
return (0);
}
return (len);
}
char *
inet_nsap_ntoa(int binlen, const u_char *binary, char *ascii) {
int nib;
int i;
char *tmpbuf = inet_nsap_ntoa_tmpbuf;
char *start;
if (ascii)
start = ascii;
else {
ascii = tmpbuf;
start = tmpbuf;
}
*ascii++ = '0';
*ascii++ = 'x';
if (binlen > 255)
binlen = 255;
for (i = 0; i < binlen; i++) {
nib = *binary >> 4;
*ascii++ = nib + (nib < 10 ? '0' : '7');
nib = *binary++ & 0x0f;
*ascii++ = nib + (nib < 10 ? '0' : '7');
if (((i % 2) == 0 && (i + 1) < binlen))
*ascii++ = '.';
}
*ascii = '\0';
return (start);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <arpa/inet.h>.
*/
#undef inet_nsap_addr
__weak_reference(__inet_nsap_addr, inet_nsap_addr);
#undef inet_nsap_ntoa
__weak_reference(__inet_nsap_ntoa, inet_nsap_ntoa);
/*! \file */
diff --git a/lib/libc/isc/ev_streams.c b/lib/libc/isc/ev_streams.c
index 254005738226..b145a06413e1 100644
--- a/lib/libc/isc/ev_streams.c
+++ b/lib/libc/isc/ev_streams.c
@@ -1,318 +1,317 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/* ev_streams.c - implement asynch stream file IO for the eventlib
* vix 04mar96 [initial]
*/
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: ev_streams.c,v 1.5 2005/04/27 04:56:36 sra Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#ifndef _LIBC
#include "fd_setsize.h"
#endif
#include <sys/types.h>
#include <sys/uio.h>
#include <errno.h>
#include <isc/eventlib.h>
#ifndef _LIBC
#include <isc/assertions.h>
#endif
#include "eventlib_p.h"
#include "port_after.h"
#ifndef _LIBC
static int copyvec(evStream *str, const struct iovec *iov, int iocnt);
static void consume(evStream *str, size_t bytes);
static void done(evContext opaqueCtx, evStream *str);
static void writable(evContext opaqueCtx, void *uap, int fd, int evmask);
static void readable(evContext opaqueCtx, void *uap, int fd, int evmask);
#endif
struct iovec
evConsIovec(void *buf, size_t cnt) {
struct iovec ret;
memset(&ret, 0xf5, sizeof ret);
ret.iov_base = buf;
ret.iov_len = cnt;
return (ret);
}
#ifndef _LIBC
int
evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
evStreamFunc func, void *uap, evStreamID *id)
{
evContext_p *ctx = opaqueCtx.opaque;
evStream *new;
int save;
OKNEW(new);
new->func = func;
new->uap = uap;
new->fd = fd;
new->flags = 0;
if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
goto free;
if (copyvec(new, iov, iocnt) < 0)
goto free;
new->prevDone = NULL;
new->nextDone = NULL;
if (ctx->streams != NULL)
ctx->streams->prev = new;
new->prev = NULL;
new->next = ctx->streams;
ctx->streams = new;
if (id != NULL)
id->opaque = new;
return (0);
free:
save = errno;
FREE(new);
errno = save;
return (-1);
}
int
evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
evStreamFunc func, void *uap, evStreamID *id)
{
evContext_p *ctx = opaqueCtx.opaque;
evStream *new;
int save;
OKNEW(new);
new->func = func;
new->uap = uap;
new->fd = fd;
new->flags = 0;
if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
goto free;
if (copyvec(new, iov, iocnt) < 0)
goto free;
new->prevDone = NULL;
new->nextDone = NULL;
if (ctx->streams != NULL)
ctx->streams->prev = new;
new->prev = NULL;
new->next = ctx->streams;
ctx->streams = new;
if (id)
id->opaque = new;
return (0);
free:
save = errno;
FREE(new);
errno = save;
return (-1);
}
int
evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
evStream *str = id.opaque;
UNUSED(opaqueCtx);
str->timer = timer;
str->flags |= EV_STR_TIMEROK;
return (0);
}
int
evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
evStream *str = id.opaque;
UNUSED(opaqueCtx);
str->flags &= ~EV_STR_TIMEROK;
return (0);
}
int
evCancelRW(evContext opaqueCtx, evStreamID id) {
evContext_p *ctx = opaqueCtx.opaque;
evStream *old = id.opaque;
/*
* The streams list is doubly threaded. First, there's ctx->streams
* that's used by evDestroy() to find and cancel all streams. Second,
* there's ctx->strDone (head) and ctx->strLast (tail) which thread
* through the potentially smaller number of "IO completed" streams,
* used in evGetNext() to avoid scanning the entire list.
*/
/* Unlink from ctx->streams. */
if (old->prev != NULL)
old->prev->next = old->next;
else
ctx->streams = old->next;
if (old->next != NULL)
old->next->prev = old->prev;
/*
* If 'old' is on the ctx->strDone list, remove it. Update
* ctx->strLast if necessary.
*/
if (old->prevDone == NULL && old->nextDone == NULL) {
/*
* Either 'old' is the only item on the done list, or it's
* not on the done list. If the former, then we unlink it
* from the list. If the latter, we leave the list alone.
*/
if (ctx->strDone == old) {
ctx->strDone = NULL;
ctx->strLast = NULL;
}
} else {
if (old->prevDone != NULL)
old->prevDone->nextDone = old->nextDone;
else
ctx->strDone = old->nextDone;
if (old->nextDone != NULL)
old->nextDone->prevDone = old->prevDone;
else
ctx->strLast = old->prevDone;
}
/* Deallocate the stream. */
if (old->file.opaque)
evDeselectFD(opaqueCtx, old->file);
memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
FREE(old);
return (0);
}
/* Copy a scatter/gather vector and initialize a stream handler's IO. */
static int
copyvec(evStream *str, const struct iovec *iov, int iocnt) {
int i;
str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
if (str->iovOrig == NULL) {
errno = ENOMEM;
return (-1);
}
str->ioTotal = 0;
for (i = 0; i < iocnt; i++) {
str->iovOrig[i] = iov[i];
str->ioTotal += iov[i].iov_len;
}
str->iovOrigCount = iocnt;
str->iovCur = str->iovOrig;
str->iovCurCount = str->iovOrigCount;
str->ioDone = 0;
return (0);
}
/* Pull off or truncate lead iovec(s). */
static void
consume(evStream *str, size_t bytes) {
while (bytes > 0U) {
if (bytes < (size_t)str->iovCur->iov_len) {
str->iovCur->iov_len -= bytes;
str->iovCur->iov_base = (void *)
((u_char *)str->iovCur->iov_base + bytes);
str->ioDone += bytes;
bytes = 0;
} else {
bytes -= str->iovCur->iov_len;
str->ioDone += str->iovCur->iov_len;
str->iovCur++;
str->iovCurCount--;
}
}
}
/* Add a stream to Done list and deselect the FD. */
static void
done(evContext opaqueCtx, evStream *str) {
evContext_p *ctx = opaqueCtx.opaque;
if (ctx->strLast != NULL) {
str->prevDone = ctx->strLast;
ctx->strLast->nextDone = str;
ctx->strLast = str;
} else {
INSIST(ctx->strDone == NULL);
ctx->strDone = ctx->strLast = str;
}
evDeselectFD(opaqueCtx, str->file);
str->file.opaque = NULL;
/* evDrop() will call evCancelRW() on us. */
}
/* Dribble out some bytes on the stream. (Called by evDispatch().) */
static void
writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
evStream *str = uap;
int bytes;
UNUSED(evmask);
bytes = writev(fd, str->iovCur, str->iovCurCount);
if (bytes > 0) {
if ((str->flags & EV_STR_TIMEROK) != 0)
evTouchIdleTimer(opaqueCtx, str->timer);
consume(str, bytes);
} else {
if (bytes < 0 && errno != EINTR) {
str->ioDone = -1;
str->ioErrno = errno;
}
}
if (str->ioDone == -1 || str->ioDone == str->ioTotal)
done(opaqueCtx, str);
}
/* Scoop up some bytes from the stream. (Called by evDispatch().) */
static void
readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
evStream *str = uap;
int bytes;
UNUSED(evmask);
bytes = readv(fd, str->iovCur, str->iovCurCount);
if (bytes > 0) {
if ((str->flags & EV_STR_TIMEROK) != 0)
evTouchIdleTimer(opaqueCtx, str->timer);
consume(str, bytes);
} else {
if (bytes == 0)
str->ioDone = 0;
else {
if (errno != EINTR) {
str->ioDone = -1;
str->ioErrno = errno;
}
}
}
if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
done(opaqueCtx, str);
}
#endif
/*! \file */
diff --git a/lib/libc/isc/ev_timers.c b/lib/libc/isc/ev_timers.c
index 4dcc8f05bc3a..60b222a36a27 100644
--- a/lib/libc/isc/ev_timers.c
+++ b/lib/libc/isc/ev_timers.c
@@ -1,515 +1,514 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-1999 by Internet Software Consortium
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/* ev_timers.c - implement timers for the eventlib
* vix 09sep95 [initial]
*/
#if !defined(LINT) && !defined(CODECENTER)
static const char rcsid[] = "$Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp $";
#endif
-#include <sys/cdefs.h>
/* Import. */
#include "port_before.h"
#ifndef _LIBC
#include "fd_setsize.h"
#endif
#include <errno.h>
#ifndef _LIBC
#include <isc/assertions.h>
#endif
#include <isc/eventlib.h>
#include "eventlib_p.h"
#include "port_after.h"
/* Constants. */
#define MILLION 1000000
#define BILLION 1000000000
/* Forward. */
#ifdef _LIBC
static int __evOptMonoTime;
#else
static int due_sooner(void *, void *);
static void set_index(void *, int);
static void free_timer(void *, void *);
static void print_timer(void *, void *);
static void idle_timeout(evContext, void *, struct timespec, struct timespec);
/* Private type. */
typedef struct {
evTimerFunc func;
void * uap;
struct timespec lastTouched;
struct timespec max_idle;
evTimer * timer;
} idle_timer;
#endif
/* Public. */
struct timespec
evConsTime(time_t sec, long nsec) {
struct timespec x;
x.tv_sec = sec;
x.tv_nsec = nsec;
return (x);
}
struct timespec
evAddTime(struct timespec addend1, struct timespec addend2) {
struct timespec x;
x.tv_sec = addend1.tv_sec + addend2.tv_sec;
x.tv_nsec = addend1.tv_nsec + addend2.tv_nsec;
if (x.tv_nsec >= BILLION) {
x.tv_sec++;
x.tv_nsec -= BILLION;
}
return (x);
}
struct timespec
evSubTime(struct timespec minuend, struct timespec subtrahend) {
struct timespec x;
x.tv_sec = minuend.tv_sec - subtrahend.tv_sec;
if (minuend.tv_nsec >= subtrahend.tv_nsec)
x.tv_nsec = minuend.tv_nsec - subtrahend.tv_nsec;
else {
x.tv_nsec = BILLION - subtrahend.tv_nsec + minuend.tv_nsec;
x.tv_sec--;
}
return (x);
}
int
evCmpTime(struct timespec a, struct timespec b) {
long x = a.tv_sec - b.tv_sec;
if (x == 0L)
x = a.tv_nsec - b.tv_nsec;
return (x < 0L ? (-1) : x > 0L ? (1) : (0));
}
struct timespec
evNowTime(void) {
struct timeval now;
#ifdef CLOCK_REALTIME
struct timespec tsnow;
int m = CLOCK_REALTIME;
#ifdef CLOCK_MONOTONIC
if (__evOptMonoTime)
m = CLOCK_MONOTONIC;
#endif
if (clock_gettime(m, &tsnow) == 0)
return (tsnow);
#endif
if (gettimeofday(&now, NULL) < 0)
return (evConsTime(0, 0));
return (evTimeSpec(now));
}
struct timespec
evUTCTime(void) {
struct timeval now;
#ifdef CLOCK_REALTIME
struct timespec tsnow;
if (clock_gettime(CLOCK_REALTIME, &tsnow) == 0)
return (tsnow);
#endif
if (gettimeofday(&now, NULL) < 0)
return (evConsTime(0, 0));
return (evTimeSpec(now));
}
#ifndef _LIBC
struct timespec
evLastEventTime(evContext opaqueCtx) {
evContext_p *ctx = opaqueCtx.opaque;
return (ctx->lastEventTime);
}
#endif
struct timespec
evTimeSpec(struct timeval tv) {
struct timespec ts;
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000;
return (ts);
}
#if !defined(USE_KQUEUE) || !defined(_LIBC)
struct timeval
evTimeVal(struct timespec ts) {
struct timeval tv;
tv.tv_sec = ts.tv_sec;
tv.tv_usec = ts.tv_nsec / 1000;
return (tv);
}
#endif
#ifndef _LIBC
int
evSetTimer(evContext opaqueCtx,
evTimerFunc func,
void *uap,
struct timespec due,
struct timespec inter,
evTimerID *opaqueID
) {
evContext_p *ctx = opaqueCtx.opaque;
evTimer *id;
evPrintf(ctx, 1,
"evSetTimer(ctx %p, func %p, uap %p, due %ld.%09ld, inter %ld.%09ld)\n",
ctx, func, uap,
(long)due.tv_sec, due.tv_nsec,
(long)inter.tv_sec, inter.tv_nsec);
#ifdef __hpux
/*
* tv_sec and tv_nsec are unsigned.
*/
if (due.tv_nsec >= BILLION)
EV_ERR(EINVAL);
if (inter.tv_nsec >= BILLION)
EV_ERR(EINVAL);
#else
if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
EV_ERR(EINVAL);
if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
EV_ERR(EINVAL);
#endif
/* due={0,0} is a magic cookie meaning "now." */
if (due.tv_sec == (time_t)0 && due.tv_nsec == 0L)
due = evNowTime();
/* Allocate and fill. */
OKNEW(id);
id->func = func;
id->uap = uap;
id->due = due;
id->inter = inter;
if (heap_insert(ctx->timers, id) < 0)
return (-1);
/* Remember the ID if the caller provided us a place for it. */
if (opaqueID)
opaqueID->opaque = id;
if (ctx->debug > 7) {
evPrintf(ctx, 7, "timers after evSetTimer:\n");
(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
}
return (0);
}
int
evClearTimer(evContext opaqueCtx, evTimerID id) {
evContext_p *ctx = opaqueCtx.opaque;
evTimer *del = id.opaque;
if (ctx->cur != NULL &&
ctx->cur->type == Timer &&
ctx->cur->u.timer.this == del) {
evPrintf(ctx, 8, "deferring delete of timer (executing)\n");
/*
* Setting the interval to zero ensures that evDrop() will
* clean up the timer.
*/
del->inter = evConsTime(0, 0);
return (0);
}
if (heap_element(ctx->timers, del->index) != del)
EV_ERR(ENOENT);
if (heap_delete(ctx->timers, del->index) < 0)
return (-1);
FREE(del);
if (ctx->debug > 7) {
evPrintf(ctx, 7, "timers after evClearTimer:\n");
(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
}
return (0);
}
int
evConfigTimer(evContext opaqueCtx,
evTimerID id,
const char *param,
int value
) {
evContext_p *ctx = opaqueCtx.opaque;
evTimer *timer = id.opaque;
int result=0;
UNUSED(value);
if (heap_element(ctx->timers, timer->index) != timer)
EV_ERR(ENOENT);
if (strcmp(param, "rate") == 0)
timer->mode |= EV_TMR_RATE;
else if (strcmp(param, "interval") == 0)
timer->mode &= ~EV_TMR_RATE;
else
EV_ERR(EINVAL);
return (result);
}
int
evResetTimer(evContext opaqueCtx,
evTimerID id,
evTimerFunc func,
void *uap,
struct timespec due,
struct timespec inter
) {
evContext_p *ctx = opaqueCtx.opaque;
evTimer *timer = id.opaque;
struct timespec old_due;
int result=0;
if (heap_element(ctx->timers, timer->index) != timer)
EV_ERR(ENOENT);
#ifdef __hpux
/*
* tv_sec and tv_nsec are unsigned.
*/
if (due.tv_nsec >= BILLION)
EV_ERR(EINVAL);
if (inter.tv_nsec >= BILLION)
EV_ERR(EINVAL);
#else
if (due.tv_sec < 0 || due.tv_nsec < 0 || due.tv_nsec >= BILLION)
EV_ERR(EINVAL);
if (inter.tv_sec < 0 || inter.tv_nsec < 0 || inter.tv_nsec >= BILLION)
EV_ERR(EINVAL);
#endif
old_due = timer->due;
timer->func = func;
timer->uap = uap;
timer->due = due;
timer->inter = inter;
switch (evCmpTime(due, old_due)) {
case -1:
result = heap_increased(ctx->timers, timer->index);
break;
case 0:
result = 0;
break;
case 1:
result = heap_decreased(ctx->timers, timer->index);
break;
}
if (ctx->debug > 7) {
evPrintf(ctx, 7, "timers after evResetTimer:\n");
(void) heap_for_each(ctx->timers, print_timer, (void *)ctx);
}
return (result);
}
int
evSetIdleTimer(evContext opaqueCtx,
evTimerFunc func,
void *uap,
struct timespec max_idle,
evTimerID *opaqueID
) {
evContext_p *ctx = opaqueCtx.opaque;
idle_timer *tt;
/* Allocate and fill. */
OKNEW(tt);
tt->func = func;
tt->uap = uap;
tt->lastTouched = ctx->lastEventTime;
tt->max_idle = max_idle;
if (evSetTimer(opaqueCtx, idle_timeout, tt,
evAddTime(ctx->lastEventTime, max_idle),
max_idle, opaqueID) < 0) {
FREE(tt);
return (-1);
}
tt->timer = opaqueID->opaque;
return (0);
}
int
evClearIdleTimer(evContext opaqueCtx, evTimerID id) {
evTimer *del = id.opaque;
idle_timer *tt = del->uap;
FREE(tt);
return (evClearTimer(opaqueCtx, id));
}
int
evResetIdleTimer(evContext opaqueCtx,
evTimerID opaqueID,
evTimerFunc func,
void *uap,
struct timespec max_idle
) {
evContext_p *ctx = opaqueCtx.opaque;
evTimer *timer = opaqueID.opaque;
idle_timer *tt = timer->uap;
tt->func = func;
tt->uap = uap;
tt->lastTouched = ctx->lastEventTime;
tt->max_idle = max_idle;
return (evResetTimer(opaqueCtx, opaqueID, idle_timeout, tt,
evAddTime(ctx->lastEventTime, max_idle),
max_idle));
}
int
evTouchIdleTimer(evContext opaqueCtx, evTimerID id) {
evContext_p *ctx = opaqueCtx.opaque;
evTimer *t = id.opaque;
idle_timer *tt = t->uap;
tt->lastTouched = ctx->lastEventTime;
return (0);
}
/* Public to the rest of eventlib. */
heap_context
evCreateTimers(const evContext_p *ctx) {
UNUSED(ctx);
return (heap_new(due_sooner, set_index, 2048));
}
void
evDestroyTimers(const evContext_p *ctx) {
(void) heap_for_each(ctx->timers, free_timer, NULL);
(void) heap_free(ctx->timers);
}
/* Private. */
static int
due_sooner(void *a, void *b) {
evTimer *a_timer, *b_timer;
a_timer = a;
b_timer = b;
return (evCmpTime(a_timer->due, b_timer->due) < 0);
}
static void
set_index(void *what, int index) {
evTimer *timer;
timer = what;
timer->index = index;
}
static void
free_timer(void *what, void *uap) {
evTimer *t = what;
UNUSED(uap);
FREE(t);
}
static void
print_timer(void *what, void *uap) {
evTimer *cur = what;
evContext_p *ctx = uap;
cur = what;
evPrintf(ctx, 7,
" func %p, uap %p, due %ld.%09ld, inter %ld.%09ld\n",
cur->func, cur->uap,
(long)cur->due.tv_sec, cur->due.tv_nsec,
(long)cur->inter.tv_sec, cur->inter.tv_nsec);
}
static void
idle_timeout(evContext opaqueCtx,
void *uap,
struct timespec due,
struct timespec inter
) {
evContext_p *ctx = opaqueCtx.opaque;
idle_timer *this = uap;
struct timespec idle;
UNUSED(due);
UNUSED(inter);
idle = evSubTime(ctx->lastEventTime, this->lastTouched);
if (evCmpTime(idle, this->max_idle) >= 0) {
(this->func)(opaqueCtx, this->uap, this->timer->due,
this->max_idle);
/*
* Setting the interval to zero will cause the timer to
* be cleaned up in evDrop().
*/
this->timer->inter = evConsTime(0, 0);
FREE(this);
} else {
/* evDrop() will reschedule the timer. */
this->timer->inter = evSubTime(this->max_idle, idle);
}
}
#endif
/*! \file */
diff --git a/lib/libc/locale/ascii.c b/lib/libc/locale/ascii.c
index 55761626d67b..2afbcea9cab9 100644
--- a/lib/libc/locale/ascii.c
+++ b/lib/libc/locale/ascii.c
@@ -1,194 +1,193 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <runetype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
static size_t _ascii_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _ascii_mbsinit(const mbstate_t *);
static size_t _ascii_mbsnrtowcs(wchar_t * __restrict dst,
const char ** __restrict src, size_t nms, size_t len,
mbstate_t * __restrict ps __unused);
static size_t _ascii_wcrtomb(char * __restrict, wchar_t,
mbstate_t * __restrict);
static size_t _ascii_wcsnrtombs(char * __restrict, const wchar_t ** __restrict,
size_t, size_t, mbstate_t * __restrict);
int
_ascii_init(struct xlocale_ctype *l,_RuneLocale *rl)
{
l->__mbrtowc = _ascii_mbrtowc;
l->__mbsinit = _ascii_mbsinit;
l->__mbsnrtowcs = _ascii_mbsnrtowcs;
l->__wcrtomb = _ascii_wcrtomb;
l->__wcsnrtombs = _ascii_wcsnrtombs;
l->runes = rl;
l->__mb_cur_max = 1;
l->__mb_sb_limit = 128;
return(0);
}
static int
_ascii_mbsinit(const mbstate_t *ps __unused)
{
/*
* Encoding is not state dependent - we are always in the
* initial state.
*/
return (1);
}
static size_t
_ascii_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
mbstate_t * __restrict ps __unused)
{
if (s == NULL)
/* Reset to initial shift state (no-op) */
return (0);
if (n == 0)
/* Incomplete multibyte sequence */
return ((size_t)-2);
if (*s & 0x80) {
errno = EILSEQ;
return ((size_t)-1);
}
if (pwc != NULL)
*pwc = (unsigned char)*s;
return (*s == '\0' ? 0 : 1);
}
static size_t
_ascii_wcrtomb(char * __restrict s, wchar_t wc,
mbstate_t * __restrict ps __unused)
{
if (s == NULL)
/* Reset to initial shift state (no-op) */
return (1);
if (wc < 0 || wc > 127) {
errno = EILSEQ;
return ((size_t)-1);
}
*s = (unsigned char)wc;
return (1);
}
static size_t
_ascii_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps __unused)
{
const char *s;
size_t nchr;
if (dst == NULL) {
for (s = *src; nms > 0 && *s != '\0'; s++, nms--) {
if (*s & 0x80) {
errno = EILSEQ;
return ((size_t)-1);
}
}
return (s - *src);
}
s = *src;
nchr = 0;
while (len-- > 0 && nms-- > 0) {
if (*s & 0x80) {
*src = s;
errno = EILSEQ;
return ((size_t)-1);
}
if ((*dst++ = (unsigned char)*s++) == L'\0') {
*src = NULL;
return (nchr);
}
nchr++;
}
*src = s;
return (nchr);
}
static size_t
_ascii_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps __unused)
{
const wchar_t *s;
size_t nchr;
if (dst == NULL) {
for (s = *src; nwc > 0 && *s != L'\0'; s++, nwc--) {
if (*s < 0 || *s > 127) {
errno = EILSEQ;
return ((size_t)-1);
}
}
return (s - *src);
}
s = *src;
nchr = 0;
while (len-- > 0 && nwc-- > 0) {
if (*s < 0 || *s > 127) {
*src = s;
errno = EILSEQ;
return ((size_t)-1);
}
if ((*dst++ = *s++) == '\0') {
*src = NULL;
return (nchr);
}
nchr++;
}
*src = s;
return (nchr);
}
diff --git a/lib/libc/locale/big5.c b/lib/libc/locale/big5.c
index 77c19e9d7c0e..3793a5e33319 100644
--- a/lib/libc/locale/big5.c
+++ b/lib/libc/locale/big5.c
@@ -1,198 +1,197 @@
/*-
* Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)big5.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <runetype.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
extern int __mb_sb_limit;
static size_t _BIG5_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _BIG5_mbsinit(const mbstate_t *);
static size_t _BIG5_wcrtomb(char * __restrict, wchar_t,
mbstate_t * __restrict);
static size_t _BIG5_mbsnrtowcs(wchar_t * __restrict,
const char ** __restrict, size_t, size_t,
mbstate_t * __restrict);
static size_t _BIG5_wcsnrtombs(char * __restrict,
const wchar_t ** __restrict, size_t, size_t,
mbstate_t * __restrict);
typedef struct {
wchar_t ch;
} _BIG5State;
int
_BIG5_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
l->__mbrtowc = _BIG5_mbrtowc;
l->__wcrtomb = _BIG5_wcrtomb;
l->__mbsnrtowcs = _BIG5_mbsnrtowcs;
l->__wcsnrtombs = _BIG5_wcsnrtombs;
l->__mbsinit = _BIG5_mbsinit;
l->runes = rl;
l->__mb_cur_max = 2;
l->__mb_sb_limit = 128;
return (0);
}
static int
_BIG5_mbsinit(const mbstate_t *ps)
{
return (ps == NULL || ((const _BIG5State *)ps)->ch == 0);
}
static __inline int
_big5_check(u_int c)
{
c &= 0xff;
return ((c >= 0xa1 && c <= 0xfe) ? 2 : 1);
}
static size_t
_BIG5_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
mbstate_t * __restrict ps)
{
_BIG5State *bs;
wchar_t wc;
size_t len;
bs = (_BIG5State *)ps;
if ((bs->ch & ~0xFF) != 0) {
/* Bad conversion state. */
errno = EINVAL;
return ((size_t)-1);
}
if (s == NULL) {
s = "";
n = 1;
pwc = NULL;
}
if (n == 0)
/* Incomplete multibyte sequence */
return ((size_t)-2);
if (bs->ch != 0) {
if (*s == '\0') {
errno = EILSEQ;
return ((size_t)-1);
}
wc = (bs->ch << 8) | (*s & 0xFF);
if (pwc != NULL)
*pwc = wc;
bs->ch = 0;
return (1);
}
len = (size_t)_big5_check(*s);
wc = *s++ & 0xff;
if (len == 2) {
if (n < 2) {
/* Incomplete multibyte sequence */
bs->ch = wc;
return ((size_t)-2);
}
if (*s == '\0') {
errno = EILSEQ;
return ((size_t)-1);
}
wc = (wc << 8) | (*s++ & 0xff);
if (pwc != NULL)
*pwc = wc;
return (2);
} else {
if (pwc != NULL)
*pwc = wc;
return (wc == L'\0' ? 0 : 1);
}
}
static size_t
_BIG5_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
{
_BIG5State *bs;
bs = (_BIG5State *)ps;
if (bs->ch != 0) {
errno = EINVAL;
return ((size_t)-1);
}
if (s == NULL)
/* Reset to initial shift state (no-op) */
return (1);
if (wc & 0x8000) {
*s++ = (wc >> 8) & 0xff;
*s = wc & 0xff;
return (2);
}
*s = wc & 0xff;
return (1);
}
static size_t
_BIG5_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps)
{
return (__mbsnrtowcs_std(dst, src, nms, len, ps, _BIG5_mbrtowc));
}
static size_t
_BIG5_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps)
{
return (__wcsnrtombs_std(dst, src, nwc, len, ps, _BIG5_wcrtomb));
}
diff --git a/lib/libc/locale/btowc.c b/lib/libc/locale/btowc.c
index e5e4951fedd8..a5bf7182298d 100644
--- a/lib/libc/locale/btowc.c
+++ b/lib/libc/locale/btowc.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002, 2003 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <wchar.h>
#include "mblocal.h"
wint_t
btowc_l(int c, locale_t l)
{
static const mbstate_t initial;
mbstate_t mbs = initial;
char cc;
wchar_t wc;
FIX_LOCALE(l);
if (c == EOF)
return (WEOF);
/*
* We expect mbrtowc() to return 0 or 1, hence the check for n > 1
* which detects error return values as well as "impossible" byte
* counts.
*/
cc = (char)c;
if (XLOCALE_CTYPE(l)->__mbrtowc(&wc, &cc, 1, &mbs) > 1)
return (WEOF);
return (wc);
}
wint_t
btowc(int c)
{
return btowc_l(c, __get_locale());
}
diff --git a/lib/libc/locale/c16rtomb.c b/lib/libc/locale/c16rtomb.c
index de6ada6521c6..7814da308fc9 100644
--- a/lib/libc/locale/c16rtomb.c
+++ b/lib/libc/locale/c16rtomb.c
@@ -1,81 +1,80 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <uchar.h>
#include "mblocal.h"
typedef struct {
char16_t lead_surrogate;
mbstate_t c32_mbstate;
} _Char16State;
size_t
c16rtomb_l(char * __restrict s, char16_t c16, mbstate_t * __restrict ps,
locale_t locale)
{
_Char16State *cs;
char32_t c32;
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->c16rtomb);
cs = (_Char16State *)ps;
/* If s is a null pointer, the value of parameter c16 is ignored. */
if (s == NULL) {
c32 = 0;
} else if (cs->lead_surrogate >= 0xd800 &&
cs->lead_surrogate <= 0xdbff) {
/* We should see a trail surrogate now. */
if (c16 < 0xdc00 || c16 > 0xdfff) {
errno = EILSEQ;
return ((size_t)-1);
}
c32 = 0x10000 + ((cs->lead_surrogate & 0x3ff) << 10 |
(c16 & 0x3ff));
} else if (c16 >= 0xd800 && c16 <= 0xdbff) {
/* Store lead surrogate for next invocation. */
cs->lead_surrogate = c16;
return (0);
} else {
/* Regular character. */
c32 = c16;
}
cs->lead_surrogate = 0;
return (c32rtomb_l(s, c32, &cs->c32_mbstate, locale));
}
size_t
c16rtomb(char * __restrict s, char16_t c16, mbstate_t * __restrict ps)
{
return (c16rtomb_l(s, c16, ps, __get_locale()));
}
diff --git a/lib/libc/locale/c32rtomb.c b/lib/libc/locale/c32rtomb.c
index f60d137556b2..1addb222e588 100644
--- a/lib/libc/locale/c32rtomb.c
+++ b/lib/libc/locale/c32rtomb.c
@@ -1,59 +1,58 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <uchar.h>
#include <wchar.h>
#include "mblocal.h"
size_t
c32rtomb_l(char * __restrict s, char32_t c32, mbstate_t * __restrict ps,
locale_t locale)
{
/* Unicode Standard 5.0, D90: ill-formed characters. */
if ((c32 >= 0xd800 && c32 <= 0xdfff) || c32 > 0x10ffff) {
errno = EILSEQ;
return ((size_t)-1);
}
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->c32rtomb);
/* Assume wchar_t uses UTF-32. */
return (wcrtomb_l(s, c32, ps, locale));
}
size_t
c32rtomb(char * __restrict s, char32_t c32, mbstate_t * __restrict ps)
{
return (c32rtomb_l(s, c32, ps, __get_locale()));
}
diff --git a/lib/libc/locale/cXXrtomb_iconv.h b/lib/libc/locale/cXXrtomb_iconv.h
index cca2c1f160d4..f75126df3c14 100644
--- a/lib/libc/locale/cXXrtomb_iconv.h
+++ b/lib/libc/locale/cXXrtomb_iconv.h
@@ -1,113 +1,112 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/queue.h>
#include <assert.h>
#include <errno.h>
#include <langinfo.h>
#include <uchar.h>
#include "../iconv/citrus_hash.h"
#include "../iconv/citrus_module.h"
#include "../iconv/citrus_iconv.h"
#include "mblocal.h"
typedef struct {
bool initialized;
struct _citrus_iconv iconv;
union {
charXX_t widechar[SRCBUF_LEN];
char bytes[sizeof(charXX_t) * SRCBUF_LEN];
} srcbuf;
size_t srcbuf_len;
} _ConversionState;
_Static_assert(sizeof(_ConversionState) <= sizeof(mbstate_t),
"Size of _ConversionState must not exceed mbstate_t's size.");
size_t
cXXrtomb_l(char * __restrict s, charXX_t c, mbstate_t * __restrict ps,
locale_t locale)
{
_ConversionState *cs;
struct _citrus_iconv *handle;
char *src, *dst;
size_t srcleft, dstleft, invlen;
int err;
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->cXXrtomb);
cs = (_ConversionState *)ps;
handle = &cs->iconv;
/* Reinitialize mbstate_t. */
if (s == NULL || !cs->initialized) {
if (_citrus_iconv_open(&handle, UTF_XX_INTERNAL,
nl_langinfo_l(CODESET, locale)) != 0) {
cs->initialized = false;
errno = EINVAL;
return (-1);
}
cs->srcbuf_len = 0;
cs->initialized = true;
if (s == NULL)
return (1);
}
assert(cs->srcbuf_len < sizeof(cs->srcbuf.widechar) / sizeof(charXX_t));
cs->srcbuf.widechar[cs->srcbuf_len++] = c;
/* Perform conversion. */
src = cs->srcbuf.bytes;
srcleft = cs->srcbuf_len * sizeof(charXX_t);
dst = s;
dstleft = MB_CUR_MAX_L(locale);
err = _citrus_iconv_convert(handle, &src, &srcleft, &dst, &dstleft,
_CITRUS_ICONV_F_HIDE_INVALID, &invlen);
/* Character is part of a surrogate pair. We need more input. */
if (err == EINVAL)
return (0);
cs->srcbuf_len = 0;
/* Illegal sequence. */
if (dst == s) {
errno = EILSEQ;
return ((size_t)-1);
}
return (dst - s);
}
size_t
cXXrtomb(char * __restrict s, charXX_t c, mbstate_t * __restrict ps)
{
return (cXXrtomb_l(s, c, ps, __get_locale()));
}
diff --git a/lib/libc/locale/collate.c b/lib/libc/locale/collate.c
index 60c14a7de552..8e3635485f10 100644
--- a/lib/libc/locale/collate.c
+++ b/lib/libc/locale/collate.c
@@ -1,735 +1,734 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Adapted to xlocale by John Marino <draco@marino.st>
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "un-namespace.h"
#include "collate.h"
#include "setlocale.h"
#include "ldpart.h"
#include "libc_private.h"
struct xlocale_collate __xlocale_global_collate = {
{{0}, "C"}, 1, 0, 0, 0
};
struct xlocale_collate __xlocale_C_collate = {
{{0}, "C"}, 1, 0, 0, 0
};
struct xlocale_collate __xlocale_POSIX_collate = {
{{0}, "POSIX"}, 1, 0, 0, 0
};
struct xlocale_collate __xlocale_CUTF8_collate = {
{{0}, "C.UTF-8"}, 1, 0, 0, 0
};
static int
__collate_load_tables_l(const char *encoding, struct xlocale_collate *table);
static void
destruct_collate(void *t)
{
struct xlocale_collate *table = t;
if (table->map && (table->maplen > 0)) {
(void) munmap(table->map, table->maplen);
}
free(t);
}
void *
__collate_load(const char *encoding, __unused locale_t unused)
{
if (strcmp(encoding, "C") == 0)
return (&__xlocale_C_collate);
else if (strcmp(encoding, "POSIX") == 0)
return (&__xlocale_POSIX_collate);
else if (strcmp(encoding, "C.UTF-8") == 0)
return (&__xlocale_CUTF8_collate);
struct xlocale_collate *table = calloc(sizeof(struct xlocale_collate),
1);
if (table == NULL)
return (NULL);
table->header.header.destructor = destruct_collate;
/*
* FIXME: Make sure that _LDP_CACHE is never returned. We
* should be doing the caching outside of this section.
*/
if (__collate_load_tables_l(encoding, table) != _LDP_LOADED) {
xlocale_release(table);
return (NULL);
}
return (table);
}
/**
* Load the collation tables for the specified encoding into the global table.
*/
int
__collate_load_tables(const char *encoding)
{
return (__collate_load_tables_l(encoding, &__xlocale_global_collate));
}
static int
__collate_load_tables_l(const char *encoding, struct xlocale_collate *table)
{
int i, chains, z;
char *buf;
char *TMP;
char *map;
collate_info_t *info;
struct stat sbuf;
int fd;
table->__collate_load_error = 1;
/* 'encoding' must be already checked. */
if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0 ||
strncmp(encoding, "C.", 2) == 0) {
return (_LDP_CACHE);
}
if (asprintf(&buf, "%s/%s/LC_COLLATE", _PathLocale, encoding) == -1)
return (_LDP_ERROR);
if ((fd = _open(buf, O_RDONLY | O_CLOEXEC)) < 0) {
free(buf);
return (_LDP_ERROR);
}
free(buf);
if (_fstat(fd, &sbuf) < 0) {
(void) _close(fd);
return (_LDP_ERROR);
}
if (sbuf.st_size < (COLLATE_FMT_VERSION_LEN +
XLOCALE_DEF_VERSION_LEN +
sizeof (*info))) {
(void) _close(fd);
errno = EINVAL;
return (_LDP_ERROR);
}
map = mmap(NULL, sbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
(void) _close(fd);
if ((TMP = map) == MAP_FAILED) {
return (_LDP_ERROR);
}
if (strncmp(TMP, COLLATE_FMT_VERSION, COLLATE_FMT_VERSION_LEN) != 0) {
(void) munmap(map, sbuf.st_size);
errno = EINVAL;
return (_LDP_ERROR);
}
TMP += COLLATE_FMT_VERSION_LEN;
strlcat(table->header.version, TMP, sizeof (table->header.version));
TMP += XLOCALE_DEF_VERSION_LEN;
info = (void *)TMP;
TMP += sizeof (*info);
if ((info->directive_count < 1) ||
(info->directive_count >= COLL_WEIGHTS_MAX) ||
((chains = info->chain_count) < 0)) {
(void) munmap(map, sbuf.st_size);
errno = EINVAL;
return (_LDP_ERROR);
}
i = (sizeof (collate_char_t) * (UCHAR_MAX + 1)) +
(sizeof (collate_chain_t) * chains) +
(sizeof (collate_large_t) * info->large_count);
for (z = 0; z < info->directive_count; z++) {
i += sizeof (collate_subst_t) * info->subst_count[z];
}
if (i != (sbuf.st_size - (TMP - map))) {
(void) munmap(map, sbuf.st_size);
errno = EINVAL;
return (_LDP_ERROR);
}
if (table->map && (table->maplen > 0)) {
(void) munmap(table->map, table->maplen);
}
table->map = map;
table->maplen = sbuf.st_size;
table->info = info;
table->char_pri_table = (void *)TMP;
TMP += sizeof (collate_char_t) * (UCHAR_MAX + 1);
for (z = 0; z < info->directive_count; z++) {
if (info->subst_count[z] > 0) {
table->subst_table[z] = (void *)TMP;
TMP += info->subst_count[z] * sizeof (collate_subst_t);
} else {
table->subst_table[z] = NULL;
}
}
if (chains > 0) {
table->chain_pri_table = (void *)TMP;
TMP += chains * sizeof (collate_chain_t);
} else
table->chain_pri_table = NULL;
if (info->large_count > 0)
table->large_pri_table = (void *)TMP;
else
table->large_pri_table = NULL;
table->__collate_load_error = 0;
return (_LDP_LOADED);
}
static const int32_t *
substsearch(struct xlocale_collate *table, const wchar_t key, int pass)
{
const collate_subst_t *p;
int n = table->info->subst_count[pass];
if (n == 0)
return (NULL);
if (pass >= table->info->directive_count)
return (NULL);
if (!(key & COLLATE_SUBST_PRIORITY))
return (NULL);
p = table->subst_table[pass] + (key & ~COLLATE_SUBST_PRIORITY);
assert(p->key == key);
return (p->pri);
}
static collate_chain_t *
chainsearch(struct xlocale_collate *table, const wchar_t *key, int *len)
{
int low = 0;
int high = table->info->chain_count - 1;
int next, compar, l;
collate_chain_t *p;
collate_chain_t *tab = table->chain_pri_table;
if (high < 0)
return (NULL);
while (low <= high) {
next = (low + high) / 2;
p = tab + next;
compar = *key - *p->str;
if (compar == 0) {
l = wcsnlen(p->str, COLLATE_STR_LEN);
compar = wcsncmp(key, p->str, l);
if (compar == 0) {
*len = l;
return (p);
}
}
if (compar > 0)
low = next + 1;
else
high = next - 1;
}
return (NULL);
}
static collate_large_t *
largesearch(struct xlocale_collate *table, const wchar_t key)
{
int low = 0;
int high = table->info->large_count - 1;
int next, compar;
collate_large_t *p;
collate_large_t *tab = table->large_pri_table;
if (high < 0)
return (NULL);
while (low <= high) {
next = (low + high) / 2;
p = tab + next;
compar = key - p->val;
if (compar == 0)
return (p);
if (compar > 0)
low = next + 1;
else
high = next - 1;
}
return (NULL);
}
void
_collate_lookup(struct xlocale_collate *table, const wchar_t *t, int *len,
int *pri, int which, const int **state)
{
collate_chain_t *p2;
collate_large_t *match;
int p, l;
const int *sptr;
/*
* If this is the "last" pass for the UNDEFINED, then
* we just return the priority itself.
*/
if (which >= table->info->directive_count) {
*pri = *t;
*len = 1;
*state = NULL;
return;
}
/*
* If we have remaining substitution data from a previous
* call, consume it first.
*/
if ((sptr = *state) != NULL) {
*pri = *sptr;
sptr++;
if ((sptr == *state) || (sptr == NULL))
*state = NULL;
else
*state = sptr;
*len = 0;
return;
}
/* No active substitutions */
*len = 1;
/*
* Check for composites such as diphthongs that collate as a
* single element (aka chains or collating-elements).
*/
if (((p2 = chainsearch(table, t, &l)) != NULL) &&
((p = p2->pri[which]) >= 0)) {
*len = l;
*pri = p;
} else if (*t <= UCHAR_MAX) {
/*
* Character is a small (8-bit) character.
* We just look these up directly for speed.
*/
*pri = table->char_pri_table[*t].pri[which];
} else if ((table->info->large_count > 0) &&
((match = largesearch(table, *t)) != NULL)) {
/*
* Character was found in the extended table.
*/
*pri = match->pri.pri[which];
} else {
/*
* Character lacks a specific definition.
*/
if (table->info->directive[which] & DIRECTIVE_UNDEFINED) {
/* Mask off sign bit to prevent ordering confusion. */
*pri = (*t & COLLATE_MAX_PRIORITY);
} else {
*pri = table->info->undef_pri[which];
}
/* No substitutions for undefined characters! */
return;
}
/*
* Try substituting (expanding) the character. We are
* currently doing this *after* the chain compression. I
* think it should not matter, but this way might be slightly
* faster.
*
* We do this after the priority search, as this will help us
* to identify a single key value. In order for this to work,
* its important that the priority assigned to a given element
* to be substituted be unique for that level. The localedef
* code ensures this for us.
*/
if ((sptr = substsearch(table, *pri, which)) != NULL) {
if ((*pri = *sptr) > 0) {
sptr++;
*state = *sptr ? sptr : NULL;
}
}
}
/*
* This is the meaty part of wcsxfrm & strxfrm. Note that it does
* NOT NULL terminate. That is left to the caller.
*/
size_t
_collate_wxfrm(struct xlocale_collate *table, const wchar_t *src, wchar_t *xf,
size_t room)
{
int pri;
int len;
const wchar_t *t;
wchar_t *tr = NULL;
int direc;
int pass;
const int32_t *state;
size_t want = 0;
size_t need = 0;
int ndir = table->info->directive_count;
assert(src);
for (pass = 0; pass <= ndir; pass++) {
state = NULL;
if (pass != 0) {
/* insert level separator from the previous pass */
if (room) {
*xf++ = 1;
room--;
}
want++;
}
/* special pass for undefined */
if (pass == ndir) {
direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
} else {
direc = table->info->directive[pass];
}
t = src;
if (direc & DIRECTIVE_BACKWARD) {
wchar_t *bp, *fp, c;
free(tr);
if ((tr = wcsdup(t)) == NULL) {
errno = ENOMEM;
goto fail;
}
bp = tr;
fp = tr + wcslen(tr) - 1;
while (bp < fp) {
c = *bp;
*bp++ = *fp;
*fp-- = c;
}
t = (const wchar_t *)tr;
}
if (direc & DIRECTIVE_POSITION) {
while (*t || state) {
_collate_lookup(table, t, &len, &pri, pass, &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
errno = EINVAL;
goto fail;
}
state = NULL;
pri = COLLATE_MAX_PRIORITY;
}
if (room) {
*xf++ = pri;
room--;
}
want++;
need = want;
}
} else {
while (*t || state) {
_collate_lookup(table, t, &len, &pri, pass, &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
errno = EINVAL;
goto fail;
}
state = NULL;
continue;
}
if (room) {
*xf++ = pri;
room--;
}
want++;
need = want;
}
}
}
free(tr);
return (need);
fail:
free(tr);
return ((size_t)(-1));
}
/*
* In the non-POSIX case, we transform each character into a string of
* characters representing the character's priority. Since char is usually
* signed, we are limited by 7 bits per byte. To avoid zero, we need to add
* XFRM_OFFSET, so we can't use a full 7 bits. For simplicity, we choose 6
* bits per byte.
*
* It turns out that we sometimes have real priorities that are
* 31-bits wide. (But: be careful using priorities where the high
* order bit is set -- i.e. the priority is negative. The sort order
* may be surprising!)
*
* TODO: This would be a good area to optimize somewhat. It turns out
* that real prioririties *except for the last UNDEFINED pass* are generally
* very small. We need the localedef code to precalculate the max
* priority for us, and ideally also give us a mask, and then we could
* severely limit what we expand to.
*/
#define XFRM_BYTES 6
#define XFRM_OFFSET ('0') /* make all printable characters */
#define XFRM_SHIFT 6
#define XFRM_MASK ((1 << XFRM_SHIFT) - 1)
#define XFRM_SEP ('.') /* chosen to be less than XFRM_OFFSET */
static int
xfrm(struct xlocale_collate *table, unsigned char *p, int pri, int pass)
{
/* we use unsigned to ensure zero fill on right shift */
uint32_t val = (uint32_t)table->info->pri_count[pass];
int nc = 0;
while (val) {
*p = (pri & XFRM_MASK) + XFRM_OFFSET;
pri >>= XFRM_SHIFT;
val >>= XFRM_SHIFT;
p++;
nc++;
}
return (nc);
}
size_t
_collate_sxfrm(struct xlocale_collate *table, const wchar_t *src, char *xf,
size_t room)
{
int pri;
int len;
const wchar_t *t;
wchar_t *tr = NULL;
int direc;
int pass;
const int32_t *state;
size_t want = 0;
size_t need = 0;
int b;
uint8_t buf[XFRM_BYTES];
int ndir = table->info->directive_count;
assert(src);
for (pass = 0; pass <= ndir; pass++) {
state = NULL;
if (pass != 0) {
/* insert level separator from the previous pass */
if (room) {
*xf++ = XFRM_SEP;
room--;
}
want++;
}
/* special pass for undefined */
if (pass == ndir) {
direc = DIRECTIVE_FORWARD | DIRECTIVE_UNDEFINED;
} else {
direc = table->info->directive[pass];
}
t = src;
if (direc & DIRECTIVE_BACKWARD) {
wchar_t *bp, *fp, c;
free(tr);
if ((tr = wcsdup(t)) == NULL) {
errno = ENOMEM;
goto fail;
}
bp = tr;
fp = tr + wcslen(tr) - 1;
while (bp < fp) {
c = *bp;
*bp++ = *fp;
*fp-- = c;
}
t = (const wchar_t *)tr;
}
if (direc & DIRECTIVE_POSITION) {
while (*t || state) {
_collate_lookup(table, t, &len, &pri, pass, &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
errno = EINVAL;
goto fail;
}
state = NULL;
pri = COLLATE_MAX_PRIORITY;
}
b = xfrm(table, buf, pri, pass);
want += b;
if (room) {
while (b) {
b--;
if (room) {
*xf++ = buf[b];
room--;
}
}
}
need = want;
}
} else {
while (*t || state) {
_collate_lookup(table, t, &len, &pri, pass, &state);
t += len;
if (pri <= 0) {
if (pri < 0) {
errno = EINVAL;
goto fail;
}
state = NULL;
continue;
}
b = xfrm(table, buf, pri, pass);
want += b;
if (room) {
while (b) {
b--;
if (room) {
*xf++ = buf[b];
room--;
}
}
}
need = want;
}
}
}
free(tr);
return (need);
fail:
free(tr);
return ((size_t)(-1));
}
/*
* __collate_equiv_value returns the primary collation value for the given
* collating symbol specified by str and len. Zero or negative is returned
* if the collating symbol was not found. This function is used by bracket
* code in the TRE regex library.
*/
int
__collate_equiv_value(locale_t locale, const wchar_t *str, size_t len)
{
int32_t e;
if (len < 1 || len >= COLLATE_STR_LEN)
return (-1);
FIX_LOCALE(locale);
struct xlocale_collate *table =
(struct xlocale_collate*)locale->components[XLC_COLLATE];
if (table->__collate_load_error)
return ((len == 1 && *str <= UCHAR_MAX) ? *str : -1);
if (len == 1) {
e = -1;
if (*str <= UCHAR_MAX)
e = table->char_pri_table[*str].pri[0];
else if (table->info->large_count > 0) {
collate_large_t *match_large;
match_large = largesearch(table, *str);
if (match_large)
e = match_large->pri.pri[0];
}
if (e == 0)
return (1);
return (e > 0 ? e : 0);
}
if (table->info->chain_count > 0) {
wchar_t name[COLLATE_STR_LEN];
collate_chain_t *match_chain;
int clen;
wcsncpy (name, str, len);
name[len] = 0;
match_chain = chainsearch(table, name, &clen);
if (match_chain) {
e = match_chain->pri[0];
if (e == 0)
return (1);
return (e < 0 ? -e : e);
}
}
return (0);
}
diff --git a/lib/libc/locale/collate.h b/lib/libc/locale/collate.h
index 2d3723b49f5b..f157d8651899 100644
--- a/lib/libc/locale/collate.h
+++ b/lib/libc/locale/collate.h
@@ -1,142 +1,141 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _COLLATE_H_
#define _COLLATE_H_
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
#include "xlocale_private.h"
/*
* Work around buildworld bootstrapping from older systems whose limits.h
* sets COLL_WEIGHTS_MAX to 0.
*/
#if COLL_WEIGHTS_MAX == 0
#undef COLL_WEIGHTS_MAX
#define COLL_WEIGHTS_MAX 10
#endif
#define COLLATE_STR_LEN 24 /* should be 64-bit multiple */
#define COLLATE_FMT_VERSION_LEN 12
#define COLLATE_FMT_VERSION "BSD 1.0\n"
#define COLLATE_MAX_PRIORITY (0x7fffffff) /* max signed value */
#define COLLATE_SUBST_PRIORITY (0x40000000) /* bit indicates subst table */
#define DIRECTIVE_UNDEF 0x00
#define DIRECTIVE_FORWARD 0x01
#define DIRECTIVE_BACKWARD 0x02
#define DIRECTIVE_POSITION 0x04
#define DIRECTIVE_UNDEFINED 0x08 /* special last weight for UNDEFINED */
#define DIRECTIVE_DIRECTION_MASK (DIRECTIVE_FORWARD | DIRECTIVE_BACKWARD)
/*
* The collate file format is as follows:
*
* char fmt_version[COLLATE_FMT_VERSION_LEN]; // must be COLLATE_FMT_VERSION
* char def_version[XLOCALE_DEF_VERSION_LEN]; // NUL-terminated, may be empty
* collate_info_t info; // see below, includes padding
* collate_char_pri_t char_data[256]; // 8 bit char values
* collate_subst_t subst[*]; // 0 or more substitutions
* collate_chain_pri_t chains[*]; // 0 or more chains
* collate_large_pri_t large[*]; // extended char priorities
*
* Note that all structures must be 32-bit aligned, as each structure
* contains 32-bit member fields. The entire file is mmap'd, so its
* critical that alignment be observed. It is not generally safe to
* use any 64-bit values in the structures.
*/
typedef struct collate_info {
uint8_t directive_count;
uint8_t directive[COLL_WEIGHTS_MAX];
int32_t pri_count[COLL_WEIGHTS_MAX];
int32_t flags;
int32_t chain_count;
int32_t large_count;
int32_t subst_count[COLL_WEIGHTS_MAX];
int32_t undef_pri[COLL_WEIGHTS_MAX];
} collate_info_t;
typedef struct collate_char {
int32_t pri[COLL_WEIGHTS_MAX];
} collate_char_t;
typedef struct collate_chain {
wchar_t str[COLLATE_STR_LEN];
int32_t pri[COLL_WEIGHTS_MAX];
} collate_chain_t;
typedef struct collate_large {
int32_t val;
collate_char_t pri;
} collate_large_t;
typedef struct collate_subst {
int32_t key;
int32_t pri[COLLATE_STR_LEN];
} collate_subst_t;
struct xlocale_collate {
struct xlocale_component header;
int __collate_load_error;
char * map;
size_t maplen;
collate_info_t *info;
collate_char_t *char_pri_table;
collate_large_t *large_pri_table;
collate_chain_t *chain_pri_table;
collate_subst_t *subst_table[COLL_WEIGHTS_MAX];
};
__BEGIN_DECLS
int __collate_load_tables(const char *);
int __collate_equiv_value(locale_t, const wchar_t *, size_t);
void _collate_lookup(struct xlocale_collate *,const wchar_t *, int *, int *,
int, const int **);
int __collate_range_cmp(char, char);
int __wcollate_range_cmp(wchar_t, wchar_t);
size_t _collate_wxfrm(struct xlocale_collate *, const wchar_t *, wchar_t *,
size_t);
size_t _collate_sxfrm(struct xlocale_collate *, const wchar_t *, char *,
size_t);
__END_DECLS
#endif /* !_COLLATE_H_ */
diff --git a/lib/libc/locale/collcmp.c b/lib/libc/locale/collcmp.c
index 7b2d6723411b..855f84d884da 100644
--- a/lib/libc/locale/collcmp.c
+++ b/lib/libc/locale/collcmp.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 1996 by Andrey A. Chernov, Moscow, Russia.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <string.h>
#include <wchar.h>
#include "collate.h"
/*
* Compare two characters using collate
*/
int __collate_range_cmp(char c1, char c2)
{
char s1[2], s2[2];
s1[0] = c1;
s1[1] = '\0';
s2[0] = c2;
s2[1] = '\0';
return (strcoll(s1, s2));
}
int __wcollate_range_cmp(wchar_t c1, wchar_t c2)
{
wchar_t s1[2], s2[2];
s1[0] = c1;
s1[1] = L'\0';
s2[0] = c2;
s2[1] = L'\0';
return (wcscoll(s1, s2));
}
diff --git a/lib/libc/locale/fix_grouping.c b/lib/libc/locale/fix_grouping.c
index 19b32a378b95..2ae165661d84 100644
--- a/lib/libc/locale/fix_grouping.c
+++ b/lib/libc/locale/fix_grouping.c
@@ -1,86 +1,85 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <limits.h>
#include <stddef.h>
static const char nogrouping[] = { '\0' };
/*
* Internal helper used to convert grouping sequences from string
* representation into POSIX specified form, i.e.
*
* "3;3;-1" -> "\003\003\177\000"
*/
const char *
__fix_locale_grouping_str(const char *str)
{
char *src, *dst;
char n;
if (str == NULL || *str == '\0') {
return nogrouping;
}
for (src = (char*)str, dst = (char*)str; *src != '\0'; src++) {
/* input string examples: "3;3", "3;2;-1" */
if (*src == ';')
continue;
if (*src == '-' && *(src+1) == '1') {
*dst++ = CHAR_MAX;
src++;
continue;
}
if (!isdigit((unsigned char)*src)) {
/* broken grouping string */
return nogrouping;
}
/* assume all numbers <= 99 */
n = *src - '0';
if (isdigit((unsigned char)*(src+1))) {
src++;
n *= 10;
n += *src - '0';
}
*dst = n;
/* NOTE: assume all input started with "0" as 'no grouping' */
if (*dst == '\0')
return (dst == (char*)str) ? nogrouping : str;
dst++;
}
*dst = '\0';
return str;
}
diff --git a/lib/libc/locale/gbk.c b/lib/libc/locale/gbk.c
index 045e0645b1b5..c64a9d534701 100644
--- a/lib/libc/locale/gbk.c
+++ b/lib/libc/locale/gbk.c
@@ -1,197 +1,196 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <runetype.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
extern int __mb_sb_limit;
static size_t _GBK_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _GBK_mbsinit(const mbstate_t *);
static size_t _GBK_wcrtomb(char * __restrict, wchar_t,
mbstate_t * __restrict);
static size_t _GBK_mbsnrtowcs(wchar_t * __restrict,
const char ** __restrict, size_t, size_t,
mbstate_t * __restrict);
static size_t _GBK_wcsnrtombs(char * __restrict,
const wchar_t ** __restrict, size_t, size_t,
mbstate_t * __restrict);
typedef struct {
wchar_t ch;
} _GBKState;
int
_GBK_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
l->__mbrtowc = _GBK_mbrtowc;
l->__wcrtomb = _GBK_wcrtomb;
l->__mbsinit = _GBK_mbsinit;
l->__mbsnrtowcs = _GBK_mbsnrtowcs;
l->__wcsnrtombs = _GBK_wcsnrtombs;
l->runes = rl;
l->__mb_cur_max = 2;
l->__mb_sb_limit = 128;
return (0);
}
static int
_GBK_mbsinit(const mbstate_t *ps)
{
return (ps == NULL || ((const _GBKState *)ps)->ch == 0);
}
static int
_gbk_check(u_int c)
{
c &= 0xff;
return ((c >= 0x81 && c <= 0xfe) ? 2 : 1);
}
static size_t
_GBK_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
mbstate_t * __restrict ps)
{
_GBKState *gs;
wchar_t wc;
size_t len;
gs = (_GBKState *)ps;
if ((gs->ch & ~0xFF) != 0) {
/* Bad conversion state. */
errno = EINVAL;
return ((size_t)-1);
}
if (s == NULL) {
s = "";
n = 1;
pwc = NULL;
}
if (n == 0)
/* Incomplete multibyte sequence */
return ((size_t)-2);
if (gs->ch != 0) {
if (*s == '\0') {
errno = EILSEQ;
return ((size_t)-1);
}
wc = (gs->ch << 8) | (*s & 0xFF);
if (pwc != NULL)
*pwc = wc;
gs->ch = 0;
return (1);
}
len = (size_t)_gbk_check(*s);
wc = *s++ & 0xff;
if (len == 2) {
if (n < 2) {
/* Incomplete multibyte sequence */
gs->ch = wc;
return ((size_t)-2);
}
if (*s == '\0') {
errno = EILSEQ;
return ((size_t)-1);
}
wc = (wc << 8) | (*s++ & 0xff);
if (pwc != NULL)
*pwc = wc;
return (2);
} else {
if (pwc != NULL)
*pwc = wc;
return (wc == L'\0' ? 0 : 1);
}
}
static size_t
_GBK_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
{
_GBKState *gs;
gs = (_GBKState *)ps;
if (gs->ch != 0) {
errno = EINVAL;
return ((size_t)-1);
}
if (s == NULL)
/* Reset to initial shift state (no-op) */
return (1);
if (wc & 0x8000) {
*s++ = (wc >> 8) & 0xff;
*s = wc & 0xff;
return (2);
}
*s = wc & 0xff;
return (1);
}
static size_t
_GBK_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps)
{
return (__mbsnrtowcs_std(dst, src, nms, len, ps, _GBK_mbrtowc));
}
static size_t
_GBK_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps)
{
return (__wcsnrtombs_std(dst, src, nwc, len, ps, _GBK_wcrtomb));
}
diff --git a/lib/libc/locale/isctype.c b/lib/libc/locale/isctype.c
index 45dc86c260f6..9f918e867636 100644
--- a/lib/libc/locale/isctype.c
+++ b/lib/libc/locale/isctype.c
@@ -1,206 +1,205 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)isctype.c 8.3 (Berkeley) 2/24/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <ctype.h>
#undef digittoint
int
digittoint(int c)
{
return (__sbmaskrune(c, 0xFF));
}
#undef isalnum
int
isalnum(int c)
{
return (__sbistype(c, _CTYPE_A|_CTYPE_N));
}
#undef isalpha
int
isalpha(int c)
{
return (__sbistype(c, _CTYPE_A));
}
#undef isascii
int
isascii(int c)
{
return ((c & ~0x7F) == 0);
}
#undef isblank
int
isblank(int c)
{
return (__sbistype(c, _CTYPE_B));
}
#undef iscntrl
int
iscntrl(int c)
{
return (__sbistype(c, _CTYPE_C));
}
#undef isdigit
int
isdigit(int c)
{
return (__isctype(c, _CTYPE_D));
}
#undef isgraph
int
isgraph(int c)
{
return (__sbistype(c, _CTYPE_G));
}
#undef ishexnumber
int
ishexnumber(int c)
{
return (__sbistype(c, _CTYPE_X));
}
#undef isideogram
int
isideogram(int c)
{
return (__sbistype(c, _CTYPE_I));
}
#undef islower
int
islower(int c)
{
return (__sbistype(c, _CTYPE_L));
}
#undef isnumber
int
isnumber(int c)
{
return (__sbistype(c, _CTYPE_N));
}
#undef isphonogram
int
isphonogram(int c)
{
return (__sbistype(c, _CTYPE_Q));
}
#undef isprint
int
isprint(int c)
{
return (__sbistype(c, _CTYPE_R));
}
#undef ispunct
int
ispunct(int c)
{
return (__sbistype(c, _CTYPE_P));
}
#undef isrune
int
isrune(int c)
{
return (__sbistype(c, 0xFFFFFF00L));
}
#undef isspace
int
isspace(int c)
{
return (__sbistype(c, _CTYPE_S));
}
#undef isspecial
int
isspecial(int c)
{
return (__sbistype(c, _CTYPE_T));
}
#undef isupper
int
isupper(int c)
{
return (__sbistype(c, _CTYPE_U));
}
#undef isxdigit
int
isxdigit(int c)
{
return (__isctype(c, _CTYPE_X));
}
#undef toascii
int
toascii(int c)
{
return (c & 0x7F);
}
#undef tolower
int
tolower(int c)
{
return (__sbtolower(c));
}
#undef toupper
int
toupper(int c)
{
return (__sbtoupper(c));
}
diff --git a/lib/libc/locale/iswctype.c b/lib/libc/locale/iswctype.c
index 8e5879b0b72c..0693da602116 100644
--- a/lib/libc/locale/iswctype.c
+++ b/lib/libc/locale/iswctype.c
@@ -1,189 +1,188 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wctype.h>
#undef iswalnum
int
iswalnum(wint_t wc)
{
return (__istype(wc, _CTYPE_A|_CTYPE_N));
}
#undef iswalpha
int
iswalpha(wint_t wc)
{
return (__istype(wc, _CTYPE_A));
}
#undef iswascii
int
iswascii(wint_t wc)
{
return ((wc & ~0x7F) == 0);
}
#undef iswblank
int
iswblank(wint_t wc)
{
return (__istype(wc, _CTYPE_B));
}
#undef iswcntrl
int
iswcntrl(wint_t wc)
{
return (__istype(wc, _CTYPE_C));
}
#undef iswdigit
int
iswdigit(wint_t wc)
{
return (__istype(wc, _CTYPE_D));
}
#undef iswgraph
int
iswgraph(wint_t wc)
{
return (__istype(wc, _CTYPE_G));
}
#undef iswhexnumber
int
iswhexnumber(wint_t wc)
{
return (__istype(wc, _CTYPE_X));
}
#undef iswideogram
int
iswideogram(wint_t wc)
{
return (__istype(wc, _CTYPE_I));
}
#undef iswlower
int
iswlower(wint_t wc)
{
return (__istype(wc, _CTYPE_L));
}
#undef iswnumber
int
iswnumber(wint_t wc)
{
return (__istype(wc, _CTYPE_N));
}
#undef iswphonogram
int
iswphonogram(wint_t wc)
{
return (__istype(wc, _CTYPE_Q));
}
#undef iswprint
int
iswprint(wint_t wc)
{
return (__istype(wc, _CTYPE_R));
}
#undef iswpunct
int
iswpunct(wint_t wc)
{
return (__istype(wc, _CTYPE_P));
}
#undef iswrune
int
iswrune(wint_t wc)
{
return (__istype(wc, 0xFFFFFF00L));
}
#undef iswspace
int
iswspace(wint_t wc)
{
return (__istype(wc, _CTYPE_S));
}
#undef iswspecial
int
iswspecial(wint_t wc)
{
return (__istype(wc, _CTYPE_T));
}
#undef iswupper
int
iswupper(wint_t wc)
{
return (__istype(wc, _CTYPE_U));
}
#undef iswxdigit
int
iswxdigit(wint_t wc)
{
return (__istype(wc, _CTYPE_X));
}
#undef towlower
wint_t
towlower(wint_t wc)
{
return (__tolower(wc));
}
#undef towupper
wint_t
towupper(wint_t wc)
{
return (__toupper(wc));
}
diff --git a/lib/libc/locale/ldpart.c b/lib/libc/locale/ldpart.c
index e77f3e2e2a72..77be5404b199 100644
--- a/lib/libc/locale/ldpart.c
+++ b/lib/libc/locale/ldpart.c
@@ -1,167 +1,166 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "ldpart.h"
#include "setlocale.h"
static int split_lines(char *, const char *);
int
__part_load_locale(const char *name,
int *using_locale,
char **locale_buf,
const char *category_filename,
int locale_buf_size_max,
int locale_buf_size_min,
const char **dst_localebuf)
{
int saverr, fd, i, num_lines;
char *lbuf, *p;
const char *plim;
char filename[PATH_MAX];
struct stat st;
size_t namesize, bufsize;
/* 'name' must be already checked. */
if (strcmp(name, "C") == 0 || strcmp(name, "POSIX") == 0 ||
strncmp(name, "C.", 2) == 0) {
*using_locale = 0;
return (_LDP_CACHE);
}
/*
* If the locale name is the same as our cache, use the cache.
*/
if (*locale_buf != NULL && strcmp(name, *locale_buf) == 0) {
*using_locale = 1;
return (_LDP_CACHE);
}
/*
* Slurp the locale file into the cache.
*/
namesize = strlen(name) + 1;
/* 'PathLocale' must be already set & checked. */
/* Range checking not needed, 'name' size is limited */
strcpy(filename, _PathLocale);
strcat(filename, "/");
strcat(filename, name);
strcat(filename, "/");
strcat(filename, category_filename);
if ((fd = _open(filename, O_RDONLY | O_CLOEXEC)) < 0)
return (_LDP_ERROR);
if (_fstat(fd, &st) != 0)
goto bad_locale;
if (st.st_size <= 0) {
errno = EFTYPE;
goto bad_locale;
}
bufsize = namesize + st.st_size;
if ((lbuf = malloc(bufsize)) == NULL) {
errno = ENOMEM;
goto bad_locale;
}
(void)strcpy(lbuf, name);
p = lbuf + namesize;
plim = p + st.st_size;
if (_read(fd, p, (size_t) st.st_size) != st.st_size)
goto bad_lbuf;
/*
* Parse the locale file into localebuf.
*/
if (plim[-1] != '\n') {
errno = EFTYPE;
goto bad_lbuf;
}
num_lines = split_lines(p, plim);
if (num_lines >= locale_buf_size_max)
num_lines = locale_buf_size_max;
else if (num_lines >= locale_buf_size_min)
num_lines = locale_buf_size_min;
else {
errno = EFTYPE;
goto bad_lbuf;
}
(void)_close(fd);
/*
* Record the successful parse in the cache.
*/
if (*locale_buf != NULL)
free(*locale_buf);
*locale_buf = lbuf;
for (p = *locale_buf, i = 0; i < num_lines; i++)
dst_localebuf[i] = (p += strlen(p) + 1);
for (i = num_lines; i < locale_buf_size_max; i++)
dst_localebuf[i] = NULL;
*using_locale = 1;
return (_LDP_LOADED);
bad_lbuf:
saverr = errno;
free(lbuf);
errno = saverr;
bad_locale:
saverr = errno;
(void)_close(fd);
errno = saverr;
return (_LDP_ERROR);
}
static int
split_lines(char *p, const char *plim)
{
int i;
i = 0;
while (p < plim) {
if (*p == '\n') {
*p = '\0';
i++;
}
p++;
}
return (i);
}
diff --git a/lib/libc/locale/lmessages.c b/lib/libc/locale/lmessages.c
index 90757b131fbb..716dc1ead6ea 100644
--- a/lib/libc/locale/lmessages.c
+++ b/lib/libc/locale/lmessages.c
@@ -1,134 +1,133 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stddef.h>
#include "ldpart.h"
#include "lmessages.h"
#define LCMESSAGES_SIZE_FULL (sizeof(struct lc_messages_T) / sizeof(char *))
#define LCMESSAGES_SIZE_MIN \
(offsetof(struct lc_messages_T, yesstr) / sizeof(char *))
struct xlocale_messages {
struct xlocale_component header;
char *buffer;
struct lc_messages_T locale;
};
struct xlocale_messages __xlocale_global_messages;
static char empty[] = "";
static const struct lc_messages_T _C_messages_locale = {
"^[yY]" , /* yesexpr */
"^[nN]" , /* noexpr */
"yes" , /* yesstr */
"no" /* nostr */
};
static void
destruct_messages(void *v)
{
struct xlocale_messages *l = v;
if (l->buffer)
free(l->buffer);
free(l);
}
static int
messages_load_locale(struct xlocale_messages *loc, int *using_locale,
const char *name)
{
int ret;
struct lc_messages_T *l = &loc->locale;
ret = __part_load_locale(name, using_locale,
&loc->buffer, "LC_MESSAGES",
LCMESSAGES_SIZE_FULL, LCMESSAGES_SIZE_MIN,
(const char **)l);
if (ret == _LDP_LOADED) {
if (l->yesstr == NULL)
l->yesstr = empty;
if (l->nostr == NULL)
l->nostr = empty;
}
return (ret);
}
int
__messages_load_locale(const char *name)
{
return (messages_load_locale(&__xlocale_global_messages,
&__xlocale_global_locale.using_messages_locale, name));
}
void *
__messages_load(const char *name, locale_t l)
{
struct xlocale_messages *new = calloc(sizeof(struct xlocale_messages),
1);
if (new == NULL)
return (NULL);
new->header.header.destructor = destruct_messages;
if (messages_load_locale(new, &l->using_messages_locale, name) ==
_LDP_ERROR) {
xlocale_release(new);
return (NULL);
}
return (new);
}
struct lc_messages_T *
__get_current_messages_locale(locale_t loc)
{
return (loc->using_messages_locale ? &((struct xlocale_messages *)
loc->components[XLC_MESSAGES])->locale :
(struct lc_messages_T *)&_C_messages_locale);
}
#ifdef LOCALE_DEBUG
void
msgdebug(void) {
printf( "yesexpr = %s\n"
"noexpr = %s\n"
"yesstr = %s\n"
"nostr = %s\n",
_messages_locale.yesexpr,
_messages_locale.noexpr,
_messages_locale.yesstr,
_messages_locale.nostr
);
}
#endif /* LOCALE_DEBUG */
diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c
index f12d4d258403..75ef6b3d53dc 100644
--- a/lib/libc/locale/lmonetary.c
+++ b/lib/libc/locale/lmonetary.c
@@ -1,229 +1,228 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stddef.h>
#include <stdlib.h>
#include "ldpart.h"
#include "lmonetary.h"
extern const char * __fix_locale_grouping_str(const char *);
#define LCMONETARY_SIZE_FULL (sizeof(struct lc_monetary_T) / sizeof(char *))
#define LCMONETARY_SIZE_MIN \
(offsetof(struct lc_monetary_T, int_p_cs_precedes) / \
sizeof(char *))
static char empty[] = "";
static char numempty[] = { CHAR_MAX, '\0'};
static const struct lc_monetary_T _C_monetary_locale = {
empty, /* int_curr_symbol */
empty, /* currency_symbol */
empty, /* mon_decimal_point */
empty, /* mon_thousands_sep */
numempty, /* mon_grouping */
empty, /* positive_sign */
empty, /* negative_sign */
numempty, /* int_frac_digits */
numempty, /* frac_digits */
numempty, /* p_cs_precedes */
numempty, /* p_sep_by_space */
numempty, /* n_cs_precedes */
numempty, /* n_sep_by_space */
numempty, /* p_sign_posn */
numempty, /* n_sign_posn */
numempty, /* int_p_cs_precedes */
numempty, /* int_n_cs_precedes */
numempty, /* int_p_sep_by_space */
numempty, /* int_n_sep_by_space */
numempty, /* int_p_sign_posn */
numempty /* int_n_sign_posn */
};
struct xlocale_monetary __xlocale_global_monetary;
static char
cnv(const char *str)
{
int i = strtol(str, NULL, 10);
if (i == -1)
i = CHAR_MAX;
return ((char)i);
}
static void
destruct_monetary(void *v)
{
struct xlocale_monetary *l = v;
if (l->buffer)
free(l->buffer);
free(l);
}
static int
monetary_load_locale_l(struct xlocale_monetary *loc, int *using_locale,
int *changed, const char *name)
{
int ret;
struct lc_monetary_T *l = &loc->locale;
ret = __part_load_locale(name, using_locale,
&loc->buffer, "LC_MONETARY",
LCMONETARY_SIZE_FULL, LCMONETARY_SIZE_MIN,
(const char **)l);
if (ret == _LDP_LOADED) {
l->mon_grouping =
__fix_locale_grouping_str(l->mon_grouping);
#define M_ASSIGN_CHAR(NAME) (((char *)l->NAME)[0] = \
cnv(l->NAME))
M_ASSIGN_CHAR(int_frac_digits);
M_ASSIGN_CHAR(frac_digits);
M_ASSIGN_CHAR(p_cs_precedes);
M_ASSIGN_CHAR(p_sep_by_space);
M_ASSIGN_CHAR(n_cs_precedes);
M_ASSIGN_CHAR(n_sep_by_space);
M_ASSIGN_CHAR(p_sign_posn);
M_ASSIGN_CHAR(n_sign_posn);
/*
* The six additional C99 international monetary formatting
* parameters default to the national parameters when
* reading FreeBSD LC_MONETARY data files.
*/
#define M_ASSIGN_ICHAR(NAME) \
do { \
if (l->int_##NAME == NULL) \
l->int_##NAME = \
l->NAME; \
else \
M_ASSIGN_CHAR(int_##NAME); \
} while (0)
M_ASSIGN_ICHAR(p_cs_precedes);
M_ASSIGN_ICHAR(n_cs_precedes);
M_ASSIGN_ICHAR(p_sep_by_space);
M_ASSIGN_ICHAR(n_sep_by_space);
M_ASSIGN_ICHAR(p_sign_posn);
M_ASSIGN_ICHAR(n_sign_posn);
}
if (ret != _LDP_ERROR)
atomic_store_rel_int(changed, 1);
return (ret);
}
int
__monetary_load_locale(const char *name)
{
return (monetary_load_locale_l(&__xlocale_global_monetary,
&__xlocale_global_locale.using_monetary_locale,
&__xlocale_global_locale.monetary_locale_changed, name));
}
void *
__monetary_load(const char *name, locale_t l)
{
struct xlocale_monetary *new = calloc(sizeof(struct xlocale_monetary),
1);
if (new == NULL)
return (NULL);
new->header.header.destructor = destruct_monetary;
if (monetary_load_locale_l(new, &l->using_monetary_locale,
&l->monetary_locale_changed, name) == _LDP_ERROR) {
xlocale_release(new);
return (NULL);
}
return (new);
}
struct lc_monetary_T *
__get_current_monetary_locale(locale_t loc)
{
return (loc->using_monetary_locale ?
&((struct xlocale_monetary*)loc->components[XLC_MONETARY])->locale :
(struct lc_monetary_T *)&_C_monetary_locale);
}
#ifdef LOCALE_DEBUG
void
monetdebug(void) {
printf( "int_curr_symbol = %s\n"
"currency_symbol = %s\n"
"mon_decimal_point = %s\n"
"mon_thousands_sep = %s\n"
"mon_grouping = %s\n"
"positive_sign = %s\n"
"negative_sign = %s\n"
"int_frac_digits = %d\n"
"frac_digits = %d\n"
"p_cs_precedes = %d\n"
"p_sep_by_space = %d\n"
"n_cs_precedes = %d\n"
"n_sep_by_space = %d\n"
"p_sign_posn = %d\n"
"n_sign_posn = %d\n"
"int_p_cs_precedes = %d\n"
"int_p_sep_by_space = %d\n"
"int_n_cs_precedes = %d\n"
"int_n_sep_by_space = %d\n"
"int_p_sign_posn = %d\n"
"int_n_sign_posn = %d\n",
_monetary_locale.int_curr_symbol,
_monetary_locale.currency_symbol,
_monetary_locale.mon_decimal_point,
_monetary_locale.mon_thousands_sep,
_monetary_locale.mon_grouping,
_monetary_locale.positive_sign,
_monetary_locale.negative_sign,
_monetary_locale.int_frac_digits[0],
_monetary_locale.frac_digits[0],
_monetary_locale.p_cs_precedes[0],
_monetary_locale.p_sep_by_space[0],
_monetary_locale.n_cs_precedes[0],
_monetary_locale.n_sep_by_space[0],
_monetary_locale.p_sign_posn[0],
_monetary_locale.n_sign_posn[0],
_monetary_locale.int_p_cs_precedes[0],
_monetary_locale.int_p_sep_by_space[0],
_monetary_locale.int_n_cs_precedes[0],
_monetary_locale.int_n_sep_by_space[0],
_monetary_locale.int_p_sign_posn[0],
_monetary_locale.int_n_sign_posn[0]
);
}
#endif /* LOCALE_DEBUG */
diff --git a/lib/libc/locale/lnumeric.c b/lib/libc/locale/lnumeric.c
index 109761a62b1d..8f8443668314 100644
--- a/lib/libc/locale/lnumeric.c
+++ b/lib/libc/locale/lnumeric.c
@@ -1,130 +1,129 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2000, 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include "ldpart.h"
#include "lnumeric.h"
extern const char *__fix_locale_grouping_str(const char *);
#define LCNUMERIC_SIZE (sizeof(struct lc_numeric_T) / sizeof(char *))
static char numempty[] = { CHAR_MAX, '\0' };
static const struct lc_numeric_T _C_numeric_locale = {
".", /* decimal_point */
"", /* thousands_sep */
numempty /* grouping */
};
static void
destruct_numeric(void *v)
{
struct xlocale_numeric *l = v;
if (l->buffer)
free(l->buffer);
free(l);
}
struct xlocale_numeric __xlocale_global_numeric;
static int
numeric_load_locale(struct xlocale_numeric *loc, int *using_locale,
int *changed, const char *name)
{
int ret;
struct lc_numeric_T *l = &loc->locale;
ret = __part_load_locale(name, using_locale,
&loc->buffer, "LC_NUMERIC",
LCNUMERIC_SIZE, LCNUMERIC_SIZE,
(const char**)l);
if (ret == _LDP_LOADED) {
/* Can't be empty according to C99 */
if (*l->decimal_point == '\0')
l->decimal_point =
_C_numeric_locale.decimal_point;
l->grouping =
__fix_locale_grouping_str(l->grouping);
}
if (ret != _LDP_ERROR)
atomic_store_rel_int(changed, 1);
return (ret);
}
int
__numeric_load_locale(const char *name)
{
return (numeric_load_locale(&__xlocale_global_numeric,
&__xlocale_global_locale.using_numeric_locale,
&__xlocale_global_locale.numeric_locale_changed, name));
}
void *
__numeric_load(const char *name, locale_t l)
{
struct xlocale_numeric *new = calloc(sizeof(struct xlocale_numeric),
1);
if (new == NULL)
return (NULL);
new->header.header.destructor = destruct_numeric;
if (numeric_load_locale(new, &l->using_numeric_locale,
&l->numeric_locale_changed, name) == _LDP_ERROR) {
xlocale_release(new);
return (NULL);
}
return (new);
}
struct lc_numeric_T *
__get_current_numeric_locale(locale_t loc)
{
return (loc->using_numeric_locale ?
&((struct xlocale_numeric *)loc->components[XLC_NUMERIC])->locale :
(struct lc_numeric_T *)&_C_numeric_locale);
}
#ifdef LOCALE_DEBUG
void
numericdebug(void) {
printf( "decimal_point = %s\n"
"thousands_sep = %s\n"
"grouping = %s\n",
_numeric_locale.decimal_point,
_numeric_locale.thousands_sep,
_numeric_locale.grouping
);
}
#endif /* LOCALE_DEBUG */
diff --git a/lib/libc/locale/localeconv.c b/lib/libc/locale/localeconv.c
index d87bd03cad61..018d650741f8 100644
--- a/lib/libc/locale/localeconv.c
+++ b/lib/libc/locale/localeconv.c
@@ -1,117 +1,116 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)localeconv.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <locale.h>
#include "lmonetary.h"
#include "lnumeric.h"
/*
* The localeconv() function constructs a struct lconv from the current
* monetary and numeric locales.
*
* Because localeconv() may be called many times (especially by library
* routines like printf() & strtod()), the approprate members of the
* lconv structure are computed only when the monetary or numeric
* locale has been changed.
*/
/*
* Return the current locale conversion.
*/
struct lconv *
localeconv_l(locale_t loc)
{
FIX_LOCALE(loc);
struct lconv *ret = &loc->lconv;
if (atomic_load_acq_int(&loc->monetary_locale_changed) != 0) {
/* LC_MONETARY part */
struct lc_monetary_T * mptr;
#define M_ASSIGN_STR(NAME) (ret->NAME = (char*)mptr->NAME)
#define M_ASSIGN_CHAR(NAME) (ret->NAME = mptr->NAME[0])
mptr = __get_current_monetary_locale(loc);
M_ASSIGN_STR(int_curr_symbol);
M_ASSIGN_STR(currency_symbol);
M_ASSIGN_STR(mon_decimal_point);
M_ASSIGN_STR(mon_thousands_sep);
M_ASSIGN_STR(mon_grouping);
M_ASSIGN_STR(positive_sign);
M_ASSIGN_STR(negative_sign);
M_ASSIGN_CHAR(int_frac_digits);
M_ASSIGN_CHAR(frac_digits);
M_ASSIGN_CHAR(p_cs_precedes);
M_ASSIGN_CHAR(p_sep_by_space);
M_ASSIGN_CHAR(n_cs_precedes);
M_ASSIGN_CHAR(n_sep_by_space);
M_ASSIGN_CHAR(p_sign_posn);
M_ASSIGN_CHAR(n_sign_posn);
M_ASSIGN_CHAR(int_p_cs_precedes);
M_ASSIGN_CHAR(int_n_cs_precedes);
M_ASSIGN_CHAR(int_p_sep_by_space);
M_ASSIGN_CHAR(int_n_sep_by_space);
M_ASSIGN_CHAR(int_p_sign_posn);
M_ASSIGN_CHAR(int_n_sign_posn);
atomic_store_int(&loc->monetary_locale_changed, 0);
}
if (atomic_load_acq_int(&loc->numeric_locale_changed) != 0) {
/* LC_NUMERIC part */
struct lc_numeric_T * nptr;
#define N_ASSIGN_STR(NAME) (ret->NAME = (char*)nptr->NAME)
nptr = __get_current_numeric_locale(loc);
N_ASSIGN_STR(decimal_point);
N_ASSIGN_STR(thousands_sep);
N_ASSIGN_STR(grouping);
atomic_store_int(&loc->numeric_locale_changed, 0);
}
return ret;
}
struct lconv *
localeconv(void)
{
return localeconv_l(__get_locale());
}
diff --git a/lib/libc/locale/mblen.c b/lib/libc/locale/mblen.c
index a0ff1660ce5d..f0723b2c05a9 100644
--- a/lib/libc/locale/mblen.c
+++ b/lib/libc/locale/mblen.c
@@ -1,62 +1,61 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
int
mblen_l(const char *s, size_t n, locale_t locale)
{
static const mbstate_t initial;
size_t rval;
FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
XLOCALE_CTYPE(locale)->mblen = initial;
return (0);
}
rval = XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n,
&(XLOCALE_CTYPE(locale)->mblen));
if (rval == (size_t)-1 || rval == (size_t)-2)
return (-1);
return ((int)rval);
}
int
mblen(const char *s, size_t n)
{
return mblen_l(s, n, __get_locale());
}
diff --git a/lib/libc/locale/mbrlen.c b/lib/libc/locale/mbrlen.c
index 57237c86141e..e4470070752f 100644
--- a/lib/libc/locale/mbrlen.c
+++ b/lib/libc/locale/mbrlen.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include "mblocal.h"
size_t
mbrlen_l(const char * __restrict s, size_t n, mbstate_t * __restrict ps, locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->mbrlen);
return (XLOCALE_CTYPE(locale)->__mbrtowc(NULL, s, n, ps));
}
size_t
mbrlen(const char * __restrict s, size_t n, mbstate_t * __restrict ps)
{
return mbrlen_l(s, n, ps, __get_locale());
}
diff --git a/lib/libc/locale/mbrtoc16.c b/lib/libc/locale/mbrtoc16.c
index 54c3beb16f66..0c0d33e944f6 100644
--- a/lib/libc/locale/mbrtoc16.c
+++ b/lib/libc/locale/mbrtoc16.c
@@ -1,89 +1,88 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <uchar.h>
#include "mblocal.h"
typedef struct {
char16_t trail_surrogate;
mbstate_t c32_mbstate;
} _Char16State;
size_t
mbrtoc16_l(char16_t * __restrict pc16, const char * __restrict s, size_t n,
mbstate_t * __restrict ps, locale_t locale)
{
_Char16State *cs;
char32_t c32;
ssize_t len;
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->mbrtoc16);
cs = (_Char16State *)ps;
/*
* Call straight into mbrtoc32_l() if we don't need to return a
* character value. According to the spec, if s is a null
* pointer, the value of parameter pc16 is also ignored.
*/
if (pc16 == NULL || s == NULL) {
cs->trail_surrogate = 0;
return (mbrtoc32_l(NULL, s, n, &cs->c32_mbstate, locale));
}
/* Return the trail surrogate from the previous invocation. */
if (cs->trail_surrogate >= 0xdc00 && cs->trail_surrogate <= 0xdfff) {
*pc16 = cs->trail_surrogate;
cs->trail_surrogate = 0;
return ((size_t)-3);
}
len = mbrtoc32_l(&c32, s, n, &cs->c32_mbstate, locale);
if (len >= 0) {
if (c32 < 0x10000) {
/* Fits in one UTF-16 character. */
*pc16 = c32;
} else {
/* Split up in a surrogate pair. */
c32 -= 0x10000;
*pc16 = 0xd800 | (c32 >> 10);
cs->trail_surrogate = 0xdc00 | (c32 & 0x3ff);
}
}
return (len);
}
size_t
mbrtoc16(char16_t * __restrict pc16, const char * __restrict s, size_t n,
mbstate_t * __restrict ps)
{
return (mbrtoc16_l(pc16, s, n, ps, __get_locale()));
}
diff --git a/lib/libc/locale/mbrtoc32.c b/lib/libc/locale/mbrtoc32.c
index 33227adb70b8..29b32abcf4fc 100644
--- a/lib/libc/locale/mbrtoc32.c
+++ b/lib/libc/locale/mbrtoc32.c
@@ -1,53 +1,52 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <uchar.h>
#include <wchar.h>
#include "mblocal.h"
size_t
mbrtoc32_l(char32_t * __restrict pc32, const char * __restrict s, size_t n,
mbstate_t * __restrict ps, locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->mbrtoc32);
/* Assume wchar_t uses UTF-32. */
return (mbrtowc_l(pc32, s, n, ps, locale));
}
size_t
mbrtoc32(char32_t * __restrict pc32, const char * __restrict s, size_t n,
mbstate_t * __restrict ps)
{
return (mbrtoc32_l(pc32, s, n, ps, __get_locale()));
}
diff --git a/lib/libc/locale/mbrtocXX_iconv.h b/lib/libc/locale/mbrtocXX_iconv.h
index c3c832149617..35d0fd914b1f 100644
--- a/lib/libc/locale/mbrtocXX_iconv.h
+++ b/lib/libc/locale/mbrtocXX_iconv.h
@@ -1,156 +1,155 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/queue.h>
#include <assert.h>
#include <errno.h>
#include <langinfo.h>
#include <limits.h>
#include <string.h>
#include <uchar.h>
#include "../iconv/citrus_hash.h"
#include "../iconv/citrus_module.h"
#include "../iconv/citrus_iconv.h"
#include "mblocal.h"
typedef struct {
bool initialized;
struct _citrus_iconv iconv;
char srcbuf[MB_LEN_MAX];
size_t srcbuf_len;
union {
charXX_t widechar[DSTBUF_LEN];
char bytes[sizeof(charXX_t) * DSTBUF_LEN];
} dstbuf;
size_t dstbuf_len;
} _ConversionState;
_Static_assert(sizeof(_ConversionState) <= sizeof(mbstate_t),
"Size of _ConversionState must not exceed mbstate_t's size.");
size_t
mbrtocXX_l(charXX_t * __restrict pc, const char * __restrict s, size_t n,
mbstate_t * __restrict ps, locale_t locale)
{
_ConversionState *cs;
struct _citrus_iconv *handle;
size_t i, retval;
charXX_t retchar;
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->mbrtocXX);
cs = (_ConversionState *)ps;
handle = &cs->iconv;
/* Reinitialize mbstate_t. */
if (s == NULL || !cs->initialized) {
if (_citrus_iconv_open(&handle,
nl_langinfo_l(CODESET, locale), UTF_XX_INTERNAL) != 0) {
cs->initialized = false;
errno = EINVAL;
return (-1);
}
cs->srcbuf_len = cs->dstbuf_len = 0;
cs->initialized = true;
if (s == NULL)
return (0);
}
/* See if we still have characters left from the previous invocation. */
if (cs->dstbuf_len > 0) {
retval = (size_t)-3;
goto return_char;
}
/* Fill up the read buffer as far as possible. */
if (n > sizeof(cs->srcbuf) - cs->srcbuf_len)
n = sizeof(cs->srcbuf) - cs->srcbuf_len;
memcpy(cs->srcbuf + cs->srcbuf_len, s, n);
/* Convert as few characters to the dst buffer as possible. */
for (i = 0; ; i++) {
char *src, *dst;
size_t srcleft, dstleft, invlen;
int err;
src = cs->srcbuf;
srcleft = cs->srcbuf_len + n;
dst = cs->dstbuf.bytes;
dstleft = i * sizeof(charXX_t);
assert(srcleft <= sizeof(cs->srcbuf) &&
dstleft <= sizeof(cs->dstbuf.bytes));
err = _citrus_iconv_convert(handle, &src, &srcleft,
&dst, &dstleft, _CITRUS_ICONV_F_HIDE_INVALID, &invlen);
cs->dstbuf_len = (dst - cs->dstbuf.bytes) / sizeof(charXX_t);
/* Got new character(s). Return the first. */
if (cs->dstbuf_len > 0) {
assert(src - cs->srcbuf > cs->srcbuf_len);
retval = src - cs->srcbuf - cs->srcbuf_len;
cs->srcbuf_len = 0;
goto return_char;
}
/* Increase dst buffer size, to obtain the surrogate pair. */
if (err == E2BIG)
continue;
/* Illegal sequence. */
if (invlen > 0) {
cs->srcbuf_len = 0;
errno = EILSEQ;
return ((size_t)-1);
}
/* Save unprocessed remainder for the next invocation. */
memmove(cs->srcbuf, src, srcleft);
cs->srcbuf_len = srcleft;
return ((size_t)-2);
}
return_char:
retchar = cs->dstbuf.widechar[0];
memmove(&cs->dstbuf.widechar[0], &cs->dstbuf.widechar[1],
--cs->dstbuf_len * sizeof(charXX_t));
if (pc != NULL)
*pc = retchar;
if (retchar == 0)
return (0);
return (retval);
}
size_t
mbrtocXX(charXX_t * __restrict pc, const char * __restrict s, size_t n,
mbstate_t * __restrict ps)
{
return (mbrtocXX_l(pc, s, n, ps, __get_locale()));
}
diff --git a/lib/libc/locale/mbrtowc.c b/lib/libc/locale/mbrtowc.c
index b92968156e0e..ac1afc49a94f 100644
--- a/lib/libc/locale/mbrtowc.c
+++ b/lib/libc/locale/mbrtowc.c
@@ -1,53 +1,52 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include "mblocal.h"
size_t
mbrtowc_l(wchar_t * __restrict pwc, const char * __restrict s,
size_t n, mbstate_t * __restrict ps, locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->mbrtowc);
return (XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n, ps));
}
size_t
mbrtowc(wchar_t * __restrict pwc, const char * __restrict s,
size_t n, mbstate_t * __restrict ps)
{
return mbrtowc_l(pwc, s, n, ps, __get_locale());
}
diff --git a/lib/libc/locale/mbsinit.c b/lib/libc/locale/mbsinit.c
index c9aece68fe6f..5b964c1b3d58 100644
--- a/lib/libc/locale/mbsinit.c
+++ b/lib/libc/locale/mbsinit.c
@@ -1,48 +1,47 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include "mblocal.h"
int
mbsinit_l(const mbstate_t *ps, locale_t locale)
{
FIX_LOCALE(locale);
return (XLOCALE_CTYPE(locale)->__mbsinit(ps));
}
int
mbsinit(const mbstate_t *ps)
{
return mbsinit_l(ps, __get_locale());
}
diff --git a/lib/libc/locale/mbsnrtowcs.c b/lib/libc/locale/mbsnrtowcs.c
index b667ee710757..9a261a297e73 100644
--- a/lib/libc/locale/mbsnrtowcs.c
+++ b/lib/libc/locale/mbsnrtowcs.c
@@ -1,103 +1,102 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
size_t
mbsnrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps, locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->mbsnrtowcs);
return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, nms, len, ps));
}
size_t
mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps)
{
return mbsnrtowcs_l(dst, src, nms, len, ps, __get_locale());
}
size_t
__mbsnrtowcs_std(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps,
mbrtowc_pfn_t pmbrtowc)
{
const char *s;
size_t nchr;
wchar_t wc;
size_t nb;
s = *src;
nchr = 0;
if (dst == NULL) {
for (;;) {
if ((nb = pmbrtowc(&wc, s, nms, ps)) == (size_t)-1)
/* Invalid sequence - mbrtowc() sets errno. */
return ((size_t)-1);
else if (nb == 0 || nb == (size_t)-2)
return (nchr);
s += nb;
nms -= nb;
nchr++;
}
/*NOTREACHED*/
}
while (len-- > 0) {
if ((nb = pmbrtowc(dst, s, nms, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
} else if (nb == (size_t)-2) {
*src = s + nms;
return (nchr);
} else if (nb == 0) {
*src = NULL;
return (nchr);
}
s += nb;
nms -= nb;
nchr++;
dst++;
}
*src = s;
return (nchr);
}
diff --git a/lib/libc/locale/mbsrtowcs.c b/lib/libc/locale/mbsrtowcs.c
index 718d61c77ea4..0d7157cdd643 100644
--- a/lib/libc/locale/mbsrtowcs.c
+++ b/lib/libc/locale/mbsrtowcs.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
size_t
mbsrtowcs_l(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
mbstate_t * __restrict ps, locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->mbsrtowcs);
return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(dst, src, SIZE_T_MAX, len, ps));
}
size_t
mbsrtowcs(wchar_t * __restrict dst, const char ** __restrict src, size_t len,
mbstate_t * __restrict ps)
{
return mbsrtowcs_l(dst, src, len, ps, __get_locale());
}
diff --git a/lib/libc/locale/mbstowcs.c b/lib/libc/locale/mbstowcs.c
index 805a49b3563f..338db46185ad 100644
--- a/lib/libc/locale/mbstowcs.c
+++ b/lib/libc/locale/mbstowcs.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
size_t
mbstowcs_l(wchar_t * __restrict pwcs, const char * __restrict s, size_t n, locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
const char *sp;
FIX_LOCALE(locale);
mbs = initial;
sp = s;
return (XLOCALE_CTYPE(locale)->__mbsnrtowcs(pwcs, &sp, SIZE_T_MAX, n, &mbs));
}
size_t
mbstowcs(wchar_t * __restrict pwcs, const char * __restrict s, size_t n)
{
return mbstowcs_l(pwcs, s, n, __get_locale());
}
diff --git a/lib/libc/locale/mbtowc.c b/lib/libc/locale/mbtowc.c
index 56b9b2ba8afd..c36d1d46f1c0 100644
--- a/lib/libc/locale/mbtowc.c
+++ b/lib/libc/locale/mbtowc.c
@@ -1,68 +1,67 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
int
mbtowc_l(wchar_t * __restrict pwc, const char * __restrict s, size_t n, locale_t locale)
{
static const mbstate_t initial;
size_t rval;
FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
XLOCALE_CTYPE(locale)->mbtowc = initial;
return (0);
}
rval = XLOCALE_CTYPE(locale)->__mbrtowc(pwc, s, n,
&(XLOCALE_CTYPE(locale)->mbtowc));
switch (rval) {
case (size_t)-2:
errno = EILSEQ;
/* FALLTHROUGH */
case (size_t)-1:
return (-1);
default:
return ((int)rval);
}
}
int
mbtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n)
{
return mbtowc_l(pwc, s, n, __get_locale());
}
diff --git a/lib/libc/locale/mskanji.c b/lib/libc/locale/mskanji.c
index 3b30ed0c6027..47a55fdaf568 100644
--- a/lib/libc/locale/mskanji.c
+++ b/lib/libc/locale/mskanji.c
@@ -1,191 +1,190 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
*
* ja_JP.SJIS locale table for BSD4.4/rune
* version 1.0
* (C) Sin'ichiro MIYATANI / Phase One, Inc
* May 12, 1995
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Phase One, Inc.
* 4. The name of Phase One, Inc. may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mskanji.c 1.0 (Phase One) 5/5/95";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <runetype.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
extern int __mb_sb_limit;
static size_t _MSKanji_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _MSKanji_mbsinit(const mbstate_t *);
static size_t _MSKanji_wcrtomb(char * __restrict, wchar_t,
mbstate_t * __restrict);
static size_t _MSKanji_mbsnrtowcs(wchar_t * __restrict,
const char ** __restrict, size_t, size_t,
mbstate_t * __restrict);
static size_t _MSKanji_wcsnrtombs(char * __restrict,
const wchar_t ** __restrict, size_t, size_t,
mbstate_t * __restrict);
typedef struct {
wchar_t ch;
} _MSKanjiState;
int
_MSKanji_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
l->__mbrtowc = _MSKanji_mbrtowc;
l->__wcrtomb = _MSKanji_wcrtomb;
l->__mbsnrtowcs = _MSKanji_mbsnrtowcs;
l->__wcsnrtombs = _MSKanji_wcsnrtombs;
l->__mbsinit = _MSKanji_mbsinit;
l->runes = rl;
l->__mb_cur_max = 2;
l->__mb_sb_limit = 224;
return (0);
}
static int
_MSKanji_mbsinit(const mbstate_t *ps)
{
return (ps == NULL || ((const _MSKanjiState *)ps)->ch == 0);
}
static size_t
_MSKanji_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
mbstate_t * __restrict ps)
{
_MSKanjiState *ms;
wchar_t wc;
ms = (_MSKanjiState *)ps;
if ((ms->ch & ~0xFF) != 0) {
/* Bad conversion state. */
errno = EINVAL;
return ((size_t)-1);
}
if (s == NULL) {
s = "";
n = 1;
pwc = NULL;
}
if (n == 0)
/* Incomplete multibyte sequence */
return ((size_t)-2);
if (ms->ch != 0) {
if (*s == '\0') {
errno = EILSEQ;
return ((size_t)-1);
}
wc = (ms->ch << 8) | (*s & 0xFF);
if (pwc != NULL)
*pwc = wc;
ms->ch = 0;
return (1);
}
wc = *s++ & 0xff;
if ((wc > 0x80 && wc < 0xa0) || (wc >= 0xe0 && wc < 0xfd)) {
if (n < 2) {
/* Incomplete multibyte sequence */
ms->ch = wc;
return ((size_t)-2);
}
if (*s == '\0') {
errno = EILSEQ;
return ((size_t)-1);
}
wc = (wc << 8) | (*s++ & 0xff);
if (pwc != NULL)
*pwc = wc;
return (2);
} else {
if (pwc != NULL)
*pwc = wc;
return (wc == L'\0' ? 0 : 1);
}
}
static size_t
_MSKanji_wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
{
_MSKanjiState *ms;
int len, i;
ms = (_MSKanjiState *)ps;
if (ms->ch != 0) {
errno = EINVAL;
return ((size_t)-1);
}
if (s == NULL)
/* Reset to initial shift state (no-op) */
return (1);
len = (wc > 0x100) ? 2 : 1;
for (i = len; i-- > 0; )
*s++ = wc >> (i << 3);
return (len);
}
static size_t
_MSKanji_mbsnrtowcs(wchar_t * __restrict dst,
const char ** __restrict src, size_t nms,
size_t len, mbstate_t * __restrict ps)
{
return (__mbsnrtowcs_std(dst, src, nms, len, ps, _MSKanji_mbrtowc));
}
static size_t
_MSKanji_wcsnrtombs(char * __restrict dst,
const wchar_t ** __restrict src, size_t nwc,
size_t len, mbstate_t * __restrict ps)
{
return (__wcsnrtombs_std(dst, src, nwc, len, ps, _MSKanji_wcrtomb));
}
diff --git a/lib/libc/locale/nextwctype.c b/lib/libc/locale/nextwctype.c
index dd81cd82940e..b0416a9a1138 100644
--- a/lib/libc/locale/nextwctype.c
+++ b/lib/libc/locale/nextwctype.c
@@ -1,103 +1,102 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <runetype.h>
#include <wchar.h>
#include <wctype.h>
#include "mblocal.h"
wint_t
nextwctype_l(wint_t wc, wctype_t wct, locale_t locale)
{
size_t lim;
FIX_LOCALE(locale);
_RuneLocale *runes = XLOCALE_CTYPE(locale)->runes;
_RuneRange *rr = &runes->__runetype_ext;
_RuneEntry *base, *re;
int noinc;
noinc = 0;
if (wc < _CACHED_RUNES) {
wc++;
while (wc < _CACHED_RUNES) {
if (runes->__runetype[wc] & wct)
return (wc);
wc++;
}
wc--;
}
if (rr->__ranges != NULL && wc < rr->__ranges[0].__min) {
wc = rr->__ranges[0].__min;
noinc = 1;
}
/* Binary search -- see bsearch.c for explanation. */
base = rr->__ranges;
for (lim = rr->__nranges; lim != 0; lim >>= 1) {
re = base + (lim >> 1);
if (re->__min <= wc && wc <= re->__max)
goto found;
else if (wc > re->__max) {
base = re + 1;
lim--;
}
}
return (-1);
found:
if (!noinc)
wc++;
if (re->__min <= wc && wc <= re->__max) {
if (re->__types != NULL) {
for (; wc <= re->__max; wc++)
if (re->__types[wc - re->__min] & wct)
return (wc);
} else if (re->__map & wct)
return (wc);
}
while (++re < rr->__ranges + rr->__nranges) {
wc = re->__min;
if (re->__types != NULL) {
for (; wc <= re->__max; wc++)
if (re->__types[wc - re->__min] & wct)
return (wc);
} else if (re->__map & wct)
return (wc);
}
return (-1);
}
wint_t
nextwctype(wint_t wc, wctype_t wct)
{
return nextwctype_l(wc, wct, __get_locale());
}
diff --git a/lib/libc/locale/nl_langinfo.c b/lib/libc/locale/nl_langinfo.c
index b7055f3eaa62..7cdf2856c5bc 100644
--- a/lib/libc/locale/nl_langinfo.c
+++ b/lib/libc/locale/nl_langinfo.c
@@ -1,207 +1,206 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001, 2003 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <langinfo.h>
#include <limits.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>
#include <runetype.h>
#include <wchar.h>
#include "mblocal.h"
#include "lnumeric.h"
#include "lmessages.h"
#include "lmonetary.h"
#include "../stdtime/timelocal.h"
#define _REL(BASE) ((int)item-BASE)
char *
nl_langinfo_l(nl_item item, locale_t loc)
{
char *ret, *cs;
const char *s;
FIX_LOCALE(loc);
switch (item) {
case CODESET:
s = XLOCALE_CTYPE(loc)->runes->__encoding;
if (strcmp(s, "EUC-CN") == 0)
ret = "eucCN";
else if (strcmp(s, "EUC-JP") == 0)
ret = "eucJP";
else if (strcmp(s, "EUC-KR") == 0)
ret = "eucKR";
else if (strcmp(s, "EUC-TW") == 0)
ret = "eucTW";
else if (strcmp(s, "BIG5") == 0)
ret = "Big5";
else if (strcmp(s, "MSKanji") == 0)
ret = "SJIS";
else if (strcmp(s, "NONE") == 0)
ret = "US-ASCII";
else if (strncmp(s, "NONE:", 5) == 0)
ret = (char *)(s + 5);
else
ret = (char *)s;
break;
case D_T_FMT:
ret = (char *) __get_current_time_locale(loc)->c_fmt;
break;
case D_FMT:
ret = (char *) __get_current_time_locale(loc)->x_fmt;
break;
case T_FMT:
ret = (char *) __get_current_time_locale(loc)->X_fmt;
break;
case T_FMT_AMPM:
ret = (char *) __get_current_time_locale(loc)->ampm_fmt;
break;
case AM_STR:
ret = (char *) __get_current_time_locale(loc)->am;
break;
case PM_STR:
ret = (char *) __get_current_time_locale(loc)->pm;
break;
case DAY_1: case DAY_2: case DAY_3:
case DAY_4: case DAY_5: case DAY_6: case DAY_7:
ret = (char*) __get_current_time_locale(loc)->weekday[_REL(DAY_1)];
break;
case ABDAY_1: case ABDAY_2: case ABDAY_3:
case ABDAY_4: case ABDAY_5: case ABDAY_6: case ABDAY_7:
ret = (char*) __get_current_time_locale(loc)->wday[_REL(ABDAY_1)];
break;
case MON_1: case MON_2: case MON_3: case MON_4:
case MON_5: case MON_6: case MON_7: case MON_8:
case MON_9: case MON_10: case MON_11: case MON_12:
ret = (char*) __get_current_time_locale(loc)->month[_REL(MON_1)];
break;
case ABMON_1: case ABMON_2: case ABMON_3: case ABMON_4:
case ABMON_5: case ABMON_6: case ABMON_7: case ABMON_8:
case ABMON_9: case ABMON_10: case ABMON_11: case ABMON_12:
ret = (char*) __get_current_time_locale(loc)->mon[_REL(ABMON_1)];
break;
case ALTMON_1: case ALTMON_2: case ALTMON_3: case ALTMON_4:
case ALTMON_5: case ALTMON_6: case ALTMON_7: case ALTMON_8:
case ALTMON_9: case ALTMON_10: case ALTMON_11: case ALTMON_12:
ret = (char*)
__get_current_time_locale(loc)->alt_month[_REL(ALTMON_1)];
break;
case ERA:
/* XXX: need to be implemented */
ret = "";
break;
case ERA_D_FMT:
/* XXX: need to be implemented */
ret = "";
break;
case ERA_D_T_FMT:
/* XXX: need to be implemented */
ret = "";
break;
case ERA_T_FMT:
/* XXX: need to be implemented */
ret = "";
break;
case ALT_DIGITS:
/* XXX: need to be implemented */
ret = "";
break;
case RADIXCHAR:
ret = (char*) __get_current_numeric_locale(loc)->decimal_point;
break;
case THOUSEP:
ret = (char*) __get_current_numeric_locale(loc)->thousands_sep;
break;
case YESEXPR:
ret = (char*) __get_current_messages_locale(loc)->yesexpr;
break;
case NOEXPR:
ret = (char*) __get_current_messages_locale(loc)->noexpr;
break;
/*
* YESSTR and NOSTR items marked with LEGACY are available, but not
* recommended by SUSv2 to be used in portable applications since
* they're subject to remove in future specification editions.
*/
case YESSTR: /* LEGACY */
ret = (char*) __get_current_messages_locale(loc)->yesstr;
break;
case NOSTR: /* LEGACY */
ret = (char*) __get_current_messages_locale(loc)->nostr;
break;
/*
* SUSv2 special formatted currency string
*/
case CRNCYSTR:
ret = "";
cs = (char*) __get_current_monetary_locale(loc)->currency_symbol;
if (*cs != '\0') {
char pos = localeconv_l(loc)->p_cs_precedes;
if (pos == localeconv_l(loc)->n_cs_precedes) {
char psn = '\0';
if (pos == CHAR_MAX) {
if (strcmp(cs, __get_current_monetary_locale(loc)->mon_decimal_point) == 0)
psn = '.';
} else
psn = pos ? '-' : '+';
if (psn != '\0') {
int clen = strlen(cs);
if ((loc->csym = reallocf(loc->csym, clen + 2)) != NULL) {
*loc->csym = psn;
strcpy(loc->csym + 1, cs);
ret = loc->csym;
}
}
}
}
break;
case D_MD_ORDER: /* FreeBSD local extension */
ret = (char *) __get_current_time_locale(loc)->md_order;
break;
default:
ret = "";
}
return (ret);
}
char *
nl_langinfo(nl_item item)
{
return nl_langinfo_l(item, __get_locale());
}
diff --git a/lib/libc/locale/nomacros.c b/lib/libc/locale/nomacros.c
index 2dfdd772cfc9..680682d4447a 100644
--- a/lib/libc/locale/nomacros.c
+++ b/lib/libc/locale/nomacros.c
@@ -1,16 +1,15 @@
-#include <sys/cdefs.h>
/*
* Tell <ctype.h> to generate extern versions of all its inline
* functions. The extern versions get called if the system doesn't
* support inlines or the user defines _DONT_USE_CTYPE_INLINE_
* before including <ctype.h>.
*/
#define _EXTERNALIZE_CTYPE_INLINES_
/*
* Also make sure <runetype.h> does not generate an inline definition
* of __getCurrentRuneLocale().
*/
#define __RUNETYPE_INTERNAL
#include <ctype.h>
diff --git a/lib/libc/locale/none.c b/lib/libc/locale/none.c
index a0110f8590ec..735fe41a1b75 100644
--- a/lib/libc/locale/none.c
+++ b/lib/libc/locale/none.c
@@ -1,215 +1,214 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)none.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <runetype.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
static size_t _none_mbrtowc(wchar_t * __restrict, const char * __restrict,
size_t, mbstate_t * __restrict);
static int _none_mbsinit(const mbstate_t *);
static size_t _none_mbsnrtowcs(wchar_t * __restrict dst,
const char ** __restrict src, size_t nms, size_t len,
mbstate_t * __restrict ps __unused);
static size_t _none_wcrtomb(char * __restrict, wchar_t,
mbstate_t * __restrict);
static size_t _none_wcsnrtombs(char * __restrict, const wchar_t ** __restrict,
size_t, size_t, mbstate_t * __restrict);
/* setup defaults */
int __mb_cur_max = 1;
int __mb_sb_limit = 256; /* Expected to be <= _CACHED_RUNES */
int
_none_init(struct xlocale_ctype *l, _RuneLocale *rl)
{
l->__mbrtowc = _none_mbrtowc;
l->__mbsinit = _none_mbsinit;
l->__mbsnrtowcs = _none_mbsnrtowcs;
l->__wcrtomb = _none_wcrtomb;
l->__wcsnrtombs = _none_wcsnrtombs;
l->runes = rl;
l->__mb_cur_max = 1;
l->__mb_sb_limit = 256;
return(0);
}
static int
_none_mbsinit(const mbstate_t *ps __unused)
{
/*
* Encoding is not state dependent - we are always in the
* initial state.
*/
return (1);
}
static size_t
_none_mbrtowc(wchar_t * __restrict pwc, const char * __restrict s, size_t n,
mbstate_t * __restrict ps __unused)
{
if (s == NULL)
/* Reset to initial shift state (no-op) */
return (0);
if (n == 0)
/* Incomplete multibyte sequence */
return ((size_t)-2);
if (pwc != NULL)
*pwc = (unsigned char)*s;
return (*s == '\0' ? 0 : 1);
}
static size_t
_none_wcrtomb(char * __restrict s, wchar_t wc,
mbstate_t * __restrict ps __unused)
{
if (s == NULL)
/* Reset to initial shift state (no-op) */
return (1);
if (wc < 0 || wc > UCHAR_MAX) {
errno = EILSEQ;
return ((size_t)-1);
}
*s = (unsigned char)wc;
return (1);
}
static size_t
_none_mbsnrtowcs(wchar_t * __restrict dst, const char ** __restrict src,
size_t nms, size_t len, mbstate_t * __restrict ps __unused)
{
const char *s;
size_t nchr;
if (dst == NULL) {
s = memchr(*src, '\0', nms);
return (s != NULL ? s - *src : nms);
}
s = *src;
nchr = 0;
while (len-- > 0 && nms-- > 0) {
if ((*dst++ = (unsigned char)*s++) == L'\0') {
*src = NULL;
return (nchr);
}
nchr++;
}
*src = s;
return (nchr);
}
static size_t
_none_wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps __unused)
{
const wchar_t *s;
size_t nchr;
if (dst == NULL) {
for (s = *src; nwc > 0 && *s != L'\0'; s++, nwc--) {
if (*s < 0 || *s > UCHAR_MAX) {
errno = EILSEQ;
return ((size_t)-1);
}
}
return (s - *src);
}
s = *src;
nchr = 0;
while (len-- > 0 && nwc-- > 0) {
if (*s < 0 || *s > UCHAR_MAX) {
*src = s;
errno = EILSEQ;
return ((size_t)-1);
}
if ((*dst++ = *s++) == '\0') {
*src = NULL;
return (nchr);
}
nchr++;
}
*src = s;
return (nchr);
}
/* setup defaults */
struct xlocale_ctype __xlocale_global_ctype = {
{{0}, "C"},
(_RuneLocale*)&_DefaultRuneLocale,
_none_mbrtowc,
_none_mbsinit,
_none_mbsnrtowcs,
_none_wcrtomb,
_none_wcsnrtombs,
1, /* __mb_cur_max, */
256 /* __mb_sb_limit */
};
struct xlocale_ctype __xlocale_C_ctype = {
{{0}, "C"},
(_RuneLocale*)&_DefaultRuneLocale,
_none_mbrtowc,
_none_mbsinit,
_none_mbsnrtowcs,
_none_wcrtomb,
_none_wcsnrtombs,
1, /* __mb_cur_max, */
256 /* __mb_sb_limit */
};
diff --git a/lib/libc/locale/rpmatch.c b/lib/libc/locale/rpmatch.c
index 4826c302b827..fb778876bc30 100644
--- a/lib/libc/locale/rpmatch.c
+++ b/lib/libc/locale/rpmatch.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004-2005 Tim J. Robbins.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <langinfo.h>
#include <regex.h>
#include <stdlib.h>
int
rpmatch(const char *response)
{
regex_t yes, no;
int ret;
if (regcomp(&yes, nl_langinfo(YESEXPR), REG_EXTENDED|REG_NOSUB) != 0)
return (-1);
if (regcomp(&no, nl_langinfo(NOEXPR), REG_EXTENDED|REG_NOSUB) != 0) {
regfree(&yes);
return (-1);
}
if (regexec(&yes, response, 0, NULL, 0) == 0)
ret = 1;
else if (regexec(&no, response, 0, NULL, 0) == 0)
ret = 0;
else
ret = -1;
regfree(&yes);
regfree(&no);
return (ret);
}
diff --git a/lib/libc/locale/rune.c b/lib/libc/locale/rune.c
index 79dc4de18e25..7b2d4890a21e 100644
--- a/lib/libc/locale/rune.c
+++ b/lib/libc/locale/rune.c
@@ -1,250 +1,249 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright 2014 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rune.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <arpa/inet.h>
#include <errno.h>
#include <runetype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include "un-namespace.h"
#include "runefile.h"
_RuneLocale *
_Read_RuneMagi(const char *fname)
{
char *fdata, *data;
void *lastp;
_FileRuneLocale *frl;
_RuneLocale *rl;
_FileRuneEntry *frr;
_RuneEntry *rr;
struct stat sb;
int x, saverr;
void *variable;
_FileRuneEntry *runetype_ext_ranges;
_FileRuneEntry *maplower_ext_ranges;
_FileRuneEntry *mapupper_ext_ranges;
int runetype_ext_len = 0;
int fd;
if ((fd = _open(fname, O_RDONLY | O_CLOEXEC)) < 0) {
errno = EINVAL;
return (NULL);
}
if (_fstat(fd, &sb) < 0) {
(void) _close(fd);
errno = EINVAL;
return (NULL);
}
if ((size_t)sb.st_size < sizeof (_FileRuneLocale)) {
(void) _close(fd);
errno = EINVAL;
return (NULL);
}
fdata = mmap(NULL, sb.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
(void) _close(fd);
if (fdata == MAP_FAILED) {
errno = EINVAL;
return (NULL);
}
frl = (_FileRuneLocale *)(void *)fdata;
lastp = fdata + sb.st_size;
variable = frl + 1;
if (memcmp(frl->magic, _FILE_RUNE_MAGIC_1, sizeof (frl->magic))) {
goto invalid;
}
runetype_ext_ranges = (_FileRuneEntry *)variable;
variable = runetype_ext_ranges + frl->runetype_ext_nranges;
if (variable > lastp) {
goto invalid;
}
maplower_ext_ranges = (_FileRuneEntry *)variable;
variable = maplower_ext_ranges + frl->maplower_ext_nranges;
if (variable > lastp) {
goto invalid;
}
mapupper_ext_ranges = (_FileRuneEntry *)variable;
variable = mapupper_ext_ranges + frl->mapupper_ext_nranges;
if (variable > lastp) {
goto invalid;
}
frr = runetype_ext_ranges;
for (x = 0; x < frl->runetype_ext_nranges; ++x) {
uint32_t *types;
if (frr[x].map == 0) {
int len = frr[x].max - frr[x].min + 1;
types = variable;
variable = types + len;
runetype_ext_len += len;
if (variable > lastp) {
goto invalid;
}
}
}
if ((char *)variable + frl->variable_len > (char *)lastp) {
goto invalid;
}
/*
* Convert from disk format to host format.
*/
data = malloc(sizeof(_RuneLocale) +
(frl->runetype_ext_nranges + frl->maplower_ext_nranges +
frl->mapupper_ext_nranges) * sizeof(_RuneEntry) +
runetype_ext_len * sizeof(*rr->__types) + frl->variable_len);
if (data == NULL) {
saverr = errno;
munmap(fdata, sb.st_size);
errno = saverr;
return (NULL);
}
rl = (_RuneLocale *)data;
rl->__variable = rl + 1;
memcpy(rl->__magic, _RUNE_MAGIC_1, sizeof(rl->__magic));
memcpy(rl->__encoding, frl->encoding, sizeof(rl->__encoding));
rl->__variable_len = frl->variable_len;
rl->__runetype_ext.__nranges = frl->runetype_ext_nranges;
rl->__maplower_ext.__nranges = frl->maplower_ext_nranges;
rl->__mapupper_ext.__nranges = frl->mapupper_ext_nranges;
for (x = 0; x < _CACHED_RUNES; ++x) {
rl->__runetype[x] = frl->runetype[x];
rl->__maplower[x] = frl->maplower[x];
rl->__mapupper[x] = frl->mapupper[x];
}
rl->__runetype_ext.__ranges = (_RuneEntry *)rl->__variable;
rl->__variable = rl->__runetype_ext.__ranges +
rl->__runetype_ext.__nranges;
rl->__maplower_ext.__ranges = (_RuneEntry *)rl->__variable;
rl->__variable = rl->__maplower_ext.__ranges +
rl->__maplower_ext.__nranges;
rl->__mapupper_ext.__ranges = (_RuneEntry *)rl->__variable;
rl->__variable = rl->__mapupper_ext.__ranges +
rl->__mapupper_ext.__nranges;
variable = mapupper_ext_ranges + frl->mapupper_ext_nranges;
frr = runetype_ext_ranges;
rr = rl->__runetype_ext.__ranges;
for (x = 0; x < rl->__runetype_ext.__nranges; ++x) {
uint32_t *types;
rr[x].__min = frr[x].min;
rr[x].__max = frr[x].max;
rr[x].__map = frr[x].map;
if (rr[x].__map == 0) {
int len = rr[x].__max - rr[x].__min + 1;
types = variable;
variable = types + len;
rr[x].__types = rl->__variable;
rl->__variable = rr[x].__types + len;
while (len-- > 0)
rr[x].__types[len] = types[len];
} else
rr[x].__types = NULL;
}
frr = maplower_ext_ranges;
rr = rl->__maplower_ext.__ranges;
for (x = 0; x < rl->__maplower_ext.__nranges; ++x) {
rr[x].__min = frr[x].min;
rr[x].__max = frr[x].max;
rr[x].__map = frr[x].map;
}
frr = mapupper_ext_ranges;
rr = rl->__mapupper_ext.__ranges;
for (x = 0; x < rl->__mapupper_ext.__nranges; ++x) {
rr[x].__min = frr[x].min;
rr[x].__max = frr[x].max;
rr[x].__map = frr[x].map;
}
memcpy(rl->__variable, variable, rl->__variable_len);
munmap(fdata, sb.st_size);
/*
* Go out and zero pointers that should be zero.
*/
if (!rl->__variable_len)
rl->__variable = NULL;
if (!rl->__runetype_ext.__nranges)
rl->__runetype_ext.__ranges = NULL;
if (!rl->__maplower_ext.__nranges)
rl->__maplower_ext.__ranges = NULL;
if (!rl->__mapupper_ext.__nranges)
rl->__mapupper_ext.__ranges = NULL;
return (rl);
invalid:
munmap(fdata, sb.st_size);
errno = EINVAL;
return (NULL);
}
diff --git a/lib/libc/locale/runetype.c b/lib/libc/locale/runetype.c
index 1442c3a77fd5..e26104e97234 100644
--- a/lib/libc/locale/runetype.c
+++ b/lib/libc/locale/runetype.c
@@ -1,89 +1,88 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
#include <wchar.h>
#include "mblocal.h"
unsigned long
___runetype_l(__ct_rune_t c, locale_t locale)
{
size_t lim;
FIX_LOCALE(locale);
_RuneRange *rr = &(XLOCALE_CTYPE(locale)->runes->__runetype_ext);
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
return(0L);
/* Binary search -- see bsearch.c for explanation. */
base = rr->__ranges;
for (lim = rr->__nranges; lim != 0; lim >>= 1) {
re = base + (lim >> 1);
if (re->__min <= c && c <= re->__max) {
if (re->__types)
return(re->__types[c - re->__min]);
else
return(re->__map);
} else if (c > re->__max) {
base = re + 1;
lim--;
}
}
return(0L);
}
unsigned long
___runetype(__ct_rune_t c)
{
return ___runetype_l(c, __get_locale());
}
int ___mb_cur_max(void)
{
return XLOCALE_CTYPE(__get_locale())->__mb_cur_max;
}
int ___mb_cur_max_l(locale_t locale)
{
FIX_LOCALE(locale);
return XLOCALE_CTYPE(locale)->__mb_cur_max;
}
diff --git a/lib/libc/locale/setlocale.c b/lib/libc/locale/setlocale.c
index 53b6e635ecb7..af6fe846b0f9 100644
--- a/lib/libc/locale/setlocale.c
+++ b/lib/libc/locale/setlocale.c
@@ -1,326 +1,325 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1996 - 2002 FreeBSD Project
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setlocale.c 8.1 (Berkeley) 7/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <paths.h> /* for _PATH_LOCALE */
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "collate.h"
#include "lmonetary.h" /* for __monetary_load_locale() */
#include "lnumeric.h" /* for __numeric_load_locale() */
#include "lmessages.h" /* for __messages_load_locale() */
#include "setlocale.h"
#include "ldpart.h"
#include "../stdtime/timelocal.h" /* for __time_load_locale() */
/*
* Category names for getenv()
*/
static const char categories[_LC_LAST][12] = {
"LC_ALL",
"LC_COLLATE",
"LC_CTYPE",
"LC_MONETARY",
"LC_NUMERIC",
"LC_TIME",
"LC_MESSAGES",
};
/*
* Current locales for each category
*/
static char current_categories[_LC_LAST][ENCODING_LEN + 1] = {
"C",
"C",
"C",
"C",
"C",
"C",
"C",
};
/*
* Path to locale storage directory
*/
char *_PathLocale;
/*
* The locales we are going to try and load
*/
static char new_categories[_LC_LAST][ENCODING_LEN + 1];
static char saved_categories[_LC_LAST][ENCODING_LEN + 1];
static char current_locale_string[_LC_LAST * (ENCODING_LEN + 1/*"/"*/ + 1)];
static char *currentlocale(void);
static char *loadlocale(int);
const char *__get_locale_env(int);
char *
setlocale(int category, const char *locale)
{
int i, j, len, saverr;
const char *env, *r;
if (category < LC_ALL || category >= _LC_LAST) {
errno = EINVAL;
return (NULL);
}
if (locale == NULL)
return (category != LC_ALL ?
current_categories[category] : currentlocale());
/*
* Default to the current locale for everything.
*/
for (i = 1; i < _LC_LAST; ++i)
(void)strcpy(new_categories[i], current_categories[i]);
/*
* Now go fill up new_categories from the locale argument
*/
if (!*locale) {
if (category == LC_ALL) {
for (i = 1; i < _LC_LAST; ++i) {
env = __get_locale_env(i);
if (strlen(env) > ENCODING_LEN) {
errno = EINVAL;
return (NULL);
}
(void)strcpy(new_categories[i], env);
}
} else {
env = __get_locale_env(category);
if (strlen(env) > ENCODING_LEN) {
errno = EINVAL;
return (NULL);
}
(void)strcpy(new_categories[category], env);
}
} else if (category != LC_ALL) {
if (strlen(locale) > ENCODING_LEN) {
errno = EINVAL;
return (NULL);
}
(void)strcpy(new_categories[category], locale);
} else {
if ((r = strchr(locale, '/')) == NULL) {
if (strlen(locale) > ENCODING_LEN) {
errno = EINVAL;
return (NULL);
}
for (i = 1; i < _LC_LAST; ++i)
(void)strcpy(new_categories[i], locale);
} else {
for (i = 1; r[1] == '/'; ++r)
;
if (!r[1]) {
errno = EINVAL;
return (NULL); /* Hmm, just slashes... */
}
do {
if (i == _LC_LAST)
break; /* Too many slashes... */
if ((len = r - locale) > ENCODING_LEN) {
errno = EINVAL;
return (NULL);
}
(void)strlcpy(new_categories[i], locale,
len + 1);
i++;
while (*r == '/')
r++;
locale = r;
while (*r && *r != '/')
r++;
} while (*locale);
while (i < _LC_LAST) {
(void)strcpy(new_categories[i],
new_categories[i - 1]);
i++;
}
}
}
if (category != LC_ALL)
return (loadlocale(category));
for (i = 1; i < _LC_LAST; ++i) {
(void)strcpy(saved_categories[i], current_categories[i]);
if (loadlocale(i) == NULL) {
saverr = errno;
for (j = 1; j < i; j++) {
(void)strcpy(new_categories[j],
saved_categories[j]);
if (loadlocale(j) == NULL) {
(void)strcpy(new_categories[j], "C");
(void)loadlocale(j);
}
}
errno = saverr;
return (NULL);
}
}
return (currentlocale());
}
static char *
currentlocale(void)
{
int i;
(void)strcpy(current_locale_string, current_categories[1]);
for (i = 2; i < _LC_LAST; ++i)
if (strcmp(current_categories[1], current_categories[i])) {
for (i = 2; i < _LC_LAST; ++i) {
(void)strcat(current_locale_string, "/");
(void)strcat(current_locale_string,
current_categories[i]);
}
break;
}
return (current_locale_string);
}
static char *
loadlocale(int category)
{
char *new = new_categories[category];
char *old = current_categories[category];
int (*func) (const char *);
int saved_errno;
if ((new[0] == '.' &&
(new[1] == '\0' || (new[1] == '.' && new[2] == '\0'))) ||
strchr(new, '/') != NULL) {
errno = EINVAL;
return (NULL);
}
saved_errno = errno;
errno = __detect_path_locale();
if (errno != 0)
return (NULL);
errno = saved_errno;
switch (category) {
case LC_CTYPE:
func = __wrap_setrunelocale;
break;
case LC_COLLATE:
func = __collate_load_tables;
break;
case LC_TIME:
func = __time_load_locale;
break;
case LC_NUMERIC:
func = __numeric_load_locale;
break;
case LC_MONETARY:
func = __monetary_load_locale;
break;
case LC_MESSAGES:
func = __messages_load_locale;
break;
default:
errno = EINVAL;
return (NULL);
}
if (strcmp(new, old) == 0)
return (old);
if (func(new) != _LDP_ERROR) {
(void)strcpy(old, new);
(void)strcpy(__xlocale_global_locale.components[category-1]->locale, new);
return (old);
}
return (NULL);
}
const char *
__get_locale_env(int category)
{
const char *env;
/* 1. check LC_ALL. */
env = getenv(categories[0]);
/* 2. check LC_* */
if (env == NULL || !*env)
env = getenv(categories[category]);
/* 3. check LANG */
if (env == NULL || !*env)
env = getenv("LANG");
/* 4. if none is set, fall to "C" */
if (env == NULL || !*env)
env = "C";
return (env);
}
/*
* Detect locale storage location and store its value to _PathLocale variable
*/
int
__detect_path_locale(void)
{
if (_PathLocale == NULL) {
char *p = secure_getenv("PATH_LOCALE");
if (p != NULL) {
if (strlen(p) + 1/*"/"*/ + ENCODING_LEN +
1/*"/"*/ + CATEGORY_LEN >= PATH_MAX)
return (ENAMETOOLONG);
_PathLocale = strdup(p);
if (_PathLocale == NULL)
return (errno == 0 ? ENOMEM : errno);
} else
_PathLocale = _PATH_LOCALE;
}
return (0);
}
diff --git a/lib/libc/locale/setrunelocale.c b/lib/libc/locale/setrunelocale.c
index 8c8ef82a1193..bb89812486fa 100644
--- a/lib/libc/locale/setrunelocale.c
+++ b/lib/libc/locale/setrunelocale.c
@@ -1,224 +1,223 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define __RUNETYPE_INTERNAL 1
#include <runetype.h>
#include <errno.h>
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <wchar.h>
#include "ldpart.h"
#include "mblocal.h"
#include "setlocale.h"
#undef _CurrentRuneLocale
extern _RuneLocale const *_CurrentRuneLocale;
/*
* A cached version of the runes for this thread. Used by ctype.h
*/
_Thread_local const _RuneLocale *_ThreadRuneLocale;
extern int __mb_sb_limit;
extern _RuneLocale *_Read_RuneMagi(const char *);
static int __setrunelocale(struct xlocale_ctype *l, const char *);
static void
destruct_ctype(void *v)
{
struct xlocale_ctype *l = v;
if (&_DefaultRuneLocale != l->runes)
free(l->runes);
free(l);
}
const _RuneLocale *
__getCurrentRuneLocale(void)
{
return (XLOCALE_CTYPE(__get_locale())->runes);
}
static void
free_runes(_RuneLocale *rl)
{
if ((rl != &_DefaultRuneLocale) && (rl)) {
free(rl);
}
}
static int
__setrunelocale(struct xlocale_ctype *l, const char *encoding)
{
_RuneLocale *rl;
int ret;
char *path;
struct xlocale_ctype saved = *l;
/*
* The "C" and "POSIX" locale are always here.
*/
if (strcmp(encoding, "C") == 0 || strcmp(encoding, "POSIX") == 0) {
free_runes(saved.runes);
(void) _none_init(l, (_RuneLocale*)&_DefaultRuneLocale);
return (0);
}
/* Range checking not needed, encoding length already checked before */
if (asprintf(&path, "%s/%s/LC_CTYPE", _PathLocale, encoding) == -1)
return (errno);
if ((rl = _Read_RuneMagi(path)) == NULL) {
free(path);
errno = EINVAL;
return (errno);
}
free(path);
l->__mbrtowc = NULL;
l->__mbsinit = NULL;
l->__mbsnrtowcs = NULL;
l->__wcrtomb = NULL;
l->__wcsnrtombs = NULL;
rl->__sputrune = NULL;
rl->__sgetrune = NULL;
if (strcmp(rl->__encoding, "NONE:US-ASCII") == 0)
ret = _ascii_init(l, rl);
else if (strncmp(rl->__encoding, "NONE", 4) == 0)
ret = _none_init(l, rl);
else if (strcmp(rl->__encoding, "UTF-8") == 0)
ret = _UTF8_init(l, rl);
else if (strcmp(rl->__encoding, "EUC-CN") == 0)
ret = _EUC_CN_init(l, rl);
else if (strcmp(rl->__encoding, "EUC-JP") == 0)
ret = _EUC_JP_init(l, rl);
else if (strcmp(rl->__encoding, "EUC-KR") == 0)
ret = _EUC_KR_init(l, rl);
else if (strcmp(rl->__encoding, "EUC-TW") == 0)
ret = _EUC_TW_init(l, rl);
else if (strcmp(rl->__encoding, "GB18030") == 0)
ret = _GB18030_init(l, rl);
else if (strcmp(rl->__encoding, "GB2312") == 0)
ret = _GB2312_init(l, rl);
else if (strcmp(rl->__encoding, "GBK") == 0)
ret = _GBK_init(l, rl);
else if (strcmp(rl->__encoding, "BIG5") == 0)
ret = _BIG5_init(l, rl);
else if (strcmp(rl->__encoding, "MSKanji") == 0)
ret = _MSKanji_init(l, rl);
else
ret = EFTYPE;
if (ret == 0) {
/* Free the old runes if it exists. */
free_runes(saved.runes);
/* Reset the mbstates */
memset(&l->c16rtomb, 0, sizeof(l->c16rtomb));
memset(&l->c32rtomb, 0, sizeof(l->c32rtomb));
memset(&l->mblen, 0, sizeof(l->mblen));
memset(&l->mbrlen, 0, sizeof(l->mbrlen));
memset(&l->mbrtoc16, 0, sizeof(l->mbrtoc16));
memset(&l->mbrtoc32, 0, sizeof(l->mbrtoc32));
memset(&l->mbrtowc, 0, sizeof(l->mbrtowc));
memset(&l->mbsnrtowcs, 0, sizeof(l->mbsnrtowcs));
memset(&l->mbsrtowcs, 0, sizeof(l->mbsrtowcs));
memset(&l->mbtowc, 0, sizeof(l->mbtowc));
memset(&l->wcrtomb, 0, sizeof(l->wcrtomb));
memset(&l->wcsnrtombs, 0, sizeof(l->wcsnrtombs));
memset(&l->wcsrtombs, 0, sizeof(l->wcsrtombs));
memset(&l->wctomb, 0, sizeof(l->wctomb));
} else {
/* Restore the saved version if this failed. */
memcpy(l, &saved, sizeof(struct xlocale_ctype));
free(rl);
}
return (ret);
}
int
__wrap_setrunelocale(const char *locale)
{
int ret = __setrunelocale(&__xlocale_global_ctype, locale);
if (ret != 0) {
errno = ret;
return (_LDP_ERROR);
}
__mb_cur_max = __xlocale_global_ctype.__mb_cur_max;
__mb_sb_limit = __xlocale_global_ctype.__mb_sb_limit;
_CurrentRuneLocale = __xlocale_global_ctype.runes;
return (_LDP_LOADED);
}
void
__set_thread_rune_locale(locale_t loc)
{
if (loc == NULL) {
_ThreadRuneLocale = &_DefaultRuneLocale;
} else if (loc == LC_GLOBAL_LOCALE) {
_ThreadRuneLocale = 0;
} else {
_ThreadRuneLocale = XLOCALE_CTYPE(loc)->runes;
}
}
void *
__ctype_load(const char *locale, locale_t unused __unused)
{
struct xlocale_ctype *l = calloc(sizeof(struct xlocale_ctype), 1);
if (l == NULL)
return (NULL);
l->header.header.destructor = destruct_ctype;
if (__setrunelocale(l, locale)) {
free(l);
return (NULL);
}
return (l);
}
diff --git a/lib/libc/locale/table.c b/lib/libc/locale/table.c
index 1c6ecacbbbfa..1a14b52b0589 100644
--- a/lib/libc/locale/table.c
+++ b/lib/libc/locale/table.c
@@ -1,263 +1,262 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)table.c 8.1 (Berkeley) 6/27/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <ctype.h>
#include <runetype.h>
#include <wchar.h>
#include "mblocal.h"
const _RuneLocale _DefaultRuneLocale = {
_RUNE_MAGIC_1,
"NONE",
NULL,
NULL,
0xFFFD,
{ /*00*/ _CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
/*08*/ _CTYPE_C,
_CTYPE_C|_CTYPE_S|_CTYPE_B,
_CTYPE_C|_CTYPE_S,
_CTYPE_C|_CTYPE_S,
_CTYPE_C|_CTYPE_S,
_CTYPE_C|_CTYPE_S,
_CTYPE_C,
_CTYPE_C,
/*10*/ _CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
/*18*/ _CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
_CTYPE_C,
/*20*/ _CTYPE_S|_CTYPE_B|_CTYPE_R,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
/*28*/ _CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
/*30*/ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|0,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|1,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|2,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|3,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|4,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|5,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|6,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|7,
/*38*/ _CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|8,
_CTYPE_D|_CTYPE_R|_CTYPE_G|_CTYPE_X|_CTYPE_N|9,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
/*40*/ _CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|10,
_CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|11,
_CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|12,
_CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|13,
_CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|14,
_CTYPE_U|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|15,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
/*48*/ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
/*50*/ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
/*58*/ _CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_U|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
/*60*/ _CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|10,
_CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|11,
_CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|12,
_CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|13,
_CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|14,
_CTYPE_L|_CTYPE_X|_CTYPE_R|_CTYPE_G|_CTYPE_A|15,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
/*68*/ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
/*70*/ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
/*78*/ _CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_L|_CTYPE_R|_CTYPE_G|_CTYPE_A,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_P|_CTYPE_R|_CTYPE_G,
_CTYPE_C,
},
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 'a', 'b', 'c', 'd', 'e', 'f', 'g',
'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
'x', 'y', 'z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
},
{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
},
};
#undef _CurrentRuneLocale
const _RuneLocale *_CurrentRuneLocale = &_DefaultRuneLocale;
_RuneLocale *
__runes_for_locale(locale_t locale, int *mb_sb_limit)
{
FIX_LOCALE(locale);
struct xlocale_ctype *c = XLOCALE_CTYPE(locale);
*mb_sb_limit = c->__mb_sb_limit;
return c->runes;
}
diff --git a/lib/libc/locale/tolower.c b/lib/libc/locale/tolower.c
index 59cd24393a22..0401147705c6 100644
--- a/lib/libc/locale/tolower.c
+++ b/lib/libc/locale/tolower.c
@@ -1,76 +1,75 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
#include <wchar.h>
#include "mblocal.h"
__ct_rune_t
___tolower_l(__ct_rune_t c, locale_t l)
{
size_t lim;
FIX_LOCALE(l);
_RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__maplower_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
return(c);
/* Binary search -- see bsearch.c for explanation. */
base = rr->__ranges;
for (lim = rr->__nranges; lim != 0; lim >>= 1) {
re = base + (lim >> 1);
if (re->__min <= c && c <= re->__max)
return (re->__map + c - re->__min);
else if (c > re->__max) {
base = re + 1;
lim--;
}
}
return(c);
}
__ct_rune_t
___tolower(__ct_rune_t c)
{
return ___tolower_l(c, __get_locale());
}
diff --git a/lib/libc/locale/toupper.c b/lib/libc/locale/toupper.c
index 6de0c76860bd..bff6c5bf32e3 100644
--- a/lib/libc/locale/toupper.c
+++ b/lib/libc/locale/toupper.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <stdio.h>
#include <runetype.h>
#include <wchar.h>
#include "mblocal.h"
__ct_rune_t
___toupper_l(__ct_rune_t c, locale_t l)
{
size_t lim;
FIX_LOCALE(l);
_RuneRange *rr = &XLOCALE_CTYPE(l)->runes->__mapupper_ext;
_RuneEntry *base, *re;
if (c < 0 || c == EOF)
return(c);
/* Binary search -- see bsearch.c for explanation. */
base = rr->__ranges;
for (lim = rr->__nranges; lim != 0; lim >>= 1) {
re = base + (lim >> 1);
if (re->__min <= c && c <= re->__max)
{
return (re->__map + c - re->__min);
}
else if (c > re->__max) {
base = re + 1;
lim--;
}
}
return(c);
}
__ct_rune_t
___toupper(__ct_rune_t c)
{
return ___toupper_l(c, __get_locale());
}
diff --git a/lib/libc/locale/wcrtomb.c b/lib/libc/locale/wcrtomb.c
index 83321e4a41c9..ef7d502486b8 100644
--- a/lib/libc/locale/wcrtomb.c
+++ b/lib/libc/locale/wcrtomb.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include "mblocal.h"
size_t
wcrtomb_l(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps,
locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->wcrtomb);
return (XLOCALE_CTYPE(locale)->__wcrtomb(s, wc, ps));
}
size_t
wcrtomb(char * __restrict s, wchar_t wc, mbstate_t * __restrict ps)
{
return wcrtomb_l(s, wc, ps, __get_locale());
}
diff --git a/lib/libc/locale/wcsftime.c b/lib/libc/locale/wcsftime.c
index ce67d35846e8..f77b4e9a33f8 100644
--- a/lib/libc/locale/wcsftime.c
+++ b/lib/libc/locale/wcsftime.c
@@ -1,122 +1,121 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <time.h>
#include <wchar.h>
#include "xlocale_private.h"
/*
* Convert date and time to a wide-character string.
*
* This is the wide-character counterpart of strftime(). So that we do not
* have to duplicate the code of strftime(), we convert the format string to
* multibyte, call strftime(), then convert the result back into wide
* characters.
*
* This technique loses in the presence of stateful multibyte encoding if any
* of the conversions in the format string change conversion state. When
* stateful encoding is implemented, we will need to reset the state between
* format specifications in the format string.
*/
size_t
wcsftime_l(wchar_t * __restrict wcs, size_t maxsize,
const wchar_t * __restrict format, const struct tm * __restrict timeptr,
locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
char *dst, *sformat;
const char *dstp;
const wchar_t *formatp;
size_t n, sflen;
int sverrno;
FIX_LOCALE(locale);
sformat = dst = NULL;
/*
* Convert the supplied format string to a multibyte representation
* for strftime(), which only handles single-byte characters.
*/
mbs = initial;
formatp = format;
sflen = wcsrtombs_l(NULL, &formatp, 0, &mbs, locale);
if (sflen == (size_t)-1)
goto error;
if ((sformat = malloc(sflen + 1)) == NULL)
goto error;
mbs = initial;
wcsrtombs_l(sformat, &formatp, sflen + 1, &mbs, locale);
/*
* Allocate memory for longest multibyte sequence that will fit
* into the caller's buffer and call strftime() to fill it.
* Then, copy and convert the result back into wide characters in
* the caller's buffer.
*/
if (SIZE_T_MAX / MB_CUR_MAX <= maxsize) {
/* maxsize is prepostorously large - avoid int. overflow. */
errno = EINVAL;
goto error;
}
if ((dst = malloc(maxsize * MB_CUR_MAX)) == NULL)
goto error;
if (strftime_l(dst, maxsize, sformat, timeptr, locale) == 0)
goto error;
dstp = dst;
mbs = initial;
n = mbsrtowcs_l(wcs, &dstp, maxsize, &mbs, locale);
if (n == (size_t)-2 || n == (size_t)-1 || dstp != NULL)
goto error;
free(sformat);
free(dst);
return (n);
error:
sverrno = errno;
free(sformat);
free(dst);
errno = sverrno;
return (0);
}
size_t
wcsftime(wchar_t * __restrict wcs, size_t maxsize,
const wchar_t * __restrict format, const struct tm * __restrict timeptr)
{
return wcsftime_l(wcs, maxsize, format, timeptr, __get_locale());
}
diff --git a/lib/libc/locale/wcsnrtombs.c b/lib/libc/locale/wcsnrtombs.c
index fc47c1c7cce2..b7c7738bd85f 100644
--- a/lib/libc/locale/wcsnrtombs.c
+++ b/lib/libc/locale/wcsnrtombs.c
@@ -1,125 +1,124 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2013 Garrett D'Amore <garrett@damore.org>
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
size_t
wcsnrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
size_t len, mbstate_t * __restrict ps, locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->wcsnrtombs);
return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, nwc, len, ps));
}
size_t
wcsnrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t nwc,
size_t len, mbstate_t * __restrict ps)
{
return wcsnrtombs_l(dst, src, nwc, len, ps, __get_locale());
}
size_t
__wcsnrtombs_std(char * __restrict dst, const wchar_t ** __restrict src,
size_t nwc, size_t len, mbstate_t * __restrict ps,
wcrtomb_pfn_t pwcrtomb)
{
mbstate_t mbsbak;
char buf[MB_LEN_MAX];
const wchar_t *s;
size_t nbytes;
size_t nb;
s = *src;
nbytes = 0;
if (dst == NULL) {
while (nwc-- > 0) {
if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1)
/* Invalid character - wcrtomb() sets errno. */
return ((size_t)-1);
else if (*s == L'\0')
return (nbytes + nb - 1);
s++;
nbytes += nb;
}
return (nbytes);
}
while (len > 0 && nwc-- > 0) {
if (len > (size_t)MB_CUR_MAX) {
/* Enough space to translate in-place. */
if ((nb = pwcrtomb(dst, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
} else {
/*
* May not be enough space; use temp. buffer.
*
* We need to save a copy of the conversion state
* here so we can restore it if the multibyte
* character is too long for the buffer.
*/
mbsbak = *ps;
if ((nb = pwcrtomb(buf, *s, ps)) == (size_t)-1) {
*src = s;
return ((size_t)-1);
}
if (nb > (int)len) {
/* MB sequence for character won't fit. */
*ps = mbsbak;
break;
}
memcpy(dst, buf, nb);
}
if (*s == L'\0') {
*src = NULL;
return (nbytes + nb - 1);
}
s++;
dst += nb;
len -= nb;
nbytes += nb;
}
*src = s;
return (nbytes);
}
diff --git a/lib/libc/locale/wcsrtombs.c b/lib/libc/locale/wcsrtombs.c
index 2e472f1a0ff9..f949d9331abb 100644
--- a/lib/libc/locale/wcsrtombs.c
+++ b/lib/libc/locale/wcsrtombs.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "mblocal.h"
size_t
wcsrtombs_l(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
mbstate_t * __restrict ps, locale_t locale)
{
FIX_LOCALE(locale);
if (ps == NULL)
ps = &(XLOCALE_CTYPE(locale)->wcsrtombs);
return (XLOCALE_CTYPE(locale)->__wcsnrtombs(dst, src, SIZE_T_MAX, len, ps));
}
size_t
wcsrtombs(char * __restrict dst, const wchar_t ** __restrict src, size_t len,
mbstate_t * __restrict ps)
{
return wcsrtombs_l(dst, src, len, ps, __get_locale());
}
diff --git a/lib/libc/locale/wcstod.c b/lib/libc/locale/wcstod.c
index 570bf4474ff4..94a5ff4612a5 100644
--- a/lib/libc/locale/wcstod.c
+++ b/lib/libc/locale/wcstod.c
@@ -1,116 +1,115 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* Convert a string to a double-precision number.
*
* This is the wide-character counterpart of strtod(). So that we do not
* have to duplicate the code of strtod() here, we convert the supplied
* wide character string to multibyte and call strtod() on the result.
* This assumes that the multibyte encoding is compatible with ASCII
* for at least the digits, radix character and letters.
*/
double
wcstod_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
double val;
char *buf, *end;
const wchar_t *wcp;
size_t len;
size_t spaces;
FIX_LOCALE(locale);
wcp = nptr;
spaces = 0;
while (iswspace_l(*wcp, locale)) {
wcp++;
spaces++;
}
/*
* Convert the supplied numeric wide char. string to multibyte.
*
* We could attempt to find the end of the numeric portion of the
* wide char. string to avoid converting unneeded characters but
* choose not to bother; optimising the uncommon case where
* the input string contains a lot of text after the number
* duplicates a lot of strtod()'s functionality and slows down the
* most common cases.
*/
mbs = initial;
if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
}
if ((buf = malloc(len + 1)) == NULL) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
}
mbs = initial;
wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
/* Let strtod() do most of the work for us. */
val = strtod_l(buf, &end, locale);
/*
* We only know where the number ended in the _multibyte_
* representation of the string. If the caller wants to know
* where it ended, count multibyte characters to find the
* corresponding position in the wide char string.
*/
if (endptr != NULL) {
*endptr = (wchar_t *)nptr + (end - buf);
if (buf != end)
*endptr += spaces;
}
free(buf);
return (val);
}
double
wcstod(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
{
return wcstod_l(nptr, endptr, __get_locale());
}
diff --git a/lib/libc/locale/wcstof.c b/lib/libc/locale/wcstof.c
index 2d35f0b82f25..0c2c7946e89b 100644
--- a/lib/libc/locale/wcstof.c
+++ b/lib/libc/locale/wcstof.c
@@ -1,93 +1,92 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002, 2003 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
float
wcstof_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
float val;
char *buf, *end;
const wchar_t *wcp;
size_t len;
size_t spaces;
FIX_LOCALE(locale);
wcp = nptr;
spaces = 0;
while (iswspace_l(*wcp, locale)) {
wcp++;
spaces++;
}
mbs = initial;
if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
}
if ((buf = malloc(len + 1)) == NULL) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
}
mbs = initial;
wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
val = strtof_l(buf, &end, locale);
if (endptr != NULL) {
*endptr = (wchar_t *)nptr + (end - buf);
if (buf != end)
*endptr += spaces;
}
free(buf);
return (val);
}
float
wcstof(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
{
return wcstof_l(nptr, endptr, __get_locale());
}
diff --git a/lib/libc/locale/wcstoimax.c b/lib/libc/locale/wcstoimax.c
index 5ed949cd0531..2c0997e7ea91 100644
--- a/lib/libc/locale/wcstoimax.c
+++ b/lib/libc/locale/wcstoimax.c
@@ -1,147 +1,146 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "from @(#)strtol.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoimax.c,v 1.8 2002/09/06 11:23:59 tjr Exp ");
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* Convert a wide character string to an intmax_t integer.
*/
intmax_t
wcstoimax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == L'+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == L'0' && (*s == L'x' || *s == L'X') &&
((s[1] >= L'0' && s[1] <= L'9') ||
(s[1] >= L'A' && s[1] <= L'F') ||
(s[1] >= L'a' && s[1] <= L'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == L'0' && (*s == L'b' || *s == L'B') &&
(s[1] >= L'0' && s[1] <= L'1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == L'0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = neg ? (uintmax_t)-(INTMAX_MIN + INTMAX_MAX) + INTMAX_MAX
: INTMAX_MAX;
cutlim = cutoff % base;
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
if (iswdigit_l(c, locale))
c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
c -= L'0';
else if (c >= L'A' && c <= L'Z')
c -= L'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= L'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? INTMAX_MIN : INTMAX_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
intmax_t
wcstoimax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base)
{
return wcstoimax_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/locale/wcstol.c b/lib/libc/locale/wcstol.c
index 1678b615ca1c..2b83187347c2 100644
--- a/lib/libc/locale/wcstol.c
+++ b/lib/libc/locale/wcstol.c
@@ -1,140 +1,139 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* Convert a string to a long integer.
*/
long
wcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int
base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == L'+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == L'0' && (*s == L'x' || *s == L'X') &&
((s[1] >= L'0' && s[1] <= L'9') ||
(s[1] >= L'A' && s[1] <= L'F') ||
(s[1] >= L'a' && s[1] <= L'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == L'0' && (*s == L'b' || *s == L'B') &&
(s[1] >= L'0' && s[1] <= L'1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == L'0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
: LONG_MAX;
cutlim = cutoff % base;
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
if (iswdigit_l(c, locale))
c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
c -= L'0';
else if (c >= L'A' && c <= L'Z')
c -= L'A' - 10;
else if (c >= L'a' && c <= L'z')
c -= L'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
long
wcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
{
return wcstol_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/locale/wcstold.c b/lib/libc/locale/wcstold.c
index dc15631a22f0..1fe7c26ff79a 100644
--- a/lib/libc/locale/wcstold.c
+++ b/lib/libc/locale/wcstold.c
@@ -1,93 +1,92 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002, 2003 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* See wcstod() for comments as to the logic used.
*/
long double
wcstold_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
long double val;
char *buf, *end;
const wchar_t *wcp;
size_t len;
size_t spaces;
FIX_LOCALE(locale);
wcp = nptr;
spaces = 0;
while (iswspace_l(*wcp, locale)) {
wcp++;
spaces++;
}
mbs = initial;
if ((len = wcsrtombs_l(NULL, &wcp, 0, &mbs, locale)) == (size_t)-1) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
}
if ((buf = malloc(len + 1)) == NULL) {
if (endptr != NULL)
*endptr = (wchar_t *)nptr;
return (0.0);
}
mbs = initial;
wcsrtombs_l(buf, &wcp, len + 1, &mbs, locale);
val = strtold_l(buf, &end, locale);
if (endptr != NULL) {
*endptr = (wchar_t *)nptr + (end - buf);
if (buf != end)
*endptr += spaces;
}
free(buf);
return (val);
}
long double
wcstold(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr)
{
return wcstold_l(nptr, endptr, __get_locale());
}
diff --git a/lib/libc/locale/wcstoll.c b/lib/libc/locale/wcstoll.c
index ef1e6ef58861..1712c6be3f56 100644
--- a/lib/libc/locale/wcstoll.c
+++ b/lib/libc/locale/wcstoll.c
@@ -1,146 +1,145 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.19 2002/09/06 11:23:59 tjr Exp ");
#endif
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* Convert a wide character string to a long long integer.
*/
long long
wcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtoll for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == L'+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == L'0' && (*s == L'x' || *s == L'X') &&
((s[1] >= L'0' && s[1] <= L'9') ||
(s[1] >= L'A' && s[1] <= L'F') ||
(s[1] >= L'a' && s[1] <= L'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == L'0' && (*s == L'b' || *s == L'B') &&
(s[1] >= L'0' && s[1] <= L'1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == L'0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
: LLONG_MAX;
cutlim = cutoff % base;
cutoff /= base;
for ( ; ; c = *s++) {
#ifdef notyet
if (iswdigit_l(c, locale))
c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
c -= L'0';
else if (c >= L'A' && c <= L'Z')
c -= L'A' - 10;
else if (c >= L'a' && c <= L'z')
c -= L'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LLONG_MIN : LLONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
long long
wcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
{
return wcstoll_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/locale/wcstombs.c b/lib/libc/locale/wcstombs.c
index 0b9303cd79e1..962614bf88f3 100644
--- a/lib/libc/locale/wcstombs.c
+++ b/lib/libc/locale/wcstombs.c
@@ -1,58 +1,57 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
size_t
wcstombs_l(char * __restrict s, const wchar_t * __restrict pwcs, size_t n,
locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs;
const wchar_t *pwcsp;
FIX_LOCALE(locale);
mbs = initial;
pwcsp = pwcs;
return (XLOCALE_CTYPE(locale)->__wcsnrtombs(s, &pwcsp, SIZE_T_MAX, n, &mbs));
}
size_t
wcstombs(char * __restrict s, const wchar_t * __restrict pwcs, size_t n)
{
return wcstombs_l(s, pwcs, n, __get_locale());
}
diff --git a/lib/libc/locale/wcstoul.c b/lib/libc/locale/wcstoul.c
index 2c9c8820b1f6..b4fa4d439e10 100644
--- a/lib/libc/locale/wcstoul.c
+++ b/lib/libc/locale/wcstoul.c
@@ -1,138 +1,137 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long integer.
*/
unsigned long
wcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base, locale_t locale)
{
const wchar_t *s;
unsigned long acc;
wchar_t c;
unsigned long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == L'+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == L'0' && (*s == L'x' || *s == L'X') &&
((s[1] >= L'0' && s[1] <= L'9') ||
(s[1] >= L'A' && s[1] <= L'F') ||
(s[1] >= L'a' && s[1] <= L'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == L'0' && (*s == L'b' || *s == L'B') &&
(s[1] >= L'0' && s[1] <= L'1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == L'0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = ULONG_MAX / base;
cutlim = ULONG_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
if (iswdigit_l(c, locale))
c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
c -= L'0';
else if (c >= L'A' && c <= L'Z')
c -= L'A' - 10;
else if (c >= L'a' && c <= L'z')
c -= L'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
unsigned long
wcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
{
return wcstoul_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/locale/wcstoull.c b/lib/libc/locale/wcstoull.c
index 692eb90eef6b..b2edd3d9cea1 100644
--- a/lib/libc/locale/wcstoull.c
+++ b/lib/libc/locale/wcstoull.c
@@ -1,145 +1,144 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoull.c,v 1.18 2002/09/06 11:23:59 tjr Exp ");
#endif
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* Convert a wide character string to an unsigned long long integer.
*/
unsigned long long
wcstoull_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base, locale_t locale)
{
const wchar_t *s;
unsigned long long acc;
wchar_t c;
unsigned long long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtoull for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == L'+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == L'0' && (*s == L'x' || *s == L'X') &&
((s[1] >= L'0' && s[1] <= L'9') ||
(s[1] >= L'A' && s[1] <= L'F') ||
(s[1] >= L'a' && s[1] <= L'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == L'0' && (*s == L'b' || *s == L'B') &&
(s[1] >= L'0' && s[1] <= L'1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == L'0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = ULLONG_MAX / base;
cutlim = ULLONG_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
if (iswdigit_l(c, locale))
c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
c -= L'0';
else if (c >= L'A' && c <= L'Z')
c -= L'A' - 10;
else if (c >= L'a' && c <= L'z')
c -= L'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULLONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
unsigned long long
wcstoull(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base)
{
return wcstoull_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/locale/wcstoumax.c b/lib/libc/locale/wcstoumax.c
index c4f2ec3aaf41..bf517965ba3e 100644
--- a/lib/libc/locale/wcstoumax.c
+++ b/lib/libc/locale/wcstoumax.c
@@ -1,145 +1,144 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "from @(#)strtoul.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoumax.c,v 1.8 2002/09/06 11:23:59 tjr Exp ");
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include "xlocale_private.h"
/*
* Convert a wide character string to a uintmax_t integer.
*/
uintmax_t
wcstoumax_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base, locale_t locale)
{
const wchar_t *s;
uintmax_t acc;
wchar_t c;
uintmax_t cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (iswspace_l(c, locale));
if (c == L'-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == L'+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == L'0' && (*s == L'x' || *s == L'X') &&
((s[1] >= L'0' && s[1] <= L'9') ||
(s[1] >= L'A' && s[1] <= L'F') ||
(s[1] >= L'a' && s[1] <= L'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == L'0' && (*s == L'b' || *s == L'B') &&
(s[1] >= L'0' && s[1] <= L'1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == L'0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = UINTMAX_MAX / base;
cutlim = UINTMAX_MAX % base;
for ( ; ; c = *s++) {
#ifdef notyet
if (iswdigit_l(c, locale))
c = digittoint_l(c, locale);
else
#endif
if (c >= L'0' && c <= L'9')
c -= L'0';
else if (c >= L'A' && c <= L'Z')
c -= L'A' - 10;
else if (c >= L'a' && c <= L'z')
c -= L'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = UINTMAX_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (wchar_t *)(any ? s - 1 : nptr);
return (acc);
}
uintmax_t
wcstoumax(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
int base)
{
return wcstoumax_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/locale/wctob.c b/lib/libc/locale/wctob.c
index d3c9318cc70d..9ae1aa003331 100644
--- a/lib/libc/locale/wctob.c
+++ b/lib/libc/locale/wctob.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stdio.h>
#include <wchar.h>
#include "mblocal.h"
int
wctob_l(wint_t c, locale_t locale)
{
static const mbstate_t initial;
mbstate_t mbs = initial;
char buf[MB_LEN_MAX];
FIX_LOCALE(locale);
if (c == WEOF || XLOCALE_CTYPE(locale)->__wcrtomb(buf, c, &mbs) != 1)
return (EOF);
return ((unsigned char)*buf);
}
int
wctob(wint_t c)
{
return wctob_l(c, __get_locale());
}
diff --git a/lib/libc/locale/wctomb.c b/lib/libc/locale/wctomb.c
index 72bce6567b76..7138ae7df3a2 100644
--- a/lib/libc/locale/wctomb.c
+++ b/lib/libc/locale/wctomb.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <wchar.h>
#include "mblocal.h"
int
wctomb_l(char *s, wchar_t wchar, locale_t locale)
{
static const mbstate_t initial;
size_t rval;
FIX_LOCALE(locale);
if (s == NULL) {
/* No support for state dependent encodings. */
XLOCALE_CTYPE(locale)->wctomb = initial;
return (0);
}
if ((rval = XLOCALE_CTYPE(locale)->__wcrtomb(s, wchar,
&(XLOCALE_CTYPE(locale)->wctomb))) == (size_t)-1)
return (-1);
return ((int)rval);
}
int
wctomb(char *s, wchar_t wchar)
{
return wctomb_l(s, wchar, __get_locale());
}
diff --git a/lib/libc/locale/wctrans.c b/lib/libc/locale/wctrans.c
index 947629a8bad8..9d2371814560 100644
--- a/lib/libc/locale/wctrans.c
+++ b/lib/libc/locale/wctrans.c
@@ -1,101 +1,100 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <string.h>
#include <wctype.h>
#include "xlocale_private.h"
enum {
_WCT_ERROR = 0,
_WCT_TOLOWER = 1,
_WCT_TOUPPER = 2
};
wint_t
towctrans_l(wint_t wc, wctrans_t desc, locale_t locale)
{
switch (desc) {
case _WCT_TOLOWER:
wc = towlower_l(wc, locale);
break;
case _WCT_TOUPPER:
wc = towupper_l(wc, locale);
break;
case _WCT_ERROR:
default:
errno = EINVAL;
break;
}
return (wc);
}
wint_t
towctrans(wint_t wc, wctrans_t desc)
{
return towctrans_l(wc, desc, __get_locale());
}
/*
* wctrans() calls this will a 0 locale. If this is ever modified to actually
* use the locale, wctrans() must be modified to call __get_locale().
*/
wctrans_t
wctrans_l(const char *charclass, locale_t locale)
{
struct {
const char *name;
wctrans_t trans;
} ccls[] = {
{ "tolower", _WCT_TOLOWER },
{ "toupper", _WCT_TOUPPER },
{ NULL, _WCT_ERROR }, /* Default */
};
int i;
i = 0;
while (ccls[i].name != NULL && strcmp(ccls[i].name, charclass) != 0)
i++;
if (ccls[i].trans == _WCT_ERROR)
errno = EINVAL;
return (ccls[i].trans);
}
wctrans_t
wctrans(const char *charclass)
{
return wctrans_l(charclass, 0);
}
diff --git a/lib/libc/locale/wctype.c b/lib/libc/locale/wctype.c
index a738a075f982..1b3ac054bc0b 100644
--- a/lib/libc/locale/wctype.c
+++ b/lib/libc/locale/wctype.c
@@ -1,115 +1,114 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <string.h>
#include <wctype.h>
#include <xlocale.h>
#undef iswctype
int
iswctype(wint_t wc, wctype_t charclass)
{
return (__istype(wc, charclass));
}
int
iswctype_l(wint_t wc, wctype_t charclass, locale_t locale)
{
return __istype_l(wc, charclass, locale);
}
/*
* IMPORTANT: The 0 in the call to this function in wctype() must be changed to
* __get_locale() if wctype_l() is ever modified to actually use the locale
* parameter.
*/
wctype_t
wctype_l(const char *property, locale_t locale)
{
const char *propnames =
"alnum\0"
"alpha\0"
"blank\0"
"cntrl\0"
"digit\0"
"graph\0"
"lower\0"
"print\0"
"punct\0"
"space\0"
"upper\0"
"xdigit\0"
"ideogram\0" /* BSD extension */
"special\0" /* BSD extension */
"phonogram\0" /* BSD extension */
"number\0" /* BSD extension */
"rune\0"; /* BSD extension */
static const wctype_t propmasks[] = {
_CTYPE_A|_CTYPE_N,
_CTYPE_A,
_CTYPE_B,
_CTYPE_C,
_CTYPE_D,
_CTYPE_G,
_CTYPE_L,
_CTYPE_R,
_CTYPE_P,
_CTYPE_S,
_CTYPE_U,
_CTYPE_X,
_CTYPE_I,
_CTYPE_T,
_CTYPE_Q,
_CTYPE_N,
0xFFFFFF00L
};
size_t len1, len2;
const char *p;
const wctype_t *q;
len1 = strlen(property);
q = propmasks;
for (p = propnames; (len2 = strlen(p)) != 0; p += len2 + 1) {
if (len1 == len2 && memcmp(property, p, len1) == 0)
return (*q);
q++;
}
return (0UL);
}
wctype_t wctype(const char *property)
{
return wctype_l(property, 0);
}
diff --git a/lib/libc/locale/wcwidth.c b/lib/libc/locale/wcwidth.c
index 4c256033ac47..118680d4f2bd 100644
--- a/lib/libc/locale/wcwidth.c
+++ b/lib/libc/locale/wcwidth.c
@@ -1,61 +1,60 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include <wctype.h>
#include <xlocale.h>
#undef wcwidth
int
wcwidth(wchar_t wc)
{
return (__wcwidth(wc));
}
int
wcwidth_l(wchar_t wc, locale_t locale)
{
return (__wcwidth_l(wc, locale));
}
diff --git a/lib/libc/nameser/ns_name.c b/lib/libc/nameser/ns_name.c
index ffe3b9716ab3..7ac49cb2dbcc 100644
--- a/lib/libc/nameser/ns_name.c
+++ b/lib/libc/nameser/ns_name.c
@@ -1,1156 +1,1155 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#ifndef lint
static const char rcsid[] = "$Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <resolv.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <limits.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
#define NS_TYPE_ELT 0x40 /*%< EDNS0 extended label type */
#define DNS_LABELTYPE_BITSTRING 0x41
/* Data. */
static const char digits[] = "0123456789";
static const char digitvalue[256] = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*16*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*32*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*48*/
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, /*64*/
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*80*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*96*/
-1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*112*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*128*/
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /*256*/
};
/* Forward. */
static int special(int);
static int printable(int);
static int dn_find(const u_char *, const u_char *,
const u_char * const *,
const u_char * const *);
static int encode_bitsring(const char **, const char *,
unsigned char **, unsigned char **,
unsigned const char *);
static int labellen(const u_char *);
static int decode_bitstring(const unsigned char **,
char *, const char *);
/* Public. */
/*%
* Convert an encoded domain name to printable ascii as per RFC1035.
* return:
*\li Number of bytes written to buffer, or -1 (with errno set)
*
* notes:
*\li The root is returned as "."
*\li All other domains are returned in non absolute form
*/
int
ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
{
const u_char *cp;
char *dn, *eom;
u_char c;
u_int n;
int l;
cp = src;
dn = dst;
eom = dst + dstsiz;
while ((n = *cp++) != 0) {
if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
/* Some kind of compression pointer. */
errno = EMSGSIZE;
return (-1);
}
if (dn != dst) {
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '.';
}
if ((l = labellen(cp - 1)) < 0) {
errno = EMSGSIZE; /*%< XXX */
return (-1);
}
if (dn + l >= eom) {
errno = EMSGSIZE;
return (-1);
}
if ((n & NS_CMPRSFLGS) == NS_TYPE_ELT) {
int m;
if (n != DNS_LABELTYPE_BITSTRING) {
/* XXX: labellen should reject this case */
errno = EINVAL;
return (-1);
}
if ((m = decode_bitstring(&cp, dn, eom)) < 0)
{
errno = EMSGSIZE;
return (-1);
}
dn += m;
continue;
}
for ((void)NULL; l > 0; l--) {
c = *cp++;
if (special(c)) {
if (dn + 1 >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '\\';
*dn++ = (char)c;
} else if (!printable(c)) {
if (dn + 3 >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '\\';
*dn++ = digits[c / 100];
*dn++ = digits[(c % 100) / 10];
*dn++ = digits[c % 10];
} else {
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = (char)c;
}
}
}
if (dn == dst) {
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '.';
}
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
*dn++ = '\0';
return (dn - dst);
}
/*%
* Convert a ascii string into an encoded domain name as per RFC1035.
*
* return:
*
*\li -1 if it fails
*\li 1 if string was fully qualified
*\li 0 is string was not fully qualified
*
* notes:
*\li Enforces label and domain length limits.
*/
int
ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
return (ns_name_pton2(src, dst, dstsiz, NULL));
}
/*
* ns_name_pton2(src, dst, dstsiz, *dstlen)
* Convert a ascii string into an encoded domain name as per RFC1035.
* return:
* -1 if it fails
* 1 if string was fully qualified
* 0 is string was not fully qualified
* side effects:
* fills in *dstlen (if non-NULL)
* notes:
* Enforces label and domain length limits.
*/
int
ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) {
u_char *label, *bp, *eom;
int c, n, escaped, e = 0;
char *cp;
escaped = 0;
bp = dst;
eom = dst + dstsiz;
label = bp++;
while ((c = *src++) != 0) {
if (escaped) {
if (c == '[') { /*%< start a bit string label */
if ((cp = strchr(src, ']')) == NULL) {
errno = EINVAL; /*%< ??? */
return (-1);
}
if ((e = encode_bitsring(&src, cp + 2,
&label, &bp, eom))
!= 0) {
errno = e;
return (-1);
}
escaped = 0;
label = bp++;
if ((c = *src++) == 0)
goto done;
else if (c != '.') {
errno = EINVAL;
return (-1);
}
continue;
}
else if ((cp = strchr(digits, c)) != NULL) {
n = (cp - digits) * 100;
if ((c = *src++) == 0 ||
(cp = strchr(digits, c)) == NULL) {
errno = EMSGSIZE;
return (-1);
}
n += (cp - digits) * 10;
if ((c = *src++) == 0 ||
(cp = strchr(digits, c)) == NULL) {
errno = EMSGSIZE;
return (-1);
}
n += (cp - digits);
if (n > 255) {
errno = EMSGSIZE;
return (-1);
}
c = n;
}
escaped = 0;
} else if (c == '\\') {
escaped = 1;
continue;
} else if (c == '.') {
c = (bp - label - 1);
if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
errno = EMSGSIZE;
return (-1);
}
if (label >= eom) {
errno = EMSGSIZE;
return (-1);
}
*label = c;
/* Fully qualified ? */
if (*src == '\0') {
if (c != 0) {
if (bp >= eom) {
errno = EMSGSIZE;
return (-1);
}
*bp++ = '\0';
}
if ((bp - dst) > MAXCDNAME) {
errno = EMSGSIZE;
return (-1);
}
if (dstlen != NULL)
*dstlen = (bp - dst);
return (1);
}
if (c == 0 || *src == '.') {
errno = EMSGSIZE;
return (-1);
}
label = bp++;
continue;
}
if (bp >= eom) {
errno = EMSGSIZE;
return (-1);
}
*bp++ = (u_char)c;
}
c = (bp - label - 1);
if ((c & NS_CMPRSFLGS) != 0) { /*%< Label too big. */
errno = EMSGSIZE;
return (-1);
}
done:
if (label >= eom) {
errno = EMSGSIZE;
return (-1);
}
*label = c;
if (c != 0) {
if (bp >= eom) {
errno = EMSGSIZE;
return (-1);
}
*bp++ = 0;
}
if ((bp - dst) > MAXCDNAME) { /*%< src too big */
errno = EMSGSIZE;
return (-1);
}
if (dstlen != NULL)
*dstlen = (bp - dst);
return (0);
}
/*%
* Convert a network strings labels into all lowercase.
*
* return:
*\li Number of bytes written to buffer, or -1 (with errno set)
*
* notes:
*\li Enforces label and domain length limits.
*/
int
ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
{
const u_char *cp;
u_char *dn, *eom;
u_char c;
u_int n;
int l;
cp = src;
dn = dst;
eom = dst + dstsiz;
if (dn >= eom) {
errno = EMSGSIZE;
return (-1);
}
while ((n = *cp++) != 0) {
if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
/* Some kind of compression pointer. */
errno = EMSGSIZE;
return (-1);
}
*dn++ = n;
if ((l = labellen(cp - 1)) < 0) {
errno = EMSGSIZE;
return (-1);
}
if (dn + l >= eom) {
errno = EMSGSIZE;
return (-1);
}
for ((void)NULL; l > 0; l--) {
c = *cp++;
if (isascii(c) && isupper(c))
*dn++ = tolower(c);
else
*dn++ = c;
}
}
*dn++ = '\0';
return (dn - dst);
}
/*%
* Unpack a domain name from a message, source may be compressed.
*
* return:
*\li -1 if it fails, or consumed octets if it succeeds.
*/
int
ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
u_char *dst, size_t dstsiz)
{
return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL));
}
/*
* ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen)
* Unpack a domain name from a message, source may be compressed.
* return:
* -1 if it fails, or consumed octets if it succeeds.
* side effect:
* fills in *dstlen (if non-NULL).
*/
int
ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src,
u_char *dst, size_t dstsiz, size_t *dstlen)
{
const u_char *srcp, *dstlim;
u_char *dstp;
int n, len, checked, l;
len = -1;
checked = 0;
dstp = dst;
srcp = src;
dstlim = dst + dstsiz;
if (srcp < msg || srcp >= eom) {
errno = EMSGSIZE;
return (-1);
}
/* Fetch next label in domain name. */
while ((n = *srcp++) != 0) {
/* Check for indirection. */
switch (n & NS_CMPRSFLGS) {
case 0:
case NS_TYPE_ELT:
/* Limit checks. */
if ((l = labellen(srcp - 1)) < 0) {
errno = EMSGSIZE;
return (-1);
}
if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
errno = EMSGSIZE;
return (-1);
}
checked += l + 1;
*dstp++ = n;
memcpy(dstp, srcp, l);
dstp += l;
srcp += l;
break;
case NS_CMPRSFLGS:
if (srcp >= eom) {
errno = EMSGSIZE;
return (-1);
}
if (len < 0)
len = srcp - src + 1;
l = ((n & 0x3f) << 8) | (*srcp & 0xff);
if (l >= eom - msg) { /*%< Out of range. */
errno = EMSGSIZE;
return (-1);
}
srcp = msg + l;
checked += 2;
/*
* Check for loops in the compressed name;
* if we've looked at the whole message,
* there must be a loop.
*/
if (checked >= eom - msg) {
errno = EMSGSIZE;
return (-1);
}
break;
default:
errno = EMSGSIZE;
return (-1); /*%< flag error */
}
}
*dstp++ = 0;
if (dstlen != NULL)
*dstlen = dstp - dst;
if (len < 0)
len = srcp - src;
return (len);
}
/*%
* Pack domain name 'domain' into 'comp_dn'.
*
* return:
*\li Size of the compressed name, or -1.
*
* notes:
*\li 'dnptrs' is an array of pointers to previous compressed names.
*\li dnptrs[0] is a pointer to the beginning of the message. The array
* ends with NULL.
*\li 'lastdnptr' is a pointer to the end of the array pointed to
* by 'dnptrs'.
*
* Side effects:
*\li The list of pointers in dnptrs is updated for labels inserted into
* the message as we compress the name. If 'dnptr' is NULL, we don't
* try to compress names. If 'lastdnptr' is NULL, we don't update the
* list.
*/
int
ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
const u_char **dnptrs, const u_char **lastdnptr)
{
u_char *dstp;
const u_char **cpp, **lpp, *eob, *msg;
const u_char *srcp;
int n, l, first = 1;
srcp = src;
dstp = dst;
eob = dstp + dstsiz;
lpp = cpp = NULL;
if (dnptrs != NULL) {
if ((msg = *dnptrs++) != NULL) {
for (cpp = dnptrs; *cpp != NULL; cpp++)
(void)NULL;
lpp = cpp; /*%< end of list to search */
}
} else
msg = NULL;
/* make sure the domain we are about to add is legal */
l = 0;
do {
int l0;
n = *srcp;
if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
errno = EMSGSIZE;
return (-1);
}
if ((l0 = labellen(srcp)) < 0) {
errno = EINVAL;
return (-1);
}
l += l0 + 1;
if (l > MAXCDNAME) {
errno = EMSGSIZE;
return (-1);
}
srcp += l0 + 1;
} while (n != 0);
/* from here on we need to reset compression pointer array on error */
srcp = src;
do {
/* Look to see if we can use pointers. */
n = *srcp;
if (n != 0 && msg != NULL) {
l = dn_find(srcp, msg, (const u_char * const *)dnptrs,
(const u_char * const *)lpp);
if (l >= 0) {
if (dstp + 1 >= eob) {
goto cleanup;
}
*dstp++ = (l >> 8) | NS_CMPRSFLGS;
*dstp++ = l % 256;
return (dstp - dst);
}
/* Not found, save it. */
if (lastdnptr != NULL && cpp < lastdnptr - 1 &&
(dstp - msg) < 0x4000 && first) {
*cpp++ = dstp;
*cpp = NULL;
first = 0;
}
}
/* copy label to buffer */
if ((n & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
/* Should not happen. */
goto cleanup;
}
n = labellen(srcp);
if (dstp + 1 + n >= eob) {
goto cleanup;
}
memcpy(dstp, srcp, n + 1);
srcp += n + 1;
dstp += n + 1;
} while (n != 0);
if (dstp > eob) {
cleanup:
if (msg != NULL)
*lpp = NULL;
errno = EMSGSIZE;
return (-1);
}
return (dstp - dst);
}
/*%
* Expand compressed domain name to presentation format.
*
* return:
*\li Number of bytes read out of `src', or -1 (with errno set).
*
* note:
*\li Root domain returns as "." not "".
*/
int
ns_name_uncompress(const u_char *msg, const u_char *eom, const u_char *src,
char *dst, size_t dstsiz)
{
u_char tmp[NS_MAXCDNAME];
int n;
if ((n = ns_name_unpack(msg, eom, src, tmp, sizeof tmp)) == -1)
return (-1);
if (ns_name_ntop(tmp, dst, dstsiz) == -1)
return (-1);
return (n);
}
/*%
* Compress a domain name into wire format, using compression pointers.
*
* return:
*\li Number of bytes consumed in `dst' or -1 (with errno set).
*
* notes:
*\li 'dnptrs' is an array of pointers to previous compressed names.
*\li dnptrs[0] is a pointer to the beginning of the message.
*\li The list ends with NULL. 'lastdnptr' is a pointer to the end of the
* array pointed to by 'dnptrs'. Side effect is to update the list of
* pointers for labels inserted into the message as we compress the name.
*\li If 'dnptr' is NULL, we don't try to compress names. If 'lastdnptr'
* is NULL, we don't update the list.
*/
int
ns_name_compress(const char *src, u_char *dst, size_t dstsiz,
const u_char **dnptrs, const u_char **lastdnptr)
{
u_char tmp[NS_MAXCDNAME];
if (ns_name_pton(src, tmp, sizeof tmp) == -1)
return (-1);
return (ns_name_pack(tmp, dst, dstsiz, dnptrs, lastdnptr));
}
/*%
* Reset dnptrs so that there are no active references to pointers at or
* after src.
*/
void
ns_name_rollback(const u_char *src, const u_char **dnptrs,
const u_char **lastdnptr)
{
while (dnptrs < lastdnptr && *dnptrs != NULL) {
if (*dnptrs >= src) {
*dnptrs = NULL;
break;
}
dnptrs++;
}
}
/*%
* Advance *ptrptr to skip over the compressed name it points at.
*
* return:
*\li 0 on success, -1 (with errno set) on failure.
*/
int
ns_name_skip(const u_char **ptrptr, const u_char *eom)
{
const u_char *cp;
u_int n;
int l = 0;
cp = *ptrptr;
while (cp < eom && (n = *cp++) != 0) {
/* Check for indirection. */
switch (n & NS_CMPRSFLGS) {
case 0: /*%< normal case, n == len */
cp += n;
continue;
case NS_TYPE_ELT: /*%< EDNS0 extended label */
if (cp < eom && (l = labellen(cp - 1)) < 0) {
errno = EMSGSIZE; /*%< XXX */
return (-1);
}
cp += l;
continue;
case NS_CMPRSFLGS: /*%< indirection */
cp++;
break;
default: /*%< illegal type */
errno = EMSGSIZE;
return (-1);
}
break;
}
if (cp > eom) {
errno = EMSGSIZE;
return (-1);
}
*ptrptr = cp;
return (0);
}
/* Find the number of octets an nname takes up, including the root label.
* (This is basically ns_name_skip() without compression-pointer support.)
* ((NOTE: can only return zero if passed-in namesiz argument is zero.))
*/
ssize_t
ns_name_length(ns_nname_ct nname, size_t namesiz) {
ns_nname_ct orig = nname;
u_int n;
while (namesiz-- > 0 && (n = *nname++) != 0) {
if ((n & NS_CMPRSFLGS) != 0) {
errno = EISDIR;
return (-1);
}
if (n > namesiz) {
errno = EMSGSIZE;
return (-1);
}
nname += n;
namesiz -= n;
}
return (nname - orig);
}
/* Compare two nname's for equality. Return -1 on error (setting errno).
*/
int
ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) {
ns_nname_ct ae = a + as, be = b + bs;
int ac, bc;
while (ac = *a, bc = *b, ac != 0 && bc != 0) {
if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) {
errno = EISDIR;
return (-1);
}
if (a + ac >= ae || b + bc >= be) {
errno = EMSGSIZE;
return (-1);
}
if (ac != bc || strncasecmp((const char *) ++a,
(const char *) ++b, ac) != 0)
return (0);
a += ac, b += bc;
}
return (ac == 0 && bc == 0);
}
/* Is domain "A" owned by (at or below) domain "B"?
*/
int
ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) {
/* If A is shorter, it cannot be owned by B. */
if (an < bn)
return (0);
/* If they are unequal before the length of the shorter, A cannot... */
while (bn > 0) {
if (a->len != b->len ||
strncasecmp((const char *) a->base,
(const char *) b->base, a->len) != 0)
return (0);
a++, an--;
b++, bn--;
}
/* A might be longer or not, but either way, B owns it. */
return (1);
}
/* Build an array of <base,len> tuples from an nname, top-down order.
* Return the number of tuples (labels) thus discovered.
*/
int
ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) {
u_int n;
int l;
n = *nname++;
namelen--;
/* Root zone? */
if (n == 0) {
/* Extra data follows name? */
if (namelen > 0) {
errno = EMSGSIZE;
return (-1);
}
return (0);
}
/* Compression pointer? */
if ((n & NS_CMPRSFLGS) != 0) {
errno = EISDIR;
return (-1);
}
/* Label too long? */
if (n > namelen) {
errno = EMSGSIZE;
return (-1);
}
/* Recurse to get rest of name done first. */
l = ns_name_map(nname + n, namelen - n, map, mapsize);
if (l < 0)
return (-1);
/* Too many labels? */
if (l >= mapsize) {
errno = ENAMETOOLONG;
return (-1);
}
/* We're on our way back up-stack, store current map data. */
map[l].base = nname;
map[l].len = n;
return (l + 1);
}
/* Count the labels in a domain name. Root counts, so COM. has two. This
* is to make the result comparable to the result of ns_name_map().
*/
int
ns_name_labels(ns_nname_ct nname, size_t namesiz) {
int ret = 0;
u_int n;
while (namesiz-- > 0 && (n = *nname++) != 0) {
if ((n & NS_CMPRSFLGS) != 0) {
errno = EISDIR;
return (-1);
}
if (n > namesiz) {
errno = EMSGSIZE;
return (-1);
}
nname += n;
namesiz -= n;
ret++;
}
return (ret + 1);
}
/* Private. */
/*%
* Thinking in noninternationalized USASCII (per the DNS spec),
* is this characted special ("in need of quoting") ?
*
* return:
*\li boolean.
*/
static int
special(int ch) {
switch (ch) {
case 0x22: /*%< '"' */
case 0x2E: /*%< '.' */
case 0x3B: /*%< ';' */
case 0x5C: /*%< '\\' */
case 0x28: /*%< '(' */
case 0x29: /*%< ')' */
/* Special modifiers in zone files. */
case 0x40: /*%< '@' */
case 0x24: /*%< '$' */
return (1);
default:
return (0);
}
}
/*%
* Thinking in noninternationalized USASCII (per the DNS spec),
* is this character visible and not a space when printed ?
*
* return:
*\li boolean.
*/
static int
printable(int ch) {
return (ch > 0x20 && ch < 0x7f);
}
/*%
* Thinking in noninternationalized USASCII (per the DNS spec),
* convert this character to lower case if it's upper case.
*/
static int
mklower(int ch) {
if (ch >= 0x41 && ch <= 0x5A)
return (ch + 0x20);
return (ch);
}
/*%
* Search for the counted-label name in an array of compressed names.
*
* return:
*\li offset from msg if found, or -1.
*
* notes:
*\li dnptrs is the pointer to the first name on the list,
*\li not the pointer to the start of the message.
*/
static int
dn_find(const u_char *domain, const u_char *msg,
const u_char * const *dnptrs,
const u_char * const *lastdnptr)
{
const u_char *dn, *cp, *sp;
const u_char * const *cpp;
u_int n;
for (cpp = dnptrs; cpp < lastdnptr; cpp++) {
sp = *cpp;
/*
* terminate search on:
* root label
* compression pointer
* unusable offset
*/
while (*sp != 0 && (*sp & NS_CMPRSFLGS) == 0 &&
(sp - msg) < 0x4000) {
dn = domain;
cp = sp;
while ((n = *cp++) != 0) {
/*
* check for indirection
*/
switch (n & NS_CMPRSFLGS) {
case 0: /*%< normal case, n == len */
n = labellen(cp - 1); /*%< XXX */
if (n != *dn++)
goto next;
for ((void)NULL; n > 0; n--)
if (mklower(*dn++) !=
mklower(*cp++))
goto next;
/* Is next root for both ? */
if (*dn == '\0' && *cp == '\0')
return (sp - msg);
if (*dn)
continue;
goto next;
case NS_CMPRSFLGS: /*%< indirection */
cp = msg + (((n & 0x3f) << 8) | *cp);
break;
default: /*%< illegal type */
errno = EMSGSIZE;
return (-1);
}
}
next: ;
sp += *sp + 1;
}
}
errno = ENOENT;
return (-1);
}
static int
decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
{
const unsigned char *cp = *cpp;
char *beg = dn, tc;
int b, blen, plen, i;
if ((blen = (*cp & 0xff)) == 0)
blen = 256;
plen = (blen + 3) / 4;
plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
if (dn + plen >= eom)
return (-1);
cp++;
i = SPRINTF((dn, "\\[x"));
if (i < 0)
return (-1);
dn += i;
for (b = blen; b > 7; b -= 8, cp++) {
i = SPRINTF((dn, "%02x", *cp & 0xff));
if (i < 0)
return (-1);
dn += i;
}
if (b > 4) {
tc = *cp++;
i = SPRINTF((dn, "%02x", tc & (0xff << (8 - b))));
if (i < 0)
return (-1);
dn += i;
} else if (b > 0) {
tc = *cp++;
i = SPRINTF((dn, "%1x",
((tc >> 4) & 0x0f) & (0x0f << (4 - b))));
if (i < 0)
return (-1);
dn += i;
}
i = SPRINTF((dn, "/%d]", blen));
if (i < 0)
return (-1);
dn += i;
*cpp = cp;
return (dn - beg);
}
static int
encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
unsigned char ** dst, unsigned const char *eom)
{
int afterslash = 0;
const char *cp = *bp;
unsigned char *tp;
char c;
const char *beg_blen;
char *end_blen = NULL;
int value = 0, count = 0, tbcount = 0, blen = 0;
beg_blen = end_blen = NULL;
/* a bitstring must contain at least 2 characters */
if (end - cp < 2)
return (EINVAL);
/* XXX: currently, only hex strings are supported */
if (*cp++ != 'x')
return (EINVAL);
if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
return (EINVAL);
for (tp = *dst + 1; cp < end && tp < eom; cp++) {
switch((c = *cp)) {
case ']': /*%< end of the bitstring */
if (afterslash) {
if (beg_blen == NULL)
return (EINVAL);
blen = (int)strtol(beg_blen, &end_blen, 10);
if (*end_blen != ']')
return (EINVAL);
}
if (count)
*tp++ = ((value << 4) & 0xff);
cp++; /*%< skip ']' */
goto done;
case '/':
afterslash = 1;
break;
default:
if (afterslash) {
if (!isdigit(c&0xff))
return (EINVAL);
if (beg_blen == NULL) {
if (c == '0') {
/* blen never begings with 0 */
return (EINVAL);
}
beg_blen = cp;
}
} else {
if (!isxdigit(c&0xff))
return (EINVAL);
value <<= 4;
value += digitvalue[(int)c];
count += 4;
tbcount += 4;
if (tbcount > 256)
return (EINVAL);
if (count == 8) {
*tp++ = value;
count = 0;
}
}
break;
}
}
done:
if (cp >= end || tp >= eom)
return (EMSGSIZE);
/*
* bit length validation:
* If a <length> is present, the number of digits in the <bit-data>
* MUST be just sufficient to contain the number of bits specified
* by the <length>. If there are insignificant bits in a final
* hexadecimal or octal digit, they MUST be zero.
* RFC2673, Section 3.2.
*/
if (blen > 0) {
int traillen;
if (((blen + 3) & ~3) != tbcount)
return (EINVAL);
traillen = tbcount - blen; /*%< between 0 and 3 */
if (((value << (8 - traillen)) & 0xff) != 0)
return (EINVAL);
}
else
blen = tbcount;
if (blen == 256)
blen = 0;
/* encode the type and the significant bit fields */
**labelp = DNS_LABELTYPE_BITSTRING;
**dst = blen;
*bp = cp;
*dst = tp;
return (0);
}
static int
labellen(const u_char *lp)
{
int bitlen;
u_char l = *lp;
if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
/* should be avoided by the caller */
return (-1);
}
if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
if (l == DNS_LABELTYPE_BITSTRING) {
if ((bitlen = *(lp + 1)) == 0)
bitlen = 256;
return ((bitlen + 7 ) / 8 + 1);
}
return (-1); /*%< unknown ELT */
}
return (l);
}
/*! \file */
diff --git a/lib/libc/nameser/ns_netint.c b/lib/libc/nameser/ns_netint.c
index 02e2d485f3f7..4340467ffe1f 100644
--- a/lib/libc/nameser/ns_netint.c
+++ b/lib/libc/nameser/ns_netint.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#ifndef lint
static const char rcsid[] = "$Id: ns_netint.c,v 1.3 2005/04/27 04:56:40 sra Exp $";
#endif
-#include <sys/cdefs.h>
/* Import. */
#include "port_before.h"
#include <arpa/nameser.h>
#include "port_after.h"
/* Public. */
u_int
ns_get16(const u_char *src) {
u_int dst;
NS_GET16(dst, src);
return (dst);
}
u_long
ns_get32(const u_char *src) {
u_long dst;
NS_GET32(dst, src);
return (dst);
}
void
ns_put16(u_int src, u_char *dst) {
NS_PUT16(src, dst);
}
void
ns_put32(u_long src, u_char *dst) {
NS_PUT32(src, dst);
}
/*! \file */
diff --git a/lib/libc/nameser/ns_parse.c b/lib/libc/nameser/ns_parse.c
index d475b92cd5fc..c3c0fc02a10f 100644
--- a/lib/libc/nameser/ns_parse.c
+++ b/lib/libc/nameser/ns_parse.c
@@ -1,277 +1,276 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#ifndef lint
static const char rcsid[] = "$Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp $";
#endif
-#include <sys/cdefs.h>
/* Import. */
#include "port_before.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <resolv.h>
#include <string.h>
#include "port_after.h"
/* Forward. */
static void setsection(ns_msg *msg, ns_sect sect);
/* Macros. */
#if !defined(SOLARIS2) || defined(__COVERITY__)
#define RETERR(err) do { errno = (err); return (-1); } while (0)
#else
#define RETERR(err) \
do { errno = (err); if (errno == errno) return (-1); } while (0)
#endif
#define PARSE_FMT_PRESO 0 /* Parse using presentation-format names */
#define PARSE_FMT_WIRE 1 /* Parse using network-format names */
/* Public. */
/* These need to be in the same order as the nres.h:ns_flag enum. */
struct _ns_flagdata _ns_flagdata[16] = {
{ 0x8000, 15 }, /*%< qr. */
{ 0x7800, 11 }, /*%< opcode. */
{ 0x0400, 10 }, /*%< aa. */
{ 0x0200, 9 }, /*%< tc. */
{ 0x0100, 8 }, /*%< rd. */
{ 0x0080, 7 }, /*%< ra. */
{ 0x0040, 6 }, /*%< z. */
{ 0x0020, 5 }, /*%< ad. */
{ 0x0010, 4 }, /*%< cd. */
{ 0x000f, 0 }, /*%< rcode. */
{ 0x0000, 0 }, /*%< expansion (1/6). */
{ 0x0000, 0 }, /*%< expansion (2/6). */
{ 0x0000, 0 }, /*%< expansion (3/6). */
{ 0x0000, 0 }, /*%< expansion (4/6). */
{ 0x0000, 0 }, /*%< expansion (5/6). */
{ 0x0000, 0 }, /*%< expansion (6/6). */
};
int ns_msg_getflag(ns_msg handle, int flag) {
return(((handle)._flags & _ns_flagdata[flag].mask) >> _ns_flagdata[flag].shift);
}
int
ns_skiprr(const u_char *ptr, const u_char *eom, ns_sect section, int count) {
const u_char *optr = ptr;
for ((void)NULL; count > 0; count--) {
int b, rdlength;
b = dn_skipname(ptr, eom);
if (b < 0)
RETERR(EMSGSIZE);
ptr += b/*Name*/ + NS_INT16SZ/*Type*/ + NS_INT16SZ/*Class*/;
if (section != ns_s_qd) {
if (ptr + NS_INT32SZ + NS_INT16SZ > eom)
RETERR(EMSGSIZE);
ptr += NS_INT32SZ/*TTL*/;
NS_GET16(rdlength, ptr);
ptr += rdlength/*RData*/;
}
}
if (ptr > eom)
RETERR(EMSGSIZE);
return (ptr - optr);
}
int
ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
const u_char *eom = msg + msglen;
int i;
handle->_msg = msg;
handle->_eom = eom;
if (msg + NS_INT16SZ > eom)
RETERR(EMSGSIZE);
NS_GET16(handle->_id, msg);
if (msg + NS_INT16SZ > eom)
RETERR(EMSGSIZE);
NS_GET16(handle->_flags, msg);
for (i = 0; i < ns_s_max; i++) {
if (msg + NS_INT16SZ > eom)
RETERR(EMSGSIZE);
NS_GET16(handle->_counts[i], msg);
}
for (i = 0; i < ns_s_max; i++)
if (handle->_counts[i] == 0)
handle->_sections[i] = NULL;
else {
int b = ns_skiprr(msg, eom, (ns_sect)i,
handle->_counts[i]);
if (b < 0)
return (-1);
handle->_sections[i] = msg;
msg += b;
}
if (msg != eom)
RETERR(EMSGSIZE);
setsection(handle, ns_s_max);
return (0);
}
int
ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
int b;
int tmp;
/* Make section right. */
tmp = section;
if (tmp < 0 || section >= ns_s_max)
RETERR(ENODEV);
if (section != handle->_sect)
setsection(handle, section);
/* Make rrnum right. */
if (rrnum == -1)
rrnum = handle->_rrnum;
if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
RETERR(ENODEV);
if (rrnum < handle->_rrnum)
setsection(handle, section);
if (rrnum > handle->_rrnum) {
b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
rrnum - handle->_rrnum);
if (b < 0)
return (-1);
handle->_msg_ptr += b;
handle->_rrnum = rrnum;
}
/* Do the parse. */
b = dn_expand(handle->_msg, handle->_eom,
handle->_msg_ptr, rr->name, NS_MAXDNAME);
if (b < 0)
return (-1);
handle->_msg_ptr += b;
if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
RETERR(EMSGSIZE);
NS_GET16(rr->type, handle->_msg_ptr);
NS_GET16(rr->rr_class, handle->_msg_ptr);
if (section == ns_s_qd) {
rr->ttl = 0;
rr->rdlength = 0;
rr->rdata = NULL;
} else {
if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
RETERR(EMSGSIZE);
NS_GET32(rr->ttl, handle->_msg_ptr);
NS_GET16(rr->rdlength, handle->_msg_ptr);
if (handle->_msg_ptr + rr->rdlength > handle->_eom)
RETERR(EMSGSIZE);
rr->rdata = handle->_msg_ptr;
handle->_msg_ptr += rr->rdlength;
}
if (++handle->_rrnum > handle->_counts[(int)section])
setsection(handle, (ns_sect)((int)section + 1));
/* All done. */
return (0);
}
/*
* This is identical to the above but uses network-format (uncompressed) names.
*/
int
ns_parserr2(ns_msg *handle, ns_sect section, int rrnum, ns_rr2 *rr) {
int b;
int tmp;
/* Make section right. */
if ((tmp = section) < 0 || section >= ns_s_max)
RETERR(ENODEV);
if (section != handle->_sect)
setsection(handle, section);
/* Make rrnum right. */
if (rrnum == -1)
rrnum = handle->_rrnum;
if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
RETERR(ENODEV);
if (rrnum < handle->_rrnum)
setsection(handle, section);
if (rrnum > handle->_rrnum) {
b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
rrnum - handle->_rrnum);
if (b < 0)
return (-1);
handle->_msg_ptr += b;
handle->_rrnum = rrnum;
}
/* Do the parse. */
b = ns_name_unpack2(handle->_msg, handle->_eom, handle->_msg_ptr,
rr->nname, NS_MAXNNAME, &rr->nnamel);
if (b < 0)
return (-1);
handle->_msg_ptr += b;
if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
RETERR(EMSGSIZE);
NS_GET16(rr->type, handle->_msg_ptr);
NS_GET16(rr->rr_class, handle->_msg_ptr);
if (section == ns_s_qd) {
rr->ttl = 0;
rr->rdlength = 0;
rr->rdata = NULL;
} else {
if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
RETERR(EMSGSIZE);
NS_GET32(rr->ttl, handle->_msg_ptr);
NS_GET16(rr->rdlength, handle->_msg_ptr);
if (handle->_msg_ptr + rr->rdlength > handle->_eom)
RETERR(EMSGSIZE);
rr->rdata = handle->_msg_ptr;
handle->_msg_ptr += rr->rdlength;
}
if (++handle->_rrnum > handle->_counts[(int)section])
setsection(handle, (ns_sect)((int)section + 1));
/* All done. */
return (0);
}
/* Private. */
static void
setsection(ns_msg *msg, ns_sect sect) {
msg->_sect = sect;
if (sect == ns_s_max) {
msg->_rrnum = -1;
msg->_msg_ptr = NULL;
} else {
msg->_rrnum = 0;
msg->_msg_ptr = msg->_sections[(int)sect];
}
}
/*! \file */
diff --git a/lib/libc/nameser/ns_print.c b/lib/libc/nameser/ns_print.c
index 84e8873bb62e..a419c668c1b5 100644
--- a/lib/libc/nameser/ns_print.c
+++ b/lib/libc/nameser/ns_print.c
@@ -1,1254 +1,1253 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#ifndef lint
static const char rcsid[] = "$Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp $";
#endif
-#include <sys/cdefs.h>
/* Import. */
#include "port_before.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#ifdef _LIBC
#include <assert.h>
#define INSIST(cond) assert(cond)
#else
#include <isc/assertions.h>
#include <isc/dst.h>
#endif
#include <errno.h>
#include <resolv.h>
#include <string.h>
#include <ctype.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
/* Forward. */
static size_t prune_origin(const char *name, const char *origin);
static int charstr(const u_char *rdata, const u_char *edata,
char **buf, size_t *buflen);
static int addname(const u_char *msg, size_t msglen,
const u_char **p, const char *origin,
char **buf, size_t *buflen);
static void addlen(size_t len, char **buf, size_t *buflen);
static int addstr(const char *src, size_t len,
char **buf, size_t *buflen);
static int addtab(size_t len, size_t target, int spaced,
char **buf, size_t *buflen);
/* Macros. */
#define T(x) \
do { \
if ((x) < 0) \
return (-1); \
} while (0)
static const char base32hex[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
/* Public. */
/*%
* Convert an RR to presentation format.
*
* return:
*\li Number of characters written to buf, or -1 (check errno).
*/
int
ns_sprintrr(const ns_msg *handle, const ns_rr *rr,
const char *name_ctx, const char *origin,
char *buf, size_t buflen)
{
int n;
n = ns_sprintrrf(ns_msg_base(*handle), ns_msg_size(*handle),
ns_rr_name(*rr), ns_rr_class(*rr), ns_rr_type(*rr),
ns_rr_ttl(*rr), ns_rr_rdata(*rr), ns_rr_rdlen(*rr),
name_ctx, origin, buf, buflen);
return (n);
}
/*%
* Convert the fields of an RR into presentation format.
*
* return:
*\li Number of characters written to buf, or -1 (check errno).
*/
int
ns_sprintrrf(const u_char *msg, size_t msglen,
const char *name, ns_class class, ns_type type,
u_long ttl, const u_char *rdata, size_t rdlen,
const char *name_ctx, const char *origin,
char *buf, size_t buflen)
{
const char *obuf = buf;
const u_char *edata = rdata + rdlen;
int spaced = 0;
const char *comment;
char tmp[100];
int len, x;
/*
* Owner.
*/
if (name_ctx != NULL && ns_samename(name_ctx, name) == 1) {
T(addstr("\t\t\t", 3, &buf, &buflen));
} else {
len = prune_origin(name, origin);
if (*name == '\0') {
goto root;
} else if (len == 0) {
T(addstr("@\t\t\t", 4, &buf, &buflen));
} else {
T(addstr(name, len, &buf, &buflen));
/* Origin not used or not root, and no trailing dot? */
if (((origin == NULL || origin[0] == '\0') ||
(origin[0] != '.' && origin[1] != '\0' &&
name[len] == '\0')) && name[len - 1] != '.') {
root:
T(addstr(".", 1, &buf, &buflen));
len++;
}
T(spaced = addtab(len, 24, spaced, &buf, &buflen));
}
}
/*
* TTL, Class, Type.
*/
T(x = ns_format_ttl(ttl, buf, buflen));
addlen(x, &buf, &buflen);
len = SPRINTF((tmp, " %s %s", p_class(class), p_type(type)));
T(addstr(tmp, len, &buf, &buflen));
T(spaced = addtab(x + len, 16, spaced, &buf, &buflen));
/*
* RData.
*/
switch (type) {
case ns_t_a:
if (rdlen != (size_t)NS_INADDRSZ)
goto formerr;
(void) inet_ntop(AF_INET, rdata, buf, buflen);
addlen(strlen(buf), &buf, &buflen);
break;
case ns_t_cname:
case ns_t_mb:
case ns_t_mg:
case ns_t_mr:
case ns_t_ns:
case ns_t_ptr:
case ns_t_dname:
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
case ns_t_hinfo:
case ns_t_isdn:
/* First word. */
T(len = charstr(rdata, edata, &buf, &buflen));
if (len == 0)
goto formerr;
rdata += len;
T(addstr(" ", 1, &buf, &buflen));
/* Second word, optional in ISDN records. */
if (type == ns_t_isdn && rdata == edata)
break;
T(len = charstr(rdata, edata, &buf, &buflen));
if (len == 0)
goto formerr;
rdata += len;
break;
case ns_t_soa: {
u_long t;
/* Server name. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" ", 1, &buf, &buflen));
/* Administrator name. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" (\n", 3, &buf, &buflen));
spaced = 0;
if ((edata - rdata) != 5*NS_INT32SZ)
goto formerr;
/* Serial number. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
len = SPRINTF((tmp, "%lu", t));
T(addstr(tmp, len, &buf, &buflen));
T(spaced = addtab(len, 16, spaced, &buf, &buflen));
T(addstr("; serial\n", 9, &buf, &buflen));
spaced = 0;
/* Refresh interval. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
T(len = ns_format_ttl(t, buf, buflen));
addlen(len, &buf, &buflen);
T(spaced = addtab(len, 16, spaced, &buf, &buflen));
T(addstr("; refresh\n", 10, &buf, &buflen));
spaced = 0;
/* Retry interval. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
T(len = ns_format_ttl(t, buf, buflen));
addlen(len, &buf, &buflen);
T(spaced = addtab(len, 16, spaced, &buf, &buflen));
T(addstr("; retry\n", 8, &buf, &buflen));
spaced = 0;
/* Expiry. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
T(len = ns_format_ttl(t, buf, buflen));
addlen(len, &buf, &buflen);
T(spaced = addtab(len, 16, spaced, &buf, &buflen));
T(addstr("; expiry\n", 9, &buf, &buflen));
spaced = 0;
/* Minimum TTL. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
T(addstr("\t\t\t\t\t", 5, &buf, &buflen));
T(len = ns_format_ttl(t, buf, buflen));
addlen(len, &buf, &buflen);
T(addstr(" )", 2, &buf, &buflen));
T(spaced = addtab(len, 16, spaced, &buf, &buflen));
T(addstr("; minimum\n", 10, &buf, &buflen));
break;
}
case ns_t_mx:
case ns_t_afsdb:
case ns_t_rt:
case ns_t_kx: {
u_int t;
if (rdlen < (size_t)NS_INT16SZ)
goto formerr;
/* Priority. */
t = ns_get16(rdata);
rdata += NS_INT16SZ;
len = SPRINTF((tmp, "%u ", t));
T(addstr(tmp, len, &buf, &buflen));
/* Target. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
}
case ns_t_px: {
u_int t;
if (rdlen < (size_t)NS_INT16SZ)
goto formerr;
/* Priority. */
t = ns_get16(rdata);
rdata += NS_INT16SZ;
len = SPRINTF((tmp, "%u ", t));
T(addstr(tmp, len, &buf, &buflen));
/* Name1. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" ", 1, &buf, &buflen));
/* Name2. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
}
case ns_t_x25:
T(len = charstr(rdata, edata, &buf, &buflen));
if (len == 0)
goto formerr;
rdata += len;
break;
case ns_t_txt:
case ns_t_spf:
while (rdata < edata) {
T(len = charstr(rdata, edata, &buf, &buflen));
if (len == 0)
goto formerr;
rdata += len;
if (rdata < edata)
T(addstr(" ", 1, &buf, &buflen));
}
break;
case ns_t_nsap: {
char t[2+255*3];
(void) inet_nsap_ntoa(rdlen, rdata, t);
T(addstr(t, strlen(t), &buf, &buflen));
break;
}
case ns_t_aaaa:
if (rdlen != (size_t)NS_IN6ADDRSZ)
goto formerr;
(void) inet_ntop(AF_INET6, rdata, buf, buflen);
addlen(strlen(buf), &buf, &buflen);
break;
case ns_t_loc: {
char t[255];
/* XXX protocol format checking? */
(void) loc_ntoa(rdata, t);
T(addstr(t, strlen(t), &buf, &buflen));
break;
}
case ns_t_naptr: {
u_int order, preference;
char t[50];
if (rdlen < 2U*NS_INT16SZ)
goto formerr;
/* Order, Precedence. */
order = ns_get16(rdata); rdata += NS_INT16SZ;
preference = ns_get16(rdata); rdata += NS_INT16SZ;
len = SPRINTF((t, "%u %u ", order, preference));
T(addstr(t, len, &buf, &buflen));
/* Flags. */
T(len = charstr(rdata, edata, &buf, &buflen));
if (len == 0)
goto formerr;
rdata += len;
T(addstr(" ", 1, &buf, &buflen));
/* Service. */
T(len = charstr(rdata, edata, &buf, &buflen));
if (len == 0)
goto formerr;
rdata += len;
T(addstr(" ", 1, &buf, &buflen));
/* Regexp. */
T(len = charstr(rdata, edata, &buf, &buflen));
if (len < 0)
return (-1);
if (len == 0)
goto formerr;
rdata += len;
T(addstr(" ", 1, &buf, &buflen));
/* Server. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
}
case ns_t_srv: {
u_int priority, weight, port;
char t[50];
if (rdlen < 3U*NS_INT16SZ)
goto formerr;
/* Priority, Weight, Port. */
priority = ns_get16(rdata); rdata += NS_INT16SZ;
weight = ns_get16(rdata); rdata += NS_INT16SZ;
port = ns_get16(rdata); rdata += NS_INT16SZ;
len = SPRINTF((t, "%u %u %u ", priority, weight, port));
T(addstr(t, len, &buf, &buflen));
/* Server. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
}
case ns_t_minfo:
case ns_t_rp:
/* Name1. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" ", 1, &buf, &buflen));
/* Name2. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
case ns_t_wks: {
int n, lcnt;
if (rdlen < 1U + NS_INT32SZ)
goto formerr;
/* Address. */
(void) inet_ntop(AF_INET, rdata, buf, buflen);
addlen(strlen(buf), &buf, &buflen);
rdata += NS_INADDRSZ;
/* Protocol. */
len = SPRINTF((tmp, " %u ( ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata += NS_INT8SZ;
/* Bit map. */
n = 0;
lcnt = 0;
while (rdata < edata) {
u_int c = *rdata++;
do {
if (c & 0200) {
if (lcnt == 0) {
T(addstr("\n\t\t\t\t", 5,
&buf, &buflen));
lcnt = 10;
spaced = 0;
}
len = SPRINTF((tmp, "%d ", n));
T(addstr(tmp, len, &buf, &buflen));
lcnt--;
}
c <<= 1;
} while (++n & 07);
}
T(addstr(")", 1, &buf, &buflen));
break;
}
case ns_t_key:
case ns_t_dnskey: {
char base64_key[NS_MD5RSA_MAX_BASE64];
u_int keyflags, protocol, algorithm, key_id;
const char *leader;
int n;
if (rdlen < 0U + NS_INT16SZ + NS_INT8SZ + NS_INT8SZ)
goto formerr;
/* Key flags, Protocol, Algorithm. */
#ifndef _LIBC
key_id = dst_s_dns_key_id(rdata, edata-rdata);
#else
key_id = 0;
#endif
keyflags = ns_get16(rdata); rdata += NS_INT16SZ;
protocol = *rdata++;
algorithm = *rdata++;
len = SPRINTF((tmp, "0x%04x %u %u",
keyflags, protocol, algorithm));
T(addstr(tmp, len, &buf, &buflen));
/* Public key data. */
len = b64_ntop(rdata, edata - rdata,
base64_key, sizeof base64_key);
if (len < 0)
goto formerr;
if (len > 15) {
T(addstr(" (", 2, &buf, &buflen));
leader = "\n\t\t";
spaced = 0;
} else
leader = " ";
for (n = 0; n < len; n += 48) {
T(addstr(leader, strlen(leader), &buf, &buflen));
T(addstr(base64_key + n, MIN(len - n, 48),
&buf, &buflen));
}
if (len > 15)
T(addstr(" )", 2, &buf, &buflen));
n = SPRINTF((tmp, " ; key_tag= %u", key_id));
T(addstr(tmp, n, &buf, &buflen));
break;
}
case ns_t_sig:
case ns_t_rrsig: {
char base64_key[NS_MD5RSA_MAX_BASE64];
u_int type, algorithm, labels, footprint;
const char *leader;
u_long t;
int n;
if (rdlen < 22U)
goto formerr;
/* Type covered, Algorithm, Label count, Original TTL. */
type = ns_get16(rdata); rdata += NS_INT16SZ;
algorithm = *rdata++;
labels = *rdata++;
t = ns_get32(rdata); rdata += NS_INT32SZ;
len = SPRINTF((tmp, "%s %d %d %lu ",
p_type(type), algorithm, labels, t));
T(addstr(tmp, len, &buf, &buflen));
if (labels > (u_int)dn_count_labels(name))
goto formerr;
/* Signature expiry. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
len = SPRINTF((tmp, "%s ", p_secstodate(t)));
T(addstr(tmp, len, &buf, &buflen));
/* Time signed. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
len = SPRINTF((tmp, "%s ", p_secstodate(t)));
T(addstr(tmp, len, &buf, &buflen));
/* Signature Footprint. */
footprint = ns_get16(rdata); rdata += NS_INT16SZ;
len = SPRINTF((tmp, "%u ", footprint));
T(addstr(tmp, len, &buf, &buflen));
/* Signer's name. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
/* Signature. */
len = b64_ntop(rdata, edata - rdata,
base64_key, sizeof base64_key);
if (len > 15) {
T(addstr(" (", 2, &buf, &buflen));
leader = "\n\t\t";
spaced = 0;
} else
leader = " ";
if (len < 0)
goto formerr;
for (n = 0; n < len; n += 48) {
T(addstr(leader, strlen(leader), &buf, &buflen));
T(addstr(base64_key + n, MIN(len - n, 48),
&buf, &buflen));
}
if (len > 15)
T(addstr(" )", 2, &buf, &buflen));
break;
}
case ns_t_nxt: {
int n, c;
/* Next domain name. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
/* Type bit map. */
n = edata - rdata;
for (c = 0; c < n*8; c++)
if (NS_NXT_BIT_ISSET(c, rdata)) {
len = SPRINTF((tmp, " %s", p_type(c)));
T(addstr(tmp, len, &buf, &buflen));
}
break;
}
case ns_t_cert: {
u_int c_type, key_tag, alg;
int n;
unsigned int siz;
char base64_cert[8192], tmp[40];
const char *leader;
c_type = ns_get16(rdata); rdata += NS_INT16SZ;
key_tag = ns_get16(rdata); rdata += NS_INT16SZ;
alg = (u_int) *rdata++;
len = SPRINTF((tmp, "%d %d %d ", c_type, key_tag, alg));
T(addstr(tmp, len, &buf, &buflen));
siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
if (siz > sizeof(base64_cert) * 3/4) {
const char *str = "record too long to print";
T(addstr(str, strlen(str), &buf, &buflen));
}
else {
len = b64_ntop(rdata, edata-rdata, base64_cert, siz);
if (len < 0)
goto formerr;
else if (len > 15) {
T(addstr(" (", 2, &buf, &buflen));
leader = "\n\t\t";
spaced = 0;
}
else
leader = " ";
for (n = 0; n < len; n += 48) {
T(addstr(leader, strlen(leader),
&buf, &buflen));
T(addstr(base64_cert + n, MIN(len - n, 48),
&buf, &buflen));
}
if (len > 15)
T(addstr(" )", 2, &buf, &buflen));
}
break;
}
case ns_t_tkey: {
/* KJD - need to complete this */
u_long t;
int mode, err, keysize;
/* Algorithm name. */
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" ", 1, &buf, &buflen));
/* Inception. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
len = SPRINTF((tmp, "%s ", p_secstodate(t)));
T(addstr(tmp, len, &buf, &buflen));
/* Experation. */
t = ns_get32(rdata); rdata += NS_INT32SZ;
len = SPRINTF((tmp, "%s ", p_secstodate(t)));
T(addstr(tmp, len, &buf, &buflen));
/* Mode , Error, Key Size. */
/* Priority, Weight, Port. */
mode = ns_get16(rdata); rdata += NS_INT16SZ;
err = ns_get16(rdata); rdata += NS_INT16SZ;
keysize = ns_get16(rdata); rdata += NS_INT16SZ;
len = SPRINTF((tmp, "%u %u %u ", mode, err, keysize));
T(addstr(tmp, len, &buf, &buflen));
/* XXX need to dump key, print otherdata length & other data */
break;
}
case ns_t_tsig: {
/* BEW - need to complete this */
int n;
T(len = addname(msg, msglen, &rdata, origin, &buf, &buflen));
T(addstr(" ", 1, &buf, &buflen));
rdata += 8; /*%< time */
n = ns_get16(rdata); rdata += INT16SZ;
rdata += n; /*%< sig */
n = ns_get16(rdata); rdata += INT16SZ; /*%< original id */
sprintf(buf, "%d", ns_get16(rdata));
rdata += INT16SZ;
addlen(strlen(buf), &buf, &buflen);
break;
}
case ns_t_a6: {
struct in6_addr a;
int pbyte, pbit;
/* prefix length */
if (rdlen == 0U) goto formerr;
len = SPRINTF((tmp, "%d ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
pbit = *rdata;
if (pbit > 128) goto formerr;
pbyte = (pbit & ~7) / 8;
rdata++;
/* address suffix: provided only when prefix len != 128 */
if (pbit < 128) {
if (rdata + pbyte >= edata) goto formerr;
memset(&a, 0, sizeof(a));
memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
(void) inet_ntop(AF_INET6, &a, buf, buflen);
addlen(strlen(buf), &buf, &buflen);
rdata += sizeof(a) - pbyte;
}
/* prefix name: provided only when prefix len > 0 */
if (pbit == 0)
break;
if (rdata >= edata) goto formerr;
T(addstr(" ", 1, &buf, &buflen));
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
}
case ns_t_opt: {
len = SPRINTF((tmp, "%u bytes", class));
T(addstr(tmp, len, &buf, &buflen));
break;
}
case ns_t_ds:
case ns_t_dlv:
case ns_t_sshfp: {
u_int t;
if (type == ns_t_ds || type == ns_t_dlv) {
if (rdlen < 4U) goto formerr;
t = ns_get16(rdata);
rdata += NS_INT16SZ;
len = SPRINTF((tmp, "%u ", t));
T(addstr(tmp, len, &buf, &buflen));
} else
if (rdlen < 2U) goto formerr;
len = SPRINTF((tmp, "%u ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
len = SPRINTF((tmp, "%u ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
while (rdata < edata) {
len = SPRINTF((tmp, "%02X", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
}
break;
}
case ns_t_nsec3:
case ns_t_nsec3param: {
u_int t, w, l, j, k, c;
len = SPRINTF((tmp, "%u ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
len = SPRINTF((tmp, "%u ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
t = ns_get16(rdata);
rdata += NS_INT16SZ;
len = SPRINTF((tmp, "%u ", t));
T(addstr(tmp, len, &buf, &buflen));
t = *rdata++;
if (t == 0) {
T(addstr("-", 1, &buf, &buflen));
} else {
while (t-- > 0) {
len = SPRINTF((tmp, "%02X", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
}
}
if (type == ns_t_nsec3param)
break;
T(addstr(" ", 1, &buf, &buflen));
t = *rdata++;
while (t > 0) {
switch (t) {
case 1:
tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
tmp[2] = tmp[3] = tmp[4] = '=';
tmp[5] = tmp[6] = tmp[7] = '=';
break;
case 2:
tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
((rdata[1]>>6)&0x03)];
tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
break;
case 3:
tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
((rdata[1]>>6)&0x03)];
tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
((rdata[2]>>4)&0x0f)];
tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
tmp[5] = tmp[6] = tmp[7] = '=';
break;
case 4:
tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
((rdata[1]>>6)&0x03)];
tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
((rdata[2]>>4)&0x0f)];
tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
((rdata[3]>>7)&0x01)];
tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
tmp[6] = base32hex[(rdata[3]<<3)&0x18];
tmp[7] = '=';
break;
default:
tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
((rdata[1]>>6)&0x03)];
tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
((rdata[2]>>4)&0x0f)];
tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
((rdata[3]>>7)&0x01)];
tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
((rdata[4]>>5)&0x07)];
tmp[7] = base32hex[(rdata[4]&0x1f)];
break;
}
T(addstr(tmp, 8, &buf, &buflen));
if (t >= 5) {
rdata += 5;
t -= 5;
} else {
rdata += t;
t -= t;
}
}
while (rdata < edata) {
w = *rdata++;
l = *rdata++;
for (j = 0; j < l; j++) {
if (rdata[j] == 0)
continue;
for (k = 0; k < 8; k++) {
if ((rdata[j] & (0x80 >> k)) == 0)
continue;
c = w * 256 + j * 8 + k;
len = SPRINTF((tmp, " %s", p_type(c)));
T(addstr(tmp, len, &buf, &buflen));
}
}
rdata += l;
}
break;
}
case ns_t_nsec: {
u_int w, l, j, k, c;
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
while (rdata < edata) {
w = *rdata++;
l = *rdata++;
for (j = 0; j < l; j++) {
if (rdata[j] == 0)
continue;
for (k = 0; k < 8; k++) {
if ((rdata[j] & (0x80 >> k)) == 0)
continue;
c = w * 256 + j * 8 + k;
len = SPRINTF((tmp, " %s", p_type(c)));
T(addstr(tmp, len, &buf, &buflen));
}
}
rdata += l;
}
break;
}
case ns_t_dhcid: {
int n;
unsigned int siz;
char base64_dhcid[8192];
const char *leader;
siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
if (siz > sizeof(base64_dhcid) * 3/4) {
const char *str = "record too long to print";
T(addstr(str, strlen(str), &buf, &buflen));
} else {
len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
if (len < 0)
goto formerr;
else if (len > 15) {
T(addstr(" (", 2, &buf, &buflen));
leader = "\n\t\t";
spaced = 0;
}
else
leader = " ";
for (n = 0; n < len; n += 48) {
T(addstr(leader, strlen(leader),
&buf, &buflen));
T(addstr(base64_dhcid + n, MIN(len - n, 48),
&buf, &buflen));
}
if (len > 15)
T(addstr(" )", 2, &buf, &buflen));
}
break;
}
case ns_t_ipseckey: {
int n;
unsigned int siz;
char base64_key[8192];
const char *leader;
if (rdlen < 2)
goto formerr;
switch (rdata[1]) {
case 0:
case 3:
if (rdlen < 3)
goto formerr;
break;
case 1:
if (rdlen < 7)
goto formerr;
break;
case 2:
if (rdlen < 19)
goto formerr;
break;
default:
comment = "unknown IPSECKEY gateway type";
goto hexify;
}
len = SPRINTF((tmp, "%u ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
len = SPRINTF((tmp, "%u ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
len = SPRINTF((tmp, "%u ", *rdata));
T(addstr(tmp, len, &buf, &buflen));
rdata++;
switch (rdata[-2]) {
case 0:
T(addstr(".", 1, &buf, &buflen));
break;
case 1:
(void) inet_ntop(AF_INET, rdata, buf, buflen);
addlen(strlen(buf), &buf, &buflen);
rdata += 4;
break;
case 2:
(void) inet_ntop(AF_INET6, rdata, buf, buflen);
addlen(strlen(buf), &buf, &buflen);
rdata += 16;
break;
case 3:
T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
break;
}
if (rdata >= edata)
break;
siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
if (siz > sizeof(base64_key) * 3/4) {
const char *str = "record too long to print";
T(addstr(str, strlen(str), &buf, &buflen));
} else {
len = b64_ntop(rdata, edata-rdata, base64_key, siz);
if (len < 0)
goto formerr;
else if (len > 15) {
T(addstr(" (", 2, &buf, &buflen));
leader = "\n\t\t";
spaced = 0;
}
else
leader = " ";
for (n = 0; n < len; n += 48) {
T(addstr(leader, strlen(leader),
&buf, &buflen));
T(addstr(base64_key + n, MIN(len - n, 48),
&buf, &buflen));
}
if (len > 15)
T(addstr(" )", 2, &buf, &buflen));
}
}
case ns_t_hip: {
unsigned int i, hip_len, algorithm, key_len;
char base64_key[NS_MD5RSA_MAX_BASE64];
unsigned int siz;
const char *leader = "\n\t\t\t\t\t";
hip_len = *rdata++;
algorithm = *rdata++;
key_len = ns_get16(rdata);
rdata += NS_INT16SZ;
siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
if (siz > sizeof(base64_key) * 3/4) {
const char *str = "record too long to print";
T(addstr(str, strlen(str), &buf, &buflen));
} else {
len = sprintf(tmp, "( %u ", algorithm);
T(addstr(tmp, len, &buf, &buflen));
for (i = 0; i < hip_len; i++) {
len = sprintf(tmp, "%02X", *rdata);
T(addstr(tmp, len, &buf, &buflen));
rdata++;
}
T(addstr(leader, strlen(leader), &buf, &buflen));
len = b64_ntop(rdata, key_len, base64_key, siz);
if (len < 0)
goto formerr;
T(addstr(base64_key, len, &buf, &buflen));
rdata += key_len;
while (rdata < edata) {
T(addstr(leader, strlen(leader), &buf, &buflen));
T(addname(msg, msglen, &rdata, origin,
&buf, &buflen));
}
T(addstr(" )", 2, &buf, &buflen));
}
break;
}
default:
comment = "unknown RR type";
goto hexify;
}
return (buf - obuf);
formerr:
comment = "RR format error";
hexify: {
int n, m;
char *p;
len = SPRINTF((tmp, "\\# %u%s\t; %s", (unsigned)(edata - rdata),
rdlen != 0U ? " (" : "", comment));
T(addstr(tmp, len, &buf, &buflen));
while (rdata < edata) {
p = tmp;
p += SPRINTF((p, "\n\t"));
spaced = 0;
n = MIN(16, edata - rdata);
for (m = 0; m < n; m++)
p += SPRINTF((p, "%02x ", rdata[m]));
T(addstr(tmp, p - tmp, &buf, &buflen));
if (n < 16) {
T(addstr(")", 1, &buf, &buflen));
T(addtab(p - tmp + 1, 48, spaced, &buf, &buflen));
}
p = tmp;
p += SPRINTF((p, "; "));
for (m = 0; m < n; m++)
*p++ = (isascii(rdata[m]) && isprint(rdata[m]))
? rdata[m]
: '.';
T(addstr(tmp, p - tmp, &buf, &buflen));
rdata += n;
}
return (buf - obuf);
}
}
/* Private. */
/*%
* size_t
* prune_origin(name, origin)
* Find out if the name is at or under the current origin.
* return:
* Number of characters in name before start of origin,
* or length of name if origin does not match.
* notes:
* This function should share code with samedomain().
*/
static size_t
prune_origin(const char *name, const char *origin) {
const char *oname = name;
while (*name != '\0') {
if (origin != NULL && ns_samename(name, origin) == 1)
return (name - oname - (name > oname));
while (*name != '\0') {
if (*name == '\\') {
name++;
/* XXX need to handle \nnn form. */
if (*name == '\0')
break;
} else if (*name == '.') {
name++;
break;
}
name++;
}
}
return (name - oname);
}
/*%
* int
* charstr(rdata, edata, buf, buflen)
* Format a <character-string> into the presentation buffer.
* return:
* Number of rdata octets consumed
* 0 for protocol format error
* -1 for output buffer error
* side effects:
* buffer is advanced on success.
*/
static int
charstr(const u_char *rdata, const u_char *edata, char **buf, size_t *buflen) {
const u_char *odata = rdata;
size_t save_buflen = *buflen;
char *save_buf = *buf;
if (addstr("\"", 1, buf, buflen) < 0)
goto enospc;
if (rdata < edata) {
int n = *rdata;
if (rdata + 1 + n <= edata) {
rdata++;
while (n-- > 0) {
if (strchr("\n\"\\", *rdata) != NULL)
if (addstr("\\", 1, buf, buflen) < 0)
goto enospc;
if (addstr((const char *)rdata, 1,
buf, buflen) < 0)
goto enospc;
rdata++;
}
}
}
if (addstr("\"", 1, buf, buflen) < 0)
goto enospc;
return (rdata - odata);
enospc:
errno = ENOSPC;
*buf = save_buf;
*buflen = save_buflen;
return (-1);
}
static int
addname(const u_char *msg, size_t msglen,
const u_char **pp, const char *origin,
char **buf, size_t *buflen)
{
size_t newlen, save_buflen = *buflen;
char *save_buf = *buf;
int n;
n = dn_expand(msg, msg + msglen, *pp, *buf, *buflen);
if (n < 0)
goto enospc; /*%< Guess. */
newlen = prune_origin(*buf, origin);
if (**buf == '\0') {
goto root;
} else if (newlen == 0U) {
/* Use "@" instead of name. */
if (newlen + 2 > *buflen)
goto enospc; /* No room for "@\0". */
(*buf)[newlen++] = '@';
(*buf)[newlen] = '\0';
} else {
if (((origin == NULL || origin[0] == '\0') ||
(origin[0] != '.' && origin[1] != '\0' &&
(*buf)[newlen] == '\0')) && (*buf)[newlen - 1] != '.') {
/* No trailing dot. */
root:
if (newlen + 2 > *buflen)
goto enospc; /* No room for ".\0". */
(*buf)[newlen++] = '.';
(*buf)[newlen] = '\0';
}
}
*pp += n;
addlen(newlen, buf, buflen);
**buf = '\0';
return (newlen);
enospc:
errno = ENOSPC;
*buf = save_buf;
*buflen = save_buflen;
return (-1);
}
static void
addlen(size_t len, char **buf, size_t *buflen) {
INSIST(len <= *buflen);
*buf += len;
*buflen -= len;
}
static int
addstr(const char *src, size_t len, char **buf, size_t *buflen) {
if (len >= *buflen) {
errno = ENOSPC;
return (-1);
}
memcpy(*buf, src, len);
addlen(len, buf, buflen);
**buf = '\0';
return (0);
}
static int
addtab(size_t len, size_t target, int spaced, char **buf, size_t *buflen) {
size_t save_buflen = *buflen;
char *save_buf = *buf;
int t;
if (spaced || len >= target - 1) {
T(addstr(" ", 2, buf, buflen));
spaced = 1;
} else {
for (t = (target - len - 1) / 8; t >= 0; t--)
if (addstr("\t", 1, buf, buflen) < 0) {
*buflen = save_buflen;
*buf = save_buf;
return (-1);
}
spaced = 0;
}
return (spaced);
}
/*! \file */
diff --git a/lib/libc/nameser/ns_samedomain.c b/lib/libc/nameser/ns_samedomain.c
index 1b7f562d66b5..17451543cf08 100644
--- a/lib/libc/nameser/ns_samedomain.c
+++ b/lib/libc/nameser/ns_samedomain.c
@@ -1,211 +1,210 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#ifndef lint
static const char rcsid[] = "$Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp $";
#endif
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/types.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <string.h>
#include "port_after.h"
/*%
* Check whether a name belongs to a domain.
*
* Inputs:
*\li a - the domain whose ancestry is being verified
*\li b - the potential ancestor we're checking against
*
* Return:
*\li boolean - is a at or below b?
*
* Notes:
*\li Trailing dots are first removed from name and domain.
* Always compare complete subdomains, not only whether the
* domain name is the trailing string of the given name.
*
*\li "host.foobar.top" lies in "foobar.top" and in "top" and in ""
* but NOT in "bar.top"
*/
int
ns_samedomain(const char *a, const char *b) {
size_t la, lb;
int diff, i, escaped;
const char *cp;
la = strlen(a);
lb = strlen(b);
/* Ignore a trailing label separator (i.e. an unescaped dot) in 'a'. */
if (la != 0U && a[la - 1] == '.') {
escaped = 0;
/* Note this loop doesn't get executed if la==1. */
for (i = la - 2; i >= 0; i--)
if (a[i] == '\\') {
if (escaped)
escaped = 0;
else
escaped = 1;
} else
break;
if (!escaped)
la--;
}
/* Ignore a trailing label separator (i.e. an unescaped dot) in 'b'. */
if (lb != 0U && b[lb - 1] == '.') {
escaped = 0;
/* note this loop doesn't get executed if lb==1 */
for (i = lb - 2; i >= 0; i--)
if (b[i] == '\\') {
if (escaped)
escaped = 0;
else
escaped = 1;
} else
break;
if (!escaped)
lb--;
}
/* lb == 0 means 'b' is the root domain, so 'a' must be in 'b'. */
if (lb == 0U)
return (1);
/* 'b' longer than 'a' means 'a' can't be in 'b'. */
if (lb > la)
return (0);
/* 'a' and 'b' being equal at this point indicates sameness. */
if (lb == la)
return (strncasecmp(a, b, lb) == 0);
/* Ok, we know la > lb. */
diff = la - lb;
/*
* If 'a' is only 1 character longer than 'b', then it can't be
* a subdomain of 'b' (because of the need for the '.' label
* separator).
*/
if (diff < 2)
return (0);
/*
* If the character before the last 'lb' characters of 'b'
* isn't '.', then it can't be a match (this lets us avoid
* having "foobar.com" match "bar.com").
*/
if (a[diff - 1] != '.')
return (0);
/*
* We're not sure about that '.', however. It could be escaped
* and thus not a really a label separator.
*/
escaped = 0;
for (i = diff - 2; i >= 0; i--)
if (a[i] == '\\') {
if (escaped)
escaped = 0;
else
escaped = 1;
} else
break;
if (escaped)
return (0);
/* Now compare aligned trailing substring. */
cp = a + diff;
return (strncasecmp(cp, b, lb) == 0);
}
#ifndef _LIBC
/*%
* is "a" a subdomain of "b"?
*/
int
ns_subdomain(const char *a, const char *b) {
return (ns_samename(a, b) != 1 && ns_samedomain(a, b));
}
#endif
/*%
* make a canonical copy of domain name "src"
*
* notes:
* \code
* foo -> foo.
* foo. -> foo.
* foo.. -> foo.
* foo\. -> foo\..
* foo\\. -> foo\\.
* \endcode
*/
int
ns_makecanon(const char *src, char *dst, size_t dstsize) {
size_t n = strlen(src);
if (n + sizeof "." > dstsize) { /*%< Note: sizeof == 2 */
errno = EMSGSIZE;
return (-1);
}
strcpy(dst, src);
while (n >= 1U && dst[n - 1] == '.') /*%< Ends in "." */
if (n >= 2U && dst[n - 2] == '\\' && /*%< Ends in "\." */
(n < 3U || dst[n - 3] != '\\')) /*%< But not "\\." */
break;
else
dst[--n] = '\0';
dst[n++] = '.';
dst[n] = '\0';
return (0);
}
/*%
* determine whether domain name "a" is the same as domain name "b"
*
* return:
*\li -1 on error
*\li 0 if names differ
*\li 1 if names are the same
*/
int
ns_samename(const char *a, const char *b) {
char ta[NS_MAXDNAME], tb[NS_MAXDNAME];
if (ns_makecanon(a, ta, sizeof ta) < 0 ||
ns_makecanon(b, tb, sizeof tb) < 0)
return (-1);
if (strcasecmp(ta, tb) == 0)
return (1);
else
return (0);
}
/*! \file */
diff --git a/lib/libc/nameser/ns_ttl.c b/lib/libc/nameser/ns_ttl.c
index e6d66379fa3e..47acf445587b 100644
--- a/lib/libc/nameser/ns_ttl.c
+++ b/lib/libc/nameser/ns_ttl.c
@@ -1,164 +1,163 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996,1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#ifndef lint
static const char rcsid[] = "$Id: ns_ttl.c,v 1.4 2005/07/28 06:51:49 marka Exp $";
#endif
-#include <sys/cdefs.h>
/* Import. */
#include "port_before.h"
#include <arpa/nameser.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) ((size_t)sprintf x)
#endif
/* Forward. */
static int fmt1(int t, char s, char **buf, size_t *buflen);
/* Macros. */
#define T(x) if ((x) < 0) return (-1); else (void)NULL
/* Public. */
int
ns_format_ttl(u_long src, char *dst, size_t dstlen) {
char *odst = dst;
int secs, mins, hours, days, weeks, x;
char *p;
secs = src % 60; src /= 60;
mins = src % 60; src /= 60;
hours = src % 24; src /= 24;
days = src % 7; src /= 7;
weeks = src; src = 0;
x = 0;
if (weeks) {
T(fmt1(weeks, 'W', &dst, &dstlen));
x++;
}
if (days) {
T(fmt1(days, 'D', &dst, &dstlen));
x++;
}
if (hours) {
T(fmt1(hours, 'H', &dst, &dstlen));
x++;
}
if (mins) {
T(fmt1(mins, 'M', &dst, &dstlen));
x++;
}
if (secs || !(weeks || days || hours || mins)) {
T(fmt1(secs, 'S', &dst, &dstlen));
x++;
}
if (x > 1) {
int ch;
for (p = odst; (ch = *p) != '\0'; p++)
if (isascii(ch) && isupper(ch))
*p = tolower(ch);
}
return (dst - odst);
}
int
ns_parse_ttl(const char *src, u_long *dst) {
u_long ttl, tmp;
int ch, digits, dirty;
ttl = 0;
tmp = 0;
digits = 0;
dirty = 0;
while ((ch = *src++) != '\0') {
if (!isascii(ch) || !isprint(ch))
goto einval;
if (isdigit(ch)) {
tmp *= 10;
tmp += (ch - '0');
digits++;
continue;
}
if (digits == 0)
goto einval;
if (islower(ch))
ch = toupper(ch);
switch (ch) {
case 'W': tmp *= 7;
case 'D': tmp *= 24;
case 'H': tmp *= 60;
case 'M': tmp *= 60;
case 'S': break;
default: goto einval;
}
ttl += tmp;
tmp = 0;
digits = 0;
dirty = 1;
}
if (digits > 0) {
if (dirty)
goto einval;
else
ttl += tmp;
} else if (!dirty)
goto einval;
*dst = ttl;
return (0);
einval:
errno = EINVAL;
return (-1);
}
/* Private. */
static int
fmt1(int t, char s, char **buf, size_t *buflen) {
char tmp[50];
size_t len;
len = SPRINTF((tmp, "%d%c", t, s));
if (len + 1 > *buflen)
return (-1);
strcpy(*buf, tmp);
*buf += len;
*buflen -= len;
return (0);
}
/*! \file */
diff --git a/lib/libc/net/base64.c b/lib/libc/net/base64.c
index 44b2e9bd42f6..f508275e4eb9 100644
--- a/lib/libc/net/base64.c
+++ b/lib/libc/net/base64.c
@@ -1,317 +1,316 @@
/*
* Copyright (c) 1996, 1998 by Internet Software Consortium.
*
* 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM 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.
*/
/*
* Portions Copyright (c) 1995 by International Business Machines, Inc.
*
* International Business Machines, Inc. (hereinafter called IBM) grants
* permission under its copyrights to use, copy, modify, and distribute this
* Software with or without fee, provided that the above copyright notice and
* all paragraphs of this notice appear in all copies, and that the name of IBM
* not be used in connection with the marketing of any product incorporating
* the Software or modifications thereof, without specific, written prior
* permission.
*
* To the extent it has a right to do so, IBM grants an immunity from suit
* under its patents, if any, for the use, sale or manufacture of products to
* the extent that such products are used for performing Domain Name System
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
* granted for any product per se or for any other function of any product.
*
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define Assert(Cond) if (!(Cond)) abort()
static const char Base64[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static const char Pad64 = '=';
/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
The following encoding technique is taken from RFC 1521 by Borenstein
and Freed. It is reproduced here in a slightly edited form for
convenience.
A 65-character subset of US-ASCII is used, enabling 6 bits to be
represented per printable character. (The extra 65th character, "=",
is used to signify a special processing function.)
The encoding process represents 24-bit groups of input bits as output
strings of 4 encoded characters. Proceeding from left to right, a
24-bit input group is formed by concatenating 3 8-bit input groups.
These 24 bits are then treated as 4 concatenated 6-bit groups, each
of which is translated into a single digit in the base64 alphabet.
Each 6-bit group is used as an index into an array of 64 printable
characters. The character referenced by the index is placed in the
output string.
Table 1: The Base64 Alphabet
Value Encoding Value Encoding Value Encoding Value Encoding
0 A 17 R 34 i 51 z
1 B 18 S 35 j 52 0
2 C 19 T 36 k 53 1
3 D 20 U 37 l 54 2
4 E 21 V 38 m 55 3
5 F 22 W 39 n 56 4
6 G 23 X 40 o 57 5
7 H 24 Y 41 p 58 6
8 I 25 Z 42 q 59 7
9 J 26 a 43 r 60 8
10 K 27 b 44 s 61 9
11 L 28 c 45 t 62 +
12 M 29 d 46 u 63 /
13 N 30 e 47 v
14 O 31 f 48 w (pad) =
15 P 32 g 49 x
16 Q 33 h 50 y
Special processing is performed if fewer than 24 bits are available
at the end of the data being encoded. A full encoding quantum is
always completed at the end of a quantity. When fewer than 24 input
bits are available in an input group, zero bits are added (on the
right) to form an integral number of 6-bit groups. Padding at the
end of the data is performed using the '=' character.
Since all base64 input is an integral number of octets, only the
-------------------------------------------------
following cases can arise:
(1) the final quantum of encoding input is an integral
multiple of 24 bits; here, the final unit of encoded
output will be an integral multiple of 4 characters
with no "=" padding,
(2) the final quantum of encoding input is exactly 8 bits;
here, the final unit of encoded output will be two
characters followed by two "=" padding characters, or
(3) the final quantum of encoding input is exactly 16 bits;
here, the final unit of encoded output will be three
characters followed by one "=" padding character.
*/
int
b64_ntop(u_char const *src, size_t srclength, char *target, size_t targsize) {
size_t datalength = 0;
u_char input[3];
u_char output[4];
size_t i;
while (2 < srclength) {
input[0] = *src++;
input[1] = *src++;
input[2] = *src++;
srclength -= 3;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
output[3] = input[2] & 0x3f;
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
Assert(output[3] < 64);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
target[datalength++] = Base64[output[2]];
target[datalength++] = Base64[output[3]];
}
/* Now we worry about padding. */
if (0 != srclength) {
/* Get what's left. */
input[0] = input[1] = input[2] = '\0';
for (i = 0; i < srclength; i++)
input[i] = *src++;
output[0] = input[0] >> 2;
output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
Assert(output[0] < 64);
Assert(output[1] < 64);
Assert(output[2] < 64);
if (datalength + 4 > targsize)
return (-1);
target[datalength++] = Base64[output[0]];
target[datalength++] = Base64[output[1]];
if (srclength == 1)
target[datalength++] = Pad64;
else
target[datalength++] = Base64[output[2]];
target[datalength++] = Pad64;
}
if (datalength >= targsize)
return (-1);
target[datalength] = '\0'; /* Returned value doesn't count \0. */
return (datalength);
}
/* skips all whitespace anywhere.
converts characters, four at a time, starting at (or after)
src from base - 64 numbers into three 8 bit bytes in the target area.
it returns the number of data bytes stored at the target, or -1 on error.
*/
int
b64_pton(const char *src, u_char *target, size_t targsize)
{
int tarindex, state, ch;
u_char nextbyte;
char *pos;
state = 0;
tarindex = 0;
while ((ch = *src++) != '\0') {
if (isspace((unsigned char)ch)) /* Skip whitespace anywhere. */
continue;
if (ch == Pad64)
break;
pos = strchr(Base64, ch);
if (pos == NULL) /* A non-base64 character. */
return (-1);
switch (state) {
case 0:
if (target) {
if ((size_t)tarindex >= targsize)
return (-1);
target[tarindex] = (pos - Base64) << 2;
}
state = 1;
break;
case 1:
if (target) {
if ((size_t)tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 4;
nextbyte = ((pos - Base64) & 0x0f) << 4;
if ((size_t)tarindex + 1 < targsize)
target[tarindex + 1] = nextbyte;
else if (nextbyte)
return (-1);
}
tarindex++;
state = 2;
break;
case 2:
if (target) {
if ((size_t)tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64) >> 2;
nextbyte = ((pos - Base64) & 0x03) << 6;
if ((size_t)tarindex + 1 < targsize)
target[tarindex + 1] = nextbyte;
else if (nextbyte)
return (-1);
}
tarindex++;
state = 3;
break;
case 3:
if (target) {
if ((size_t)tarindex >= targsize)
return (-1);
target[tarindex] |= (pos - Base64);
}
tarindex++;
state = 0;
break;
default:
abort();
}
}
/*
* We are done decoding Base-64 chars. Let's see if we ended
* on a byte boundary, and/or with erroneous trailing characters.
*/
if (ch == Pad64) { /* We got a pad char. */
ch = *src++; /* Skip it, get next. */
switch (state) {
case 0: /* Invalid = in first position */
case 1: /* Invalid = in second position */
return (-1);
case 2: /* Valid, means one byte of info */
/* Skip any number of spaces. */
for ((void)NULL; ch != '\0'; ch = *src++)
if (!isspace((unsigned char)ch))
break;
/* Make sure there is another trailing = sign. */
if (ch != Pad64)
return (-1);
ch = *src++; /* Skip the = */
/* Fall through to "single trailing =" case. */
/* FALLTHROUGH */
case 3: /* Valid, means two bytes of info */
/*
* We know this char is an =. Is there anything but
* whitespace after it?
*/
for ((void)NULL; ch != '\0'; ch = *src++)
if (!isspace((unsigned char)ch))
return (-1);
/*
* Now make sure for cases 2 and 3 that the "extra"
* bits that slopped past the last full byte were
* zeros. If we don't check them, they become a
* subliminal channel.
*/
if (target && (size_t)tarindex < targsize &&
target[tarindex] != 0)
return (-1);
}
} else {
/*
* We ended by seeing the end of the string. Make sure we
* have no partial bytes lying around.
*/
if (state != 0)
return (-1);
}
return (tarindex);
}
diff --git a/lib/libc/net/ether_addr.c b/lib/libc/net/ether_addr.c
index 3a2e565a7b34..efcd84a53437 100644
--- a/lib/libc/net/ether_addr.c
+++ b/lib/libc/net/ether_addr.c
@@ -1,231 +1,230 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1995 Bill Paul <wpaul@ctr.columbia.edu>.
* Copyright (c) 2007 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* ethernet address conversion and lookup routines
*
* Written by Bill Paul <wpaul@ctr.columbia.edu>
* Center for Telecommunications Research
* Columbia University, New York City
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <net/ethernet.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifndef _PATH_ETHERS
#define _PATH_ETHERS "/etc/ethers"
#endif
/*
* Parse a string of text containing an ethernet address and hostname and
* separate it into its component parts.
*/
int
ether_line(const char *l, struct ether_addr *e, char *hostname)
{
int i, o[6];
i = sscanf(l, "%x:%x:%x:%x:%x:%x %s", &o[0], &o[1], &o[2], &o[3],
&o[4], &o[5], hostname);
if (i == 7) {
for (i = 0; i < 6; i++)
e->octet[i] = o[i];
return (0);
} else {
return (-1);
}
}
/*
* Convert an ASCII representation of an ethernet address to binary form.
*/
struct ether_addr *
ether_aton_r(const char *a, struct ether_addr *e)
{
int i;
unsigned int o0, o1, o2, o3, o4, o5;
i = sscanf(a, "%x:%x:%x:%x:%x:%x", &o0, &o1, &o2, &o3, &o4, &o5);
if (i != 6)
return (NULL);
e->octet[0]=o0;
e->octet[1]=o1;
e->octet[2]=o2;
e->octet[3]=o3;
e->octet[4]=o4;
e->octet[5]=o5;
return (e);
}
struct ether_addr *
ether_aton(const char *a)
{
static struct ether_addr e;
return (ether_aton_r(a, &e));
}
/*
* Convert a binary representation of an ethernet address to an ASCII string.
*/
char *
ether_ntoa_r(const struct ether_addr *n, char *a)
{
int i;
i = sprintf(a, "%02x:%02x:%02x:%02x:%02x:%02x", n->octet[0],
n->octet[1], n->octet[2], n->octet[3], n->octet[4], n->octet[5]);
if (i < 17)
return (NULL);
return (a);
}
char *
ether_ntoa(const struct ether_addr *n)
{
static char a[18];
return (ether_ntoa_r(n, a));
}
/*
* Map an ethernet address to a hostname. Use either /etc/ethers or NIS/YP.
*/
int
ether_ntohost(char *hostname, const struct ether_addr *e)
{
FILE *fp;
char buf[BUFSIZ + 2];
struct ether_addr local_ether;
char local_host[MAXHOSTNAMELEN];
#ifdef YP
char *result;
int resultlen;
char *ether_a;
char *yp_domain;
#endif
if ((fp = fopen(_PATH_ETHERS, "re")) == NULL)
return (1);
while (fgets(buf,BUFSIZ,fp)) {
if (buf[0] == '#')
continue;
#ifdef YP
if (buf[0] == '+') {
if (yp_get_default_domain(&yp_domain))
continue;
ether_a = ether_ntoa(e);
if (yp_match(yp_domain, "ethers.byaddr", ether_a,
strlen(ether_a), &result, &resultlen)) {
continue;
}
strncpy(buf, result, resultlen);
buf[resultlen] = '\0';
free(result);
}
#endif
if (!ether_line(buf, &local_ether, local_host)) {
if (!bcmp((char *)&local_ether.octet[0],
(char *)&e->octet[0], 6)) {
/* We have a match. */
strcpy(hostname, local_host);
fclose(fp);
return(0);
}
}
}
fclose(fp);
return (1);
}
/*
* Map a hostname to an ethernet address using /etc/ethers or NIS/YP.
*/
int
ether_hostton(const char *hostname, struct ether_addr *e)
{
FILE *fp;
char buf[BUFSIZ + 2];
struct ether_addr local_ether;
char local_host[MAXHOSTNAMELEN];
#ifdef YP
char *result;
int resultlen;
char *yp_domain;
#endif
if ((fp = fopen(_PATH_ETHERS, "re")) == NULL)
return (1);
while (fgets(buf,BUFSIZ,fp)) {
if (buf[0] == '#')
continue;
#ifdef YP
if (buf[0] == '+') {
if (yp_get_default_domain(&yp_domain))
continue;
if (yp_match(yp_domain, "ethers.byname", hostname,
strlen(hostname), &result, &resultlen)) {
continue;
}
strncpy(buf, result, resultlen);
buf[resultlen] = '\0';
free(result);
}
#endif
if (!ether_line(buf, &local_ether, local_host)) {
if (!strcmp(hostname, local_host)) {
/* We have a match. */
bcopy((char *)&local_ether.octet[0],
(char *)&e->octet[0], 6);
fclose(fp);
return(0);
}
}
}
fclose(fp);
return (1);
}
diff --git a/lib/libc/net/eui64.c b/lib/libc/net/eui64.c
index 349f907b9d0b..274c00186153 100644
--- a/lib/libc/net/eui64.c
+++ b/lib/libc/net/eui64.c
@@ -1,309 +1,308 @@
/*
* Copyright 2004 The Aerospace Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions, and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions, and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of The Aerospace Corporation may not be used to endorse or
* promote products derived from this software.
*
* THIS SOFTWARE IS PROVIDED BY THE AEROSPACE CORPORATION "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AEROSPACE CORPORATION BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Copyright (c) 1995
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* EUI-64 conversion and lookup routines
*
*
* Converted from ether_addr.c rev
* FreeBSD: src/lib/libc/net/eui64.c,v 1.15 2002/04/08 07:51:10 ru Exp
* by Brooks Davis
*
* Written by Bill Paul <wpaul@ctr.columbia.edu>
* Center for Telecommunications Research
* Columbia University, New York City
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <paths.h>
#include <sys/param.h>
#include <sys/eui64.h>
#include <string.h>
#include <stdlib.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#ifndef _PATH_EUI64
#define _PATH_EUI64 "/etc/eui64"
#endif
static int eui64_line(const char *l, struct eui64 *e, char *hostname,
size_t len);
/*
* Parse a string of text containing an EUI-64 and hostname
* and separate it into its component parts.
*/
static int
eui64_line(const char *l, struct eui64 *e, char *hostname, size_t len)
{
char *line, *linehead, *cur;
linehead = strdup(l);
if (linehead == NULL)
return (-1);
line = linehead;
/* Find and parse the EUI64 */
while ((cur = strsep(&line, " \t\r\n")) != NULL) {
if (*cur != '\0') {
if (eui64_aton(cur, e) == 0)
break;
else
goto bad;
}
}
/* Find the hostname */
while ((cur = strsep(&line, " \t\r\n")) != NULL) {
if (*cur != '\0') {
if (strlcpy(hostname, cur, len) <= len)
break;
else
goto bad;
}
}
/* Make sure what remains is either whitespace or a comment */
while ((cur = strsep(&line, " \t\r\n")) != NULL) {
if (*cur == '#')
break;
if (*cur != '\0')
goto bad;
}
free(linehead);
return (0);
bad:
free(linehead);
return (-1);
}
/*
* Convert an ASCII representation of an EUI-64 to binary form.
*/
int
eui64_aton(const char *a, struct eui64 *e)
{
int i;
unsigned int o0, o1, o2, o3, o4, o5, o6, o7;
/* canonical form */
i = sscanf(a, "%x-%x-%x-%x-%x-%x-%x-%x",
&o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
if (i == EUI64_LEN)
goto good;
/* ethernet form */
i = sscanf(a, "%x:%x:%x:%x:%x:%x:%x:%x",
&o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
if (i == EUI64_LEN)
goto good;
/* classic fwcontrol/dconschat form */
i = sscanf(a, "0x%2x%2x%2x%2x%2x%2x%2x%2x",
&o0, &o1, &o2, &o3, &o4, &o5, &o6, &o7);
if (i == EUI64_LEN)
goto good;
/* MAC format (-) */
i = sscanf(a, "%x-%x-%x-%x-%x-%x",
&o0, &o1, &o2, &o5, &o6, &o7);
if (i == 6) {
o3 = 0xff;
o4 = 0xfe;
goto good;
}
/* MAC format (:) */
i = sscanf(a, "%x:%x:%x:%x:%x:%x",
&o0, &o1, &o2, &o5, &o6, &o7);
if (i == 6) {
o3 = 0xff;
o4 = 0xfe;
goto good;
}
return (-1);
good:
e->octet[0]=o0;
e->octet[1]=o1;
e->octet[2]=o2;
e->octet[3]=o3;
e->octet[4]=o4;
e->octet[5]=o5;
e->octet[6]=o6;
e->octet[7]=o7;
return (0);
}
/*
* Convert a binary representation of an EUI-64 to an ASCII string.
*/
int
eui64_ntoa(const struct eui64 *id, char *a, size_t len)
{
int i;
i = snprintf(a, len, "%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
id->octet[0], id->octet[1], id->octet[2], id->octet[3],
id->octet[4], id->octet[5], id->octet[6], id->octet[7]);
if (i < 23 || i >= len)
return (-1);
return (0);
}
/*
* Map an EUI-64 to a hostname. Use either /etc/eui64 or NIS/YP.
*/
int
eui64_ntohost(char *hostname, size_t len, const struct eui64 *id)
{
FILE *fp;
char buf[BUFSIZ + 2];
struct eui64 local_eui64;
char local_host[MAXHOSTNAMELEN];
#ifdef YP
char *result;
int resultlen;
char eui64_a[24];
char *yp_domain;
#endif
if ((fp = fopen(_PATH_EUI64, "re")) == NULL)
return (1);
while (fgets(buf,BUFSIZ,fp)) {
if (buf[0] == '#')
continue;
#ifdef YP
if (buf[0] == '+') {
if (yp_get_default_domain(&yp_domain))
continue;
eui64_ntoa(id, eui64_a, sizeof(eui64_a));
if (yp_match(yp_domain, "eui64.byid", eui64_a,
strlen(eui64_a), &result, &resultlen)) {
continue;
}
strncpy(buf, result, resultlen);
buf[resultlen] = '\0';
free(result);
}
#endif
if (eui64_line(buf, &local_eui64, local_host,
sizeof(local_host)) == 0) {
if (bcmp(&local_eui64.octet[0],
&id->octet[0], EUI64_LEN) == 0) {
/* We have a match */
strcpy(hostname, local_host);
fclose(fp);
return(0);
}
}
}
fclose(fp);
return (1);
}
/*
* Map a hostname to an EUI-64 using /etc/eui64 or NIS/YP.
*/
int
eui64_hostton(const char *hostname, struct eui64 *id)
{
FILE *fp;
char buf[BUFSIZ + 2];
struct eui64 local_eui64;
char local_host[MAXHOSTNAMELEN];
#ifdef YP
char *result;
int resultlen;
char *yp_domain;
#endif
if ((fp = fopen(_PATH_EUI64, "re")) == NULL)
return (1);
while (fgets(buf,BUFSIZ,fp)) {
if (buf[0] == '#')
continue;
#ifdef YP
if (buf[0] == '+') {
if (yp_get_default_domain(&yp_domain))
continue;
if (yp_match(yp_domain, "eui64.byname", hostname,
strlen(hostname), &result, &resultlen)) {
continue;
}
strncpy(buf, result, resultlen);
buf[resultlen] = '\0';
free(result);
}
#endif
if (eui64_line(buf, &local_eui64, local_host,
sizeof(local_host)) == 0) {
if (strcmp(hostname, local_host) == 0) {
/* We have a match */
bcopy(&local_eui64, id, sizeof(struct eui64));
fclose(fp);
return(0);
}
}
}
fclose(fp);
return (1);
}
diff --git a/lib/libc/net/gai_strerror.c b/lib/libc/net/gai_strerror.c
index 4964ca23ae4b..0d4303e76a73 100644
--- a/lib/libc/net/gai_strerror.c
+++ b/lib/libc/net/gai_strerror.c
@@ -1,121 +1,120 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <netdb.h>
#if defined(NLS)
#include <nl_types.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "reentrant.h"
#endif
#include "un-namespace.h"
/*
* Entries EAI_ADDRFAMILY (1) and EAI_NODATA (7) were omitted from RFC 3493,
* but are or may be used as extensions or in old code.
*/
static const char *ai_errlist[] = {
"Success", /* 0 */
"Address family for hostname not supported", /* EAI_ADDRFAMILY */
"Name could not be resolved at this time", /* EAI_AGAIN */
"Flags parameter had an invalid value", /* EAI_BADFLAGS */
"Non-recoverable failure in name resolution", /* EAI_FAIL */
"Address family not recognized", /* EAI_FAMILY */
"Memory allocation failure", /* EAI_MEMORY */
"No address associated with hostname", /* EAI_NODATA*/
"Name does not resolve", /* EAI_NONAME */
"Service was not recognized for socket type", /* EAI_SERVICE */
"Intended socket type was not recognized", /* EAI_SOCKTYPE */
"System error returned in errno", /* EAI_SYSTEM */
"Invalid value for hints", /* EAI_BADHINTS */
"Resolved protocol is unknown", /* EAI_PROTOCOL */
"Argument buffer overflow" /* EAI_OVERFLOW */
};
#if defined(NLS)
static char gai_buf[NL_TEXTMAX];
static once_t gai_init_once = ONCE_INITIALIZER;
static thread_key_t gai_key;
static int gai_keycreated = 0;
static void
gai_keycreate(void)
{
gai_keycreated = (thr_keycreate(&gai_key, free) == 0);
}
#endif
const char *
gai_strerror(int ecode)
{
#if defined(NLS)
nl_catd catd;
char *buf;
if (thr_main() != 0)
buf = gai_buf;
else {
if (thr_once(&gai_init_once, gai_keycreate) != 0 ||
!gai_keycreated)
goto thr_err;
if ((buf = thr_getspecific(gai_key)) == NULL) {
if ((buf = malloc(sizeof(gai_buf))) == NULL)
goto thr_err;
if (thr_setspecific(gai_key, buf) != 0) {
free(buf);
goto thr_err;
}
}
}
catd = catopen("libc", NL_CAT_LOCALE);
if (ecode > 0 && ecode < EAI_MAX)
strlcpy(buf, catgets(catd, 3, ecode, ai_errlist[ecode]),
sizeof(gai_buf));
else if (ecode == 0)
strlcpy(buf, catgets(catd, 3, NL_MSGMAX - 1, "Success"),
sizeof(gai_buf));
else
strlcpy(buf, catgets(catd, 3, NL_MSGMAX, "Unknown error"),
sizeof(gai_buf));
catclose(catd);
return buf;
thr_err:
#endif
if (ecode >= 0 && ecode < EAI_MAX)
return ai_errlist[ecode];
return "Unknown error";
}
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index 60d2444026a0..2b9499d5099b 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -1,3039 +1,3038 @@
/* $KAME: getaddrinfo.c,v 1.15 2000/07/09 04:37:24 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Issues to be discussed:
* - Return values. There are nonstandard return values defined and used
* in the source code. This is because RFC2553 is silent about which error
* code must be returned for which situation.
* - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
* invalid. Current code accepts NULL to be compatible with other OSes.
*
* Note:
* - The code filters out AFs that are not supported by the kernel,
* when globbing NULL hostname (to loopback, or wildcard). Is it the right
* thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
* in ai_flags?
* - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
* (1) what should we do against numeric hostname (2) what should we do
* against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
* non-loopback address configured? global address configured?
*
* OS specific notes for freebsd4:
* - FreeBSD supported $GAI. The code does not.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <net/if_types.h>
#include <ifaddrs.h>
#include <sys/queue.h>
#ifdef INET6
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <netinet6/in6_var.h>
#include <netinet6/nd6.h>
#endif
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#include <netdb.h>
#include <resolv.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <ctype.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include "res_config.h"
#ifdef DEBUG
#include <syslog.h>
#endif
#include <stdarg.h>
#include <nsswitch.h>
#include "un-namespace.h"
#include "netdb_private.h"
#include "libc_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
#define ANY 0
#define YES 1
#define NO 0
static const char in_addrany[] = { 0, 0, 0, 0 };
static const char in_loopback[] = { 127, 0, 0, 1 };
#ifdef INET6
static const char in6_addrany[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
static const char in6_loopback[] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
};
#endif
struct policyqueue {
TAILQ_ENTRY(policyqueue) pc_entry;
#ifdef INET6
struct in6_addrpolicy pc_policy;
#endif
};
TAILQ_HEAD(policyhead, policyqueue);
static const struct afd {
int a_af;
int a_addrlen;
socklen_t a_socklen;
int a_off;
const char *a_addrany;
const char *a_loopback;
int a_scoped;
} afdl [] = {
#ifdef INET6
#define N_INET6 0
{PF_INET6, sizeof(struct in6_addr),
sizeof(struct sockaddr_in6),
offsetof(struct sockaddr_in6, sin6_addr),
in6_addrany, in6_loopback, 1},
#define N_INET 1
#define N_LOCAL 2
#else
#define N_INET 0
#define N_LOCAL 1
#endif
{PF_INET, sizeof(struct in_addr),
sizeof(struct sockaddr_in),
offsetof(struct sockaddr_in, sin_addr),
in_addrany, in_loopback, 0},
#define sizeofmember(type, member) (sizeof(((type *)0)->member))
{PF_LOCAL, sizeofmember(struct sockaddr_un, sun_path),
sizeof(struct sockaddr_un),
offsetof(struct sockaddr_un, sun_path),
NULL, NULL, 0},
{0, 0, 0, 0, NULL, NULL, 0},
};
struct explore {
int e_af;
int e_socktype;
int e_protocol;
int e_wild;
#define AF_ANY 0x01
#define SOCKTYPE_ANY 0x02
#define PROTOCOL_ANY 0x04
#define WILD_AF(ex) ((ex)->e_wild & AF_ANY)
#define WILD_SOCKTYPE(ex) ((ex)->e_wild & SOCKTYPE_ANY)
#define WILD_PROTOCOL(ex) ((ex)->e_wild & PROTOCOL_ANY)
};
static const struct explore explore[] = {
#ifdef INET6
{ PF_INET6, SOCK_DGRAM, IPPROTO_UDP,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_INET6, SOCK_STREAM, IPPROTO_TCP,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_INET6, SOCK_STREAM, IPPROTO_SCTP,
AF_ANY | SOCKTYPE_ANY },
{ PF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_INET6, SOCK_DGRAM, IPPROTO_UDPLITE,
AF_ANY | SOCKTYPE_ANY },
{ PF_INET6, SOCK_RAW, ANY,
AF_ANY | PROTOCOL_ANY },
#endif
{ PF_INET, SOCK_DGRAM, IPPROTO_UDP,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_INET, SOCK_STREAM, IPPROTO_TCP,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_INET, SOCK_STREAM, IPPROTO_SCTP,
AF_ANY | SOCKTYPE_ANY },
{ PF_INET, SOCK_SEQPACKET, IPPROTO_SCTP,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_INET, SOCK_DGRAM, IPPROTO_UDPLITE,
AF_ANY | SOCKTYPE_ANY },
{ PF_INET, SOCK_RAW, ANY,
AF_ANY | PROTOCOL_ANY },
{ PF_LOCAL, SOCK_DGRAM, ANY,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_LOCAL, SOCK_STREAM, ANY,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ PF_LOCAL, SOCK_SEQPACKET, ANY,
AF_ANY | SOCKTYPE_ANY | PROTOCOL_ANY },
{ -1, 0, 0, 0 },
};
#ifdef INET6
#define PTON_MAX 16
#else
#define PTON_MAX 4
#endif
#define AIO_SRCFLAG_DEPRECATED 0x1
struct ai_order {
union {
struct sockaddr_storage aiou_ss;
struct sockaddr aiou_sa;
} aio_src_un;
#define aio_srcsa aio_src_un.aiou_sa
u_int32_t aio_srcflag;
int aio_srcscope;
int aio_dstscope;
struct policyqueue *aio_srcpolicy;
struct policyqueue *aio_dstpolicy;
struct addrinfo *aio_ai;
int aio_matchlen;
int aio_initial_sequence;
};
static const ns_src default_dns_files[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NSSRC_DNS, NS_SUCCESS },
{ 0 }
};
struct res_target {
struct res_target *next;
const char *name; /* domain name */
int qclass, qtype; /* class and type of query */
u_char *answer; /* buffer to put answer */
int anslen; /* size of answer buffer */
int n; /* result length */
};
#define MAXPACKET (64*1024)
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf;
static int str2number(const char *, int *);
static int explore_copy(const struct addrinfo *, const struct addrinfo *,
struct addrinfo **);
static int explore_null(const struct addrinfo *,
const char *, struct addrinfo **);
static int explore_numeric(const struct addrinfo *, const char *,
const char *, struct addrinfo **, const char *);
static int explore_numeric_scope(const struct addrinfo *, const char *,
const char *, struct addrinfo **);
static int get_canonname(const struct addrinfo *,
struct addrinfo *, const char *);
static struct addrinfo *get_ai(const struct addrinfo *,
const struct afd *, const char *);
static struct addrinfo *copy_ai(const struct addrinfo *);
static int get_portmatch(const struct addrinfo *, const char *);
static int get_port(struct addrinfo *, const char *, int);
static const struct afd *find_afd(int);
static int addrconfig(struct addrinfo *);
#ifdef INET6
static int is_ifdisabled(char *);
#endif
static void set_source(struct ai_order *, struct policyhead *);
static int comp_dst(const void *, const void *);
#ifdef INET6
static int ip6_str2scopeid(char *, struct sockaddr_in6 *, u_int32_t *);
#endif
static int gai_addr2scopetype(struct sockaddr *);
static int explore_fqdn(const struct addrinfo *, const char *,
const char *, struct addrinfo **);
static int reorder(struct addrinfo *);
static int get_addrselectpolicy(struct policyhead *);
static void free_addrselectpolicy(struct policyhead *);
static struct policyqueue *match_addrselectpolicy(struct sockaddr *,
struct policyhead *);
static int matchlen(struct sockaddr *, struct sockaddr *);
static struct addrinfo *getanswer(const querybuf *, int, const char *, int,
const struct addrinfo *, res_state);
#if defined(RESOLVSORT)
static int addr4sort(struct addrinfo *, res_state);
#endif
static int _dns_getaddrinfo(void *, void *, va_list);
static void _sethtent(FILE **);
static void _endhtent(FILE **);
static struct addrinfo *_gethtent(FILE **, const char *,
const struct addrinfo *);
static int _files_getaddrinfo(void *, void *, va_list);
#ifdef YP
static struct addrinfo *_yphostent(char *, const struct addrinfo *);
static int _yp_getaddrinfo(void *, void *, va_list);
#endif
#ifdef NS_CACHING
static int addrinfo_id_func(char *, size_t *, va_list, void *);
static int addrinfo_marshal_func(char *, size_t *, void *, va_list, void *);
static int addrinfo_unmarshal_func(char *, size_t, void *, va_list, void *);
#endif
static int res_queryN(const char *, struct res_target *, res_state);
static int res_searchN(const char *, struct res_target *, res_state);
static int res_querydomainN(const char *, const char *,
struct res_target *, res_state);
/* XXX macros that make external reference is BAD. */
#define GET_AI(ai, afd, addr) \
do { \
/* external reference: pai, error, and label free */ \
(ai) = get_ai(pai, (afd), (addr)); \
if ((ai) == NULL) { \
error = EAI_MEMORY; \
goto free; \
} \
} while (/*CONSTCOND*/0)
#define GET_PORT(ai, serv) \
do { \
/* external reference: error and label free */ \
error = get_port((ai), (serv), 0); \
if (error != 0) \
goto free; \
} while (/*CONSTCOND*/0)
#define GET_CANONNAME(ai, str) \
do { \
/* external reference: pai, error and label free */ \
error = get_canonname(pai, (ai), (str)); \
if (error != 0) \
goto free; \
} while (/*CONSTCOND*/0)
#define ERR(err) \
do { \
/* external reference: error, and label bad */ \
error = (err); \
goto bad; \
/*NOTREACHED*/ \
} while (/*CONSTCOND*/0)
#define MATCH_FAMILY(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
#define MATCH(x, y, w) \
((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
void
freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *next;
while (ai != NULL) {
next = ai->ai_next;
free(ai->ai_canonname);
/* no need to free(ai->ai_addr) */
free(ai);
ai = next;
}
}
static int
str2number(const char *p, int *portp)
{
char *ep;
unsigned long v;
if (*p == '\0')
return -1;
ep = NULL;
errno = 0;
v = strtoul(p, &ep, 10);
if (errno == 0 && ep && *ep == '\0' && v <= UINT_MAX) {
*portp = v;
return 0;
} else
return -1;
}
int
getaddrinfo(const char *hostname, const char *servname,
const struct addrinfo *hints, struct addrinfo **res)
{
struct addrinfo sentinel;
struct addrinfo *cur;
int error = 0;
struct addrinfo ai, ai0, *afai;
struct addrinfo *pai;
const struct afd *afd;
const struct explore *ex;
struct addrinfo *afailist[nitems(afdl)];
struct addrinfo *afai_unspec;
int found;
int numeric = 0;
/* ensure we return NULL on errors */
*res = NULL;
memset(&ai, 0, sizeof(ai));
memset(afailist, 0, sizeof(afailist));
afai_unspec = NULL;
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
pai = &ai;
pai->ai_flags = 0;
pai->ai_family = PF_UNSPEC;
pai->ai_socktype = ANY;
pai->ai_protocol = ANY;
pai->ai_addrlen = 0;
pai->ai_canonname = NULL;
pai->ai_addr = NULL;
pai->ai_next = NULL;
if (hostname == NULL && servname == NULL)
return EAI_NONAME;
if (hints) {
/* error check for hints */
if (hints->ai_addrlen || hints->ai_canonname ||
hints->ai_addr || hints->ai_next)
ERR(EAI_BADHINTS); /* xxx */
if (hints->ai_flags & ~AI_MASK)
ERR(EAI_BADFLAGS);
switch (hints->ai_family) {
case PF_UNSPEC:
case PF_LOCAL:
case PF_INET:
#ifdef INET6
case PF_INET6:
#endif
break;
default:
ERR(EAI_FAMILY);
}
memcpy(pai, hints, sizeof(*pai));
/*
* if both socktype/protocol are specified, check if they
* are meaningful combination.
*/
if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
for (ex = explore; ex->e_af >= 0; ex++) {
if (!MATCH_FAMILY(pai->ai_family, ex->e_af,
WILD_AF(ex)))
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype,
WILD_SOCKTYPE(ex)))
continue;
if (!MATCH(pai->ai_protocol, ex->e_protocol,
WILD_PROTOCOL(ex)))
continue;
/* matched */
break;
}
if (ex->e_af < 0)
ERR(EAI_BADHINTS);
}
}
/*
* RFC 3493: AI_ALL and AI_V4MAPPED are effective only against
* AF_INET6 query. They need to be ignored if specified in other
* occasions.
*/
switch (pai->ai_flags & (AI_ALL | AI_V4MAPPED)) {
case AI_V4MAPPED:
case AI_ALL | AI_V4MAPPED:
#ifdef INET6
if (pai->ai_family != AF_INET6)
pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
break;
#endif
case AI_ALL:
pai->ai_flags &= ~(AI_ALL | AI_V4MAPPED);
break;
}
/*
* check for special cases. (1) numeric servname is disallowed if
* socktype/protocol are left unspecified. (2) servname is disallowed
* for raw and other inet{,6} sockets.
*/
if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
#ifdef PF_INET6
|| MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
#endif
) {
ai0 = *pai; /* backup *pai */
if (pai->ai_family == PF_UNSPEC) {
#ifdef PF_INET6
pai->ai_family = PF_INET6;
#else
pai->ai_family = PF_INET;
#endif
}
error = get_portmatch(pai, servname);
if (error)
goto bad;
*pai = ai0;
}
ai0 = *pai;
/*
* NULL hostname, or numeric hostname.
* If numeric representation of AF1 can be interpreted as FQDN
* representation of AF2, we need to think again about the code below.
*/
found = 0;
for (afd = afdl; afd->a_af; afd++) {
*pai = ai0;
if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
continue;
if (pai->ai_family == PF_UNSPEC)
pai->ai_family = afd->a_af;
if (hostname == NULL) {
error = explore_null(pai, servname,
&afailist[afd - afdl]);
/*
* Errors from explore_null should be unexpected and
* be caught to avoid returning an incomplete result.
*/
if (error != 0)
goto bad;
} else {
error = explore_numeric_scope(pai, hostname, servname,
&afailist[afd - afdl]);
/*
* explore_numeric_scope returns an error for address
* families that do not match that of hostname.
* Thus we should not catch the error at this moment.
*/
}
if (!error && afailist[afd - afdl])
found++;
}
if (found) {
numeric = 1;
goto globcopy;
}
if (hostname == NULL)
ERR(EAI_NONAME); /* used to be EAI_NODATA */
if (pai->ai_flags & AI_NUMERICHOST)
ERR(EAI_NONAME);
if ((pai->ai_flags & AI_ADDRCONFIG) != 0 && !addrconfig(&ai0))
ERR(EAI_FAIL);
/*
* hostname as alphabetical name.
*/
*pai = ai0;
error = explore_fqdn(pai, hostname, servname, &afai_unspec);
globcopy:
for (ex = explore; ex->e_af >= 0; ex++) {
*pai = ai0;
if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
continue;
if (!MATCH(pai->ai_socktype, ex->e_socktype,
WILD_SOCKTYPE(ex)))
continue;
if (!MATCH(pai->ai_protocol, ex->e_protocol,
WILD_PROTOCOL(ex)))
continue;
if (pai->ai_family == PF_UNSPEC)
pai->ai_family = ex->e_af;
if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
pai->ai_socktype = ex->e_socktype;
if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
pai->ai_protocol = ex->e_protocol;
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
continue;
if (afai_unspec)
afai = afai_unspec;
else {
if ((afd = find_afd(pai->ai_family)) == NULL)
continue;
/* XXX assumes that afd points inside afdl[] */
afai = afailist[afd - afdl];
}
if (!afai)
continue;
error = explore_copy(pai, afai, &cur->ai_next);
if (error != 0)
goto bad;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
/*
* ensure we return either:
* - error == 0, non-NULL *res
* - error != 0, NULL *res
*/
if (error == 0) {
if (sentinel.ai_next) {
/*
* If the returned entry is for an active connection,
* and the given name is not numeric, reorder the
* list, so that the application would try the list
* in the most efficient order. Since the head entry
* of the original list may contain ai_canonname and
* that entry may be moved elsewhere in the new list,
* we keep the pointer and will restore it in the new
* head entry. (Note that RFC3493 requires the head
* entry store it when requested by the caller).
*/
if (hints == NULL || !(hints->ai_flags & AI_PASSIVE)) {
if (!numeric) {
char *canonname;
canonname =
sentinel.ai_next->ai_canonname;
sentinel.ai_next->ai_canonname = NULL;
(void)reorder(&sentinel);
if (sentinel.ai_next->ai_canonname ==
NULL) {
sentinel.ai_next->ai_canonname
= canonname;
} else if (canonname != NULL)
free(canonname);
}
}
*res = sentinel.ai_next;
} else
error = EAI_FAIL;
}
bad:
if (afai_unspec)
freeaddrinfo(afai_unspec);
for (afd = afdl; afd->a_af; afd++) {
if (afailist[afd - afdl])
freeaddrinfo(afailist[afd - afdl]);
}
if (!*res)
if (sentinel.ai_next)
freeaddrinfo(sentinel.ai_next);
return (error);
}
static int
reorder(struct addrinfo *sentinel)
{
struct addrinfo *ai, **aip;
struct ai_order *aio;
int i, n;
struct policyhead policyhead;
/* count the number of addrinfo elements for sorting. */
for (n = 0, ai = sentinel->ai_next; ai != NULL; ai = ai->ai_next, n++)
;
/*
* If the number is small enough, we can skip the reordering process.
*/
if (n <= 1)
return(n);
/* allocate a temporary array for sort and initialization of it. */
if ((aio = calloc(n, sizeof(*aio))) == NULL)
return(n); /* give up reordering */
/* retrieve address selection policy from the kernel */
TAILQ_INIT(&policyhead);
if (!get_addrselectpolicy(&policyhead)) {
/* no policy is installed into kernel, we don't sort. */
free(aio);
return (n);
}
for (i = 0, ai = sentinel->ai_next; i < n; ai = ai->ai_next, i++) {
aio[i].aio_ai = ai;
aio[i].aio_dstscope = gai_addr2scopetype(ai->ai_addr);
aio[i].aio_dstpolicy = match_addrselectpolicy(ai->ai_addr,
&policyhead);
set_source(&aio[i], &policyhead);
aio[i].aio_initial_sequence = i;
}
/* perform sorting. */
qsort(aio, n, sizeof(*aio), comp_dst);
/* reorder the addrinfo chain. */
for (i = 0, aip = &sentinel->ai_next; i < n; i++) {
*aip = aio[i].aio_ai;
aip = &aio[i].aio_ai->ai_next;
}
*aip = NULL;
/* cleanup and return */
free(aio);
free_addrselectpolicy(&policyhead);
return(n);
}
static int
get_addrselectpolicy(struct policyhead *head)
{
#ifdef INET6
int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
size_t l;
char *buf;
struct in6_addrpolicy *pol, *ep;
if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0)
return (0);
if (l == 0)
return (0);
if ((buf = malloc(l)) == NULL)
return (0);
if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) {
free(buf);
return (0);
}
ep = (struct in6_addrpolicy *)(buf + l);
for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
struct policyqueue *new;
if ((new = malloc(sizeof(*new))) == NULL) {
free_addrselectpolicy(head); /* make the list empty */
break;
}
new->pc_policy = *pol;
TAILQ_INSERT_TAIL(head, new, pc_entry);
}
free(buf);
return (1);
#else
return (0);
#endif
}
static void
free_addrselectpolicy(struct policyhead *head)
{
struct policyqueue *ent, *nent;
for (ent = TAILQ_FIRST(head); ent; ent = nent) {
nent = TAILQ_NEXT(ent, pc_entry);
TAILQ_REMOVE(head, ent, pc_entry);
free(ent);
}
}
static struct policyqueue *
match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head)
{
#ifdef INET6
struct policyqueue *ent, *bestent = NULL;
struct in6_addrpolicy *pol;
int matchlen, bestmatchlen = -1;
u_char *mp, *ep, *k, *p, m;
struct sockaddr_in6 key;
switch(addr->sa_family) {
case AF_INET6:
key = *(struct sockaddr_in6 *)addr;
break;
case AF_INET:
/* convert the address into IPv4-mapped IPv6 address. */
memset(&key, 0, sizeof(key));
key.sin6_family = AF_INET6;
key.sin6_len = sizeof(key);
_map_v4v6_address(
(char *)&((struct sockaddr_in *)addr)->sin_addr,
(char *)&key.sin6_addr);
break;
default:
return(NULL);
}
for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
pol = &ent->pc_policy;
matchlen = 0;
mp = (u_char *)&pol->addrmask.sin6_addr;
ep = mp + 16; /* XXX: scope field? */
k = (u_char *)&key.sin6_addr;
p = (u_char *)&pol->addr.sin6_addr;
for (; mp < ep && *mp; mp++, k++, p++) {
m = *mp;
if ((*k & m) != *p)
goto next; /* not match */
if (m == 0xff) /* short cut for a typical case */
matchlen += 8;
else {
while (m >= 0x80) {
matchlen++;
m <<= 1;
}
}
}
/* matched. check if this is better than the current best. */
if (matchlen > bestmatchlen) {
bestent = ent;
bestmatchlen = matchlen;
}
next:
continue;
}
return(bestent);
#else
return(NULL);
#endif
}
static void
set_source(struct ai_order *aio, struct policyhead *ph)
{
struct addrinfo ai = *aio->aio_ai;
struct sockaddr_storage ss;
socklen_t srclen;
int s;
/* set unspec ("no source is available"), just in case */
aio->aio_srcsa.sa_family = AF_UNSPEC;
aio->aio_srcscope = -1;
switch(ai.ai_family) {
case AF_INET:
#ifdef INET6
case AF_INET6:
#endif
break;
default: /* ignore unsupported AFs explicitly */
return;
}
/* XXX: make a dummy addrinfo to call connect() */
ai.ai_socktype = SOCK_DGRAM;
ai.ai_protocol = IPPROTO_UDP; /* is UDP too specific? */
ai.ai_next = NULL;
memset(&ss, 0, sizeof(ss));
memcpy(&ss, ai.ai_addr, ai.ai_addrlen);
ai.ai_addr = (struct sockaddr *)&ss;
get_port(&ai, "1", 0);
/* open a socket to get the source address for the given dst */
if ((s = _socket(ai.ai_family, ai.ai_socktype | SOCK_CLOEXEC,
ai.ai_protocol)) < 0)
return; /* give up */
#ifdef INET6
if (ai.ai_family == AF_INET6) {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai.ai_addr;
int off = 0;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
(void)_setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(char *)&off, sizeof(off));
}
#endif
if (_connect(s, ai.ai_addr, ai.ai_addrlen) < 0)
goto cleanup;
srclen = ai.ai_addrlen;
if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
aio->aio_srcsa.sa_family = AF_UNSPEC;
goto cleanup;
}
aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
aio->aio_matchlen = matchlen(&aio->aio_srcsa, aio->aio_ai->ai_addr);
#ifdef INET6
if (ai.ai_family == AF_INET6) {
struct in6_ifreq ifr6;
u_int32_t flags6;
memset(&ifr6, 0, sizeof(ifr6));
memcpy(&ifr6.ifr_addr, ai.ai_addr, ai.ai_addrlen);
if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
flags6 = ifr6.ifr_ifru.ifru_flags6;
if ((flags6 & IN6_IFF_DEPRECATED))
aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
}
}
#endif
cleanup:
_close(s);
return;
}
static int
matchlen(struct sockaddr *src, struct sockaddr *dst)
{
int match = 0;
u_char *s, *d;
u_char *lim, r;
int addrlen;
switch (src->sa_family) {
#ifdef INET6
case AF_INET6:
s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
addrlen = sizeof(struct in6_addr);
lim = s + addrlen;
break;
#endif
case AF_INET:
s = (u_char *)&((struct sockaddr_in *)src)->sin_addr;
d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr;
addrlen = sizeof(struct in_addr);
lim = s + addrlen;
break;
default:
return(0);
}
while (s < lim)
if ((r = (*d++ ^ *s++)) != 0) {
while ((r & 0x80) == 0) {
match++;
r <<= 1;
}
break;
} else
match += 8;
return(match);
}
static int
comp_dst(const void *arg1, const void *arg2)
{
const struct ai_order *dst1 = arg1, *dst2 = arg2;
/*
* Rule 1: Avoid unusable destinations.
* XXX: we currently do not consider if an appropriate route exists.
*/
if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
dst2->aio_srcsa.sa_family == AF_UNSPEC) {
return(-1);
}
if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
dst2->aio_srcsa.sa_family != AF_UNSPEC) {
return(1);
}
/* Rule 2: Prefer matching scope. */
if (dst1->aio_dstscope == dst1->aio_srcscope &&
dst2->aio_dstscope != dst2->aio_srcscope) {
return(-1);
}
if (dst1->aio_dstscope != dst1->aio_srcscope &&
dst2->aio_dstscope == dst2->aio_srcscope) {
return(1);
}
/* Rule 3: Avoid deprecated addresses. */
if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
dst2->aio_srcsa.sa_family != AF_UNSPEC) {
if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
return(-1);
}
if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
!(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
return(1);
}
}
/* Rule 4: Prefer home addresses. */
/* XXX: not implemented yet */
/* Rule 5: Prefer matching label. */
#ifdef INET6
if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
dst1->aio_srcpolicy->pc_policy.label ==
dst1->aio_dstpolicy->pc_policy.label &&
(dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
dst2->aio_srcpolicy->pc_policy.label !=
dst2->aio_dstpolicy->pc_policy.label)) {
return(-1);
}
if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
dst2->aio_srcpolicy->pc_policy.label ==
dst2->aio_dstpolicy->pc_policy.label &&
(dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
dst1->aio_srcpolicy->pc_policy.label !=
dst1->aio_dstpolicy->pc_policy.label)) {
return(1);
}
#endif
/* Rule 6: Prefer higher precedence. */
#ifdef INET6
if (dst1->aio_dstpolicy &&
(dst2->aio_dstpolicy == NULL ||
dst1->aio_dstpolicy->pc_policy.preced >
dst2->aio_dstpolicy->pc_policy.preced)) {
return(-1);
}
if (dst2->aio_dstpolicy &&
(dst1->aio_dstpolicy == NULL ||
dst2->aio_dstpolicy->pc_policy.preced >
dst1->aio_dstpolicy->pc_policy.preced)) {
return(1);
}
#endif
/* Rule 7: Prefer native transport. */
/* XXX: not implemented yet */
/* Rule 8: Prefer smaller scope. */
if (dst1->aio_dstscope >= 0 &&
dst1->aio_dstscope < dst2->aio_dstscope) {
return(-1);
}
if (dst2->aio_dstscope >= 0 &&
dst2->aio_dstscope < dst1->aio_dstscope) {
return(1);
}
/*
* Rule 9: Use longest matching prefix.
* We compare the match length in a same AF only.
*/
if (dst1->aio_ai->ai_addr->sa_family ==
dst2->aio_ai->ai_addr->sa_family &&
dst1->aio_ai->ai_addr->sa_family != AF_INET) {
if (dst1->aio_matchlen > dst2->aio_matchlen) {
return(-1);
}
if (dst1->aio_matchlen < dst2->aio_matchlen) {
return(1);
}
}
/* Rule 10: Otherwise, leave the order unchanged. */
/*
* Note that qsort is unstable; so, we can't return zero and
* expect the order to be unchanged.
* That also means we can't depend on the current position of
* dst2 being after dst1. We must enforce the initial order
* with an explicit compare on the original position.
* The qsort specification requires that "When the same objects
* (consisting of width bytes, irrespective of their current
* positions in the array) are passed more than once to the
* comparison function, the results shall be consistent with one
* another."
* In other words, If A < B, then we must also return B > A.
*/
if (dst2->aio_initial_sequence < dst1->aio_initial_sequence)
return(1);
return(-1);
}
/*
* Copy from scope.c.
* XXX: we should standardize the functions and link them as standard
* library.
*/
static int
gai_addr2scopetype(struct sockaddr *sa)
{
#ifdef INET6
struct sockaddr_in6 *sa6;
#endif
struct sockaddr_in *sa4;
switch(sa->sa_family) {
#ifdef INET6
case AF_INET6:
sa6 = (struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
/* just use the scope field of the multicast address */
return(sa6->sin6_addr.s6_addr[2] & 0x0f);
}
/*
* Unicast addresses: map scope type to corresponding scope
* value defined for multcast addresses.
* XXX: hardcoded scope type values are bad...
*/
if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
return(1); /* node local scope */
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
return(2); /* link-local scope */
if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
return(5); /* site-local scope */
return(14); /* global scope */
break;
#endif
case AF_INET:
/*
* IPv4 pseudo scoping according to RFC 3484.
*/
sa4 = (struct sockaddr_in *)sa;
/* IPv4 autoconfiguration addresses have link-local scope. */
if (((u_char *)&sa4->sin_addr)[0] == 169 &&
((u_char *)&sa4->sin_addr)[1] == 254)
return(2);
/* Private addresses have site-local scope. */
if (((u_char *)&sa4->sin_addr)[0] == 10 ||
(((u_char *)&sa4->sin_addr)[0] == 172 &&
(((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
(((u_char *)&sa4->sin_addr)[0] == 192 &&
((u_char *)&sa4->sin_addr)[1] == 168))
return(14); /* XXX: It should be 5 unless NAT */
/* Loopback addresses have link-local scope. */
if (((u_char *)&sa4->sin_addr)[0] == 127)
return(2);
return(14);
break;
default:
errno = EAFNOSUPPORT; /* is this a good error? */
return(-1);
}
}
static int
explore_copy(const struct addrinfo *pai, const struct addrinfo *src0,
struct addrinfo **res)
{
int error;
struct addrinfo sentinel, *cur;
const struct addrinfo *src;
error = 0;
sentinel.ai_next = NULL;
cur = &sentinel;
for (src = src0; src != NULL; src = src->ai_next) {
if (src->ai_family != pai->ai_family)
continue;
cur->ai_next = copy_ai(src);
if (!cur->ai_next) {
error = EAI_MEMORY;
goto fail;
}
cur->ai_next->ai_socktype = pai->ai_socktype;
cur->ai_next->ai_protocol = pai->ai_protocol;
cur = cur->ai_next;
}
*res = sentinel.ai_next;
return 0;
fail:
freeaddrinfo(sentinel.ai_next);
return error;
}
/*
* hostname == NULL.
* passive socket -> anyaddr (0.0.0.0 or ::)
* non-passive socket -> localhost (127.0.0.1 or ::1)
*/
static int
explore_null(const struct addrinfo *pai, const char *servname,
struct addrinfo **res)
{
int s;
const struct afd *afd;
struct addrinfo *ai;
int error;
*res = NULL;
ai = NULL;
if (pai->ai_family == PF_LOCAL)
return (0);
/*
* filter out AFs that are not supported by the kernel
* XXX errno?
*/
s = _socket(pai->ai_family, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (s < 0) {
if (errno != EMFILE)
return 0;
} else
_close(s);
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
if (pai->ai_flags & AI_PASSIVE) {
GET_AI(ai, afd, afd->a_addrany);
GET_PORT(ai, servname);
} else {
GET_AI(ai, afd, afd->a_loopback);
GET_PORT(ai, servname);
}
*res = ai;
return 0;
free:
if (ai != NULL)
freeaddrinfo(ai);
return error;
}
/*
* numeric hostname
*/
static int
explore_numeric(const struct addrinfo *pai, const char *hostname,
const char *servname, struct addrinfo **res, const char *canonname)
{
const struct afd *afd;
struct addrinfo *ai, ai0;
int error;
char pton[PTON_MAX], path[PATH_MAX], *p;
#ifdef CTASSERT
CTASSERT(sizeofmember(struct sockaddr_un, sun_path) <= PATH_MAX);
#endif
*res = NULL;
ai = NULL;
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
switch (afd->a_af) {
case AF_LOCAL:
if (hostname[0] != '/')
ERR(EAI_NONAME);
if (strlen(hostname) > afd->a_addrlen)
ERR(EAI_MEMORY);
/* NUL-termination does not need to be guaranteed. */
strncpy(path, hostname, afd->a_addrlen);
p = &path[0];
break;
case AF_INET:
/*
* RFC3493 requires getaddrinfo() to accept AF_INET formats
* that are accepted by inet_addr() and its family. The
* accepted forms includes the "classful" one, which inet_pton
* does not accept. So we need to separate the case for
* AF_INET.
*/
if (inet_aton(hostname, (struct in_addr *)pton) != 1 ||
hostname[strspn(hostname, "0123456789.xabcdefXABCDEF")] != '\0')
return 0;
p = pton;
break;
default:
if (inet_pton(afd->a_af, hostname, pton) != 1) {
if (pai->ai_family != AF_INET6 ||
(pai->ai_flags & AI_V4MAPPED) != AI_V4MAPPED)
return 0;
if (inet_aton(hostname, (struct in_addr *)pton) != 1)
return 0;
afd = &afdl[N_INET];
ai0 = *pai;
ai0.ai_family = AF_INET;
pai = &ai0;
}
p = pton;
break;
}
if (pai->ai_family == afd->a_af) {
GET_AI(ai, afd, p);
GET_PORT(ai, servname);
if ((pai->ai_family == AF_INET ||
pai->ai_family == AF_INET6) &&
(pai->ai_flags & AI_CANONNAME)) {
/*
* Set the numeric address itself as the canonical
* name, based on a clarification in RFC3493.
*/
GET_CANONNAME(ai, canonname);
}
} else {
/*
* XXX: This should not happen since we already matched the AF
* by find_afd.
*/
ERR(EAI_FAMILY);
}
*res = ai;
return 0;
free:
bad:
if (ai != NULL)
freeaddrinfo(ai);
return error;
}
/*
* numeric hostname with scope
*/
static int
explore_numeric_scope(const struct addrinfo *pai, const char *hostname,
const char *servname, struct addrinfo **res)
{
#if !defined(SCOPE_DELIMITER) || !defined(INET6)
return explore_numeric(pai, hostname, servname, res, hostname);
#else
const struct afd *afd;
struct addrinfo *cur;
int error;
char *cp, *hostname2 = NULL, *scope, *addr;
struct sockaddr_in6 *sin6;
afd = find_afd(pai->ai_family);
if (afd == NULL)
return 0;
if (!afd->a_scoped)
return explore_numeric(pai, hostname, servname, res, hostname);
cp = strchr(hostname, SCOPE_DELIMITER);
if (cp == NULL)
return explore_numeric(pai, hostname, servname, res, hostname);
/*
* Handle special case of <scoped_address><delimiter><scope id>
*/
hostname2 = strdup(hostname);
if (hostname2 == NULL)
return EAI_MEMORY;
/* terminate at the delimiter */
hostname2[cp - hostname] = '\0';
addr = hostname2;
scope = cp + 1;
error = explore_numeric(pai, addr, servname, res, hostname);
if (error == 0) {
u_int32_t scopeid;
for (cur = *res; cur; cur = cur->ai_next) {
if (cur->ai_family != AF_INET6)
continue;
sin6 = (struct sockaddr_in6 *)(void *)cur->ai_addr;
if (ip6_str2scopeid(scope, sin6, &scopeid) == -1) {
free(hostname2);
freeaddrinfo(*res);
*res = NULL;
return(EAI_NONAME); /* XXX: is return OK? */
}
sin6->sin6_scope_id = scopeid;
}
}
free(hostname2);
if (error && *res) {
freeaddrinfo(*res);
*res = NULL;
}
return error;
#endif
}
static int
get_canonname(const struct addrinfo *pai, struct addrinfo *ai, const char *str)
{
if ((pai->ai_flags & AI_CANONNAME) != 0) {
ai->ai_canonname = strdup(str);
if (ai->ai_canonname == NULL)
return EAI_MEMORY;
}
return 0;
}
static struct addrinfo *
get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
{
char *p;
struct addrinfo *ai;
#ifdef INET6
struct in6_addr mapaddr;
if (afd->a_af == AF_INET && (pai->ai_flags & AI_V4MAPPED) != 0) {
afd = &afdl[N_INET6];
_map_v4v6_address(addr, (char *)&mapaddr);
addr = (char *)&mapaddr;
}
#endif
ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+ (afd->a_socklen));
if (ai == NULL)
return NULL;
memcpy(ai, pai, sizeof(struct addrinfo));
ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
memset(ai->ai_addr, 0, (size_t)afd->a_socklen);
ai->ai_addr->sa_len = afd->a_socklen;
ai->ai_addrlen = afd->a_socklen;
if (ai->ai_family == PF_LOCAL) {
size_t n = strnlen(addr, afd->a_addrlen);
ai->ai_addrlen -= afd->a_addrlen - n;
ai->ai_addr->sa_len -= afd->a_addrlen - n;
}
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
p = (char *)(void *)(ai->ai_addr);
memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
return ai;
}
/* XXX need to malloc() the same way we do from other functions! */
static struct addrinfo *
copy_ai(const struct addrinfo *pai)
{
struct addrinfo *ai;
size_t l;
l = sizeof(*ai) + pai->ai_addrlen;
if ((ai = calloc(1, l)) == NULL)
return NULL;
memcpy(ai, pai, sizeof(*ai));
ai->ai_addr = (struct sockaddr *)(void *)(ai + 1);
memcpy(ai->ai_addr, pai->ai_addr, pai->ai_addrlen);
if (pai->ai_canonname) {
l = strlen(pai->ai_canonname) + 1;
if ((ai->ai_canonname = malloc(l)) == NULL) {
free(ai);
return NULL;
}
strlcpy(ai->ai_canonname, pai->ai_canonname, l);
} else {
/* just to make sure */
ai->ai_canonname = NULL;
}
ai->ai_next = NULL;
return ai;
}
static int
get_portmatch(const struct addrinfo *ai, const char *servname)
{
/* get_port does not touch first argument when matchonly == 1. */
/* LINTED const cast */
return get_port((struct addrinfo *)ai, servname, 1);
}
static int
get_port(struct addrinfo *ai, const char *servname, int matchonly)
{
const char *proto;
struct servent *sp;
int port, error;
int allownumeric;
if (servname == NULL)
return 0;
switch (ai->ai_family) {
case AF_LOCAL:
/* AF_LOCAL ignores servname silently. */
return (0);
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
#endif
break;
default:
return 0;
}
switch (ai->ai_socktype) {
case SOCK_RAW:
return EAI_SERVICE;
case SOCK_DGRAM:
case SOCK_STREAM:
case SOCK_SEQPACKET:
allownumeric = 1;
break;
case ANY:
switch (ai->ai_family) {
case AF_INET:
#ifdef AF_INET6
case AF_INET6:
#endif
allownumeric = 1;
break;
default:
allownumeric = 0;
break;
}
break;
default:
return EAI_SOCKTYPE;
}
error = str2number(servname, &port);
if (error == 0) {
if (!allownumeric)
return EAI_SERVICE;
if (port < 0 || port > 65535)
return EAI_SERVICE;
port = htons(port);
} else {
if (ai->ai_flags & AI_NUMERICSERV)
return EAI_NONAME;
switch (ai->ai_protocol) {
case IPPROTO_UDP:
proto = "udp";
break;
case IPPROTO_TCP:
proto = "tcp";
break;
case IPPROTO_SCTP:
proto = "sctp";
break;
case IPPROTO_UDPLITE:
proto = "udplite";
break;
default:
proto = NULL;
break;
}
if ((sp = getservbyname(servname, proto)) == NULL)
return EAI_SERVICE;
port = sp->s_port;
}
if (!matchonly) {
switch (ai->ai_family) {
case AF_INET:
((struct sockaddr_in *)(void *)
ai->ai_addr)->sin_port = port;
break;
#ifdef INET6
case AF_INET6:
((struct sockaddr_in6 *)(void *)
ai->ai_addr)->sin6_port = port;
break;
#endif
}
}
return 0;
}
static const struct afd *
find_afd(int af)
{
const struct afd *afd;
if (af == PF_UNSPEC)
return NULL;
for (afd = afdl; afd->a_af; afd++) {
if (afd->a_af == af)
return afd;
}
return NULL;
}
/*
* RFC 3493: AI_ADDRCONFIG check. Determines which address families are
* configured on the local system and correlates with pai->ai_family value.
* If an address family is not configured on the system, it will not be
* queried for. For this purpose, loopback addresses are not considered
* configured addresses.
*
* XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
* _dns_getaddrinfo.
*/
static int
addrconfig(struct addrinfo *pai)
{
struct ifaddrs *ifaddrs, *ifa;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
int seen_inet = 0, seen_inet6 = 0;
if (getifaddrs(&ifaddrs) != 0)
return (0);
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr == NULL || (ifa->ifa_flags & IFF_UP) == 0)
continue;
switch (ifa->ifa_addr->sa_family) {
case AF_INET:
if (seen_inet)
continue;
sin = (struct sockaddr_in *)(ifa->ifa_addr);
if (htonl(sin->sin_addr.s_addr) == INADDR_LOOPBACK)
continue;
seen_inet = 1;
break;
#ifdef INET6
case AF_INET6:
if (seen_inet6)
continue;
sin6 = (struct sockaddr_in6 *)(ifa->ifa_addr);
if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
continue;
if ((ifa->ifa_flags & IFT_LOOP) != 0 &&
IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr))
continue;
if (is_ifdisabled(ifa->ifa_name))
continue;
seen_inet6 = 1;
break;
#endif
}
}
freeifaddrs(ifaddrs);
switch(pai->ai_family) {
case AF_INET6:
return (seen_inet6);
case AF_INET:
return (seen_inet);
case AF_UNSPEC:
if (seen_inet == seen_inet6)
return (seen_inet);
pai->ai_family = seen_inet ? AF_INET : AF_INET6;
return (1);
}
return (1);
}
#ifdef INET6
static int
is_ifdisabled(char *name)
{
struct in6_ndireq nd;
int fd;
if ((fd = _socket(AF_INET6, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0)
return (-1);
memset(&nd, 0, sizeof(nd));
strlcpy(nd.ifname, name, sizeof(nd.ifname));
if (_ioctl(fd, SIOCGIFINFO_IN6, &nd) < 0) {
_close(fd);
return (-1);
}
_close(fd);
return ((nd.ndi.flags & ND6_IFF_IFDISABLED) != 0);
}
/* convert a string to a scope identifier. XXX: IPv6 specific */
static int
ip6_str2scopeid(char *scope, struct sockaddr_in6 *sin6, u_int32_t *scopeid)
{
u_long lscopeid;
struct in6_addr *a6;
char *ep;
a6 = &sin6->sin6_addr;
/* empty scopeid portion is invalid */
if (*scope == '\0')
return -1;
if (IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
IN6_IS_ADDR_MC_NODELOCAL(a6)) {
/*
* We currently assume a one-to-one mapping between links
* and interfaces, so we simply use interface indices for
* like-local scopes.
*/
*scopeid = if_nametoindex(scope);
if (*scopeid == 0)
goto trynumeric;
return 0;
}
/* still unclear about literal, allow numeric only - placeholder */
if (IN6_IS_ADDR_SITELOCAL(a6) || IN6_IS_ADDR_MC_SITELOCAL(a6))
goto trynumeric;
if (IN6_IS_ADDR_MC_ORGLOCAL(a6))
goto trynumeric;
else
goto trynumeric; /* global */
/* try to convert to a numeric id as a last resort */
trynumeric:
errno = 0;
lscopeid = strtoul(scope, &ep, 10);
*scopeid = (u_int32_t)(lscopeid & 0xffffffffUL);
if (errno == 0 && ep && *ep == '\0' && *scopeid == lscopeid)
return 0;
else
return -1;
}
#endif
#ifdef NS_CACHING
static int
addrinfo_id_func(char *buffer, size_t *buffer_size, va_list ap,
void *cache_mdata)
{
res_state statp;
u_long res_options;
const int op_id = 0; /* identifies the getaddrinfo for the cache */
char *hostname;
struct addrinfo *hints;
char *p;
int ai_flags, ai_family, ai_socktype, ai_protocol;
size_t desired_size, size;
statp = __res_state();
res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
hostname = va_arg(ap, char *);
hints = va_arg(ap, struct addrinfo *);
desired_size = sizeof(res_options) + sizeof(int) + sizeof(int) * 4;
if (hostname != NULL) {
size = strlen(hostname);
desired_size += size + 1;
} else
size = 0;
if (desired_size > *buffer_size) {
*buffer_size = desired_size;
return (NS_RETURN);
}
if (hints == NULL)
ai_flags = ai_family = ai_socktype = ai_protocol = 0;
else {
ai_flags = hints->ai_flags;
ai_family = hints->ai_family;
ai_socktype = hints->ai_socktype;
ai_protocol = hints->ai_protocol;
}
p = buffer;
memcpy(p, &res_options, sizeof(res_options));
p += sizeof(res_options);
memcpy(p, &op_id, sizeof(int));
p += sizeof(int);
memcpy(p, &ai_flags, sizeof(int));
p += sizeof(int);
memcpy(p, &ai_family, sizeof(int));
p += sizeof(int);
memcpy(p, &ai_socktype, sizeof(int));
p += sizeof(int);
memcpy(p, &ai_protocol, sizeof(int));
p += sizeof(int);
if (hostname != NULL)
memcpy(p, hostname, size);
*buffer_size = desired_size;
return (NS_SUCCESS);
}
static int
addrinfo_marshal_func(char *buffer, size_t *buffer_size, void *retval,
va_list ap, void *cache_mdata)
{
struct addrinfo *ai, *cai;
char *p;
size_t desired_size, size, ai_size;
ai = *((struct addrinfo **)retval);
desired_size = sizeof(size_t);
ai_size = 0;
for (cai = ai; cai != NULL; cai = cai->ai_next) {
desired_size += sizeof(struct addrinfo) + cai->ai_addrlen;
if (cai->ai_canonname != NULL)
desired_size += sizeof(size_t) +
strlen(cai->ai_canonname);
++ai_size;
}
if (desired_size > *buffer_size) {
/* this assignment is here for future use */
errno = ERANGE;
*buffer_size = desired_size;
return (NS_RETURN);
}
memset(buffer, 0, desired_size);
p = buffer;
memcpy(p, &ai_size, sizeof(size_t));
p += sizeof(size_t);
for (cai = ai; cai != NULL; cai = cai->ai_next) {
memcpy(p, cai, sizeof(struct addrinfo));
p += sizeof(struct addrinfo);
memcpy(p, cai->ai_addr, cai->ai_addrlen);
p += cai->ai_addrlen;
if (cai->ai_canonname != NULL) {
size = strlen(cai->ai_canonname);
memcpy(p, &size, sizeof(size_t));
p += sizeof(size_t);
memcpy(p, cai->ai_canonname, size);
p += size;
}
}
return (NS_SUCCESS);
}
static int
addrinfo_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
va_list ap, void *cache_mdata)
{
struct addrinfo new_ai, *result, *sentinel, *lasts;
char *p;
size_t ai_size, ai_i, size;
p = buffer;
memcpy(&ai_size, p, sizeof(size_t));
p += sizeof(size_t);
result = NULL;
lasts = NULL;
for (ai_i = 0; ai_i < ai_size; ++ai_i) {
memcpy(&new_ai, p, sizeof(struct addrinfo));
p += sizeof(struct addrinfo);
size = new_ai.ai_addrlen + sizeof(struct addrinfo) +
_ALIGNBYTES;
sentinel = calloc(1, size);
memcpy(sentinel, &new_ai, sizeof(struct addrinfo));
sentinel->ai_addr = (struct sockaddr *)_ALIGN((char *)sentinel +
sizeof(struct addrinfo));
memcpy(sentinel->ai_addr, p, new_ai.ai_addrlen);
p += new_ai.ai_addrlen;
if (new_ai.ai_canonname != NULL) {
memcpy(&size, p, sizeof(size_t));
p += sizeof(size_t);
sentinel->ai_canonname = calloc(1, size + 1);
memcpy(sentinel->ai_canonname, p, size);
p += size;
}
if (result == NULL) {
result = sentinel;
lasts = sentinel;
} else {
lasts->ai_next = sentinel;
lasts = sentinel;
}
}
*((struct addrinfo **)retval) = result;
return (NS_SUCCESS);
}
#endif /* NS_CACHING */
/*
* FQDN hostname, DNS lookup
*/
static int
explore_fqdn(const struct addrinfo *pai, const char *hostname,
const char *servname, struct addrinfo **res)
{
struct addrinfo *result;
struct addrinfo *cur;
int error = 0;
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
hosts, NULL, addrinfo_id_func, addrinfo_marshal_func,
addrinfo_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
NS_FILES_CB(_files_getaddrinfo, NULL)
{ NSSRC_DNS, _dns_getaddrinfo, NULL }, /* force -DHESIOD */
NS_NIS_CB(_yp_getaddrinfo, NULL)
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ 0 }
};
result = NULL;
/*
* if the servname does not match socktype/protocol, ignore it.
*/
if (get_portmatch(pai, servname) != 0)
return 0;
switch (_nsdispatch(&result, dtab, NSDB_HOSTS, "getaddrinfo",
default_dns_files, hostname, pai)) {
case NS_TRYAGAIN:
error = EAI_AGAIN;
goto free;
case NS_UNAVAIL:
error = EAI_FAIL;
goto free;
case NS_NOTFOUND:
error = EAI_NONAME;
goto free;
case NS_ADDRFAMILY:
error = EAI_ADDRFAMILY;
goto free;
case NS_SUCCESS:
error = 0;
for (cur = result; cur; cur = cur->ai_next) {
GET_PORT(cur, servname);
/* canonname should be filled already */
}
break;
}
*res = result;
return 0;
free:
if (result)
freeaddrinfo(result);
return error;
}
#ifdef DEBUG
static const char AskedForGot[] =
"gethostby*.getanswer: asked for \"%s\", got \"%s\"";
#endif
static struct addrinfo *
getanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
const struct addrinfo *pai, res_state res)
{
struct addrinfo sentinel, *cur;
struct addrinfo ai;
const struct afd *afd;
char *canonname;
const HEADER *hp;
const u_char *cp;
int n;
const u_char *eom;
char *bp, *ep;
int type, class, ancount, qdcount;
int haveanswer, had_error;
char tbuf[MAXDNAME];
int (*name_ok)(const char *);
char hostbuf[8*1024];
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
canonname = NULL;
eom = answer->buf + anslen;
switch (qtype) {
case T_A:
case T_AAAA:
case T_ANY: /*use T_ANY only for T_A/T_AAAA lookup*/
name_ok = res_hnok;
break;
default:
return (NULL); /* XXX should be abort(); */
}
/*
* find first satisfactory answer
*/
hp = &answer->hdr;
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
bp = hostbuf;
ep = hostbuf + sizeof hostbuf;
cp = answer->buf + HFIXEDSZ;
if (qdcount != 1) {
RES_SET_H_ERRNO(res, NO_RECOVERY);
return (NULL);
}
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !(*name_ok)(bp)) {
RES_SET_H_ERRNO(res, NO_RECOVERY);
return (NULL);
}
cp += n + QFIXEDSZ;
if (qtype == T_A || qtype == T_AAAA || qtype == T_ANY) {
/* res_send() has already verified that the query name is the
* same as the one we sent; this just gets the expanded name
* (i.e., with the succeeding search-domain tacked on).
*/
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
RES_SET_H_ERRNO(res, NO_RECOVERY);
return (NULL);
}
canonname = bp;
bp += n;
/* The qname can be abbreviated, but h_name is now absolute. */
qname = canonname;
}
haveanswer = 0;
had_error = 0;
while (ancount-- > 0 && cp < eom && !had_error) {
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !(*name_ok)(bp)) {
had_error++;
continue;
}
cp += n; /* name */
type = _getshort(cp);
cp += INT16SZ; /* type */
class = _getshort(cp);
cp += INT16SZ + INT32SZ; /* class, TTL */
n = _getshort(cp);
cp += INT16SZ; /* len */
if (class != C_IN) {
/* XXX - debug? syslog? */
cp += n;
continue; /* XXX - had_error++ ? */
}
if ((qtype == T_A || qtype == T_AAAA || qtype == T_ANY) &&
type == T_CNAME) {
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
if ((n < 0) || !(*name_ok)(tbuf)) {
had_error++;
continue;
}
cp += n;
/* Get canonical name. */
n = strlen(tbuf) + 1; /* for the \0 */
if (n > ep - bp || n >= MAXHOSTNAMELEN) {
had_error++;
continue;
}
strlcpy(bp, tbuf, ep - bp);
canonname = bp;
bp += n;
continue;
}
if (qtype == T_ANY) {
if (!(type == T_A || type == T_AAAA)) {
cp += n;
continue;
}
} else if (type != qtype) {
#ifdef DEBUG
if (type != T_KEY && type != T_SIG &&
type != T_DNAME && type != T_RRSIG)
syslog(LOG_NOTICE|LOG_AUTH,
"gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
qname, p_class(C_IN), p_type(qtype),
p_type(type));
#endif
cp += n;
continue; /* XXX - had_error++ ? */
}
switch (type) {
case T_A:
case T_AAAA:
if (strcasecmp(canonname, bp) != 0) {
#ifdef DEBUG
syslog(LOG_NOTICE|LOG_AUTH,
AskedForGot, canonname, bp);
#endif
cp += n;
continue; /* XXX - had_error++ ? */
}
if (type == T_A && n != INADDRSZ) {
cp += n;
continue;
}
if (type == T_AAAA && n != IN6ADDRSZ) {
cp += n;
continue;
}
#ifdef FILTER_V4MAPPED
if (type == T_AAAA) {
struct in6_addr in6;
memcpy(&in6, cp, sizeof(in6));
if (IN6_IS_ADDR_V4MAPPED(&in6)) {
cp += n;
continue;
}
}
#endif
if (!haveanswer) {
int nn;
canonname = bp;
nn = strlen(bp) + 1; /* for the \0 */
bp += nn;
}
/* don't overwrite pai */
ai = *pai;
ai.ai_family = (type == T_A) ? AF_INET : AF_INET6;
afd = find_afd(ai.ai_family);
if (afd == NULL) {
cp += n;
continue;
}
cur->ai_next = get_ai(&ai, afd, (const char *)cp);
if (cur->ai_next == NULL)
had_error++;
while (cur && cur->ai_next)
cur = cur->ai_next;
cp += n;
break;
default:
abort();
}
if (!had_error)
haveanswer++;
}
if (haveanswer) {
#if defined(RESOLVSORT)
/*
* We support only IPv4 address for backward
* compatibility against gethostbyname(3).
*/
if (res->nsort && qtype == T_A) {
if (addr4sort(&sentinel, res) < 0) {
freeaddrinfo(sentinel.ai_next);
RES_SET_H_ERRNO(res, NO_RECOVERY);
return NULL;
}
}
#endif /*RESOLVSORT*/
if (!canonname)
(void)get_canonname(pai, sentinel.ai_next, qname);
else
(void)get_canonname(pai, sentinel.ai_next, canonname);
RES_SET_H_ERRNO(res, NETDB_SUCCESS);
return sentinel.ai_next;
}
/*
* We could have walked a CNAME chain, but the ultimate target
* may not have what we looked for.
*/
RES_SET_H_ERRNO(res, ntohs(hp->ancount) > 0 ? NO_DATA : NO_RECOVERY);
return NULL;
}
#ifdef RESOLVSORT
struct addr_ptr {
struct addrinfo *ai;
int aval;
};
static int
addr4sort(struct addrinfo *sentinel, res_state res)
{
struct addrinfo *ai;
struct addr_ptr *addrs, addr;
struct sockaddr_in *sin;
int naddrs, i, j;
int needsort = 0;
if (!sentinel)
return -1;
naddrs = 0;
for (ai = sentinel->ai_next; ai; ai = ai->ai_next)
naddrs++;
if (naddrs < 2)
return 0; /* We don't need sorting. */
if ((addrs = malloc(sizeof(struct addr_ptr) * naddrs)) == NULL)
return -1;
i = 0;
for (ai = sentinel->ai_next; ai; ai = ai->ai_next) {
sin = (struct sockaddr_in *)ai->ai_addr;
for (j = 0; (unsigned)j < res->nsort; j++) {
if (res->sort_list[j].addr.s_addr ==
(sin->sin_addr.s_addr & res->sort_list[j].mask))
break;
}
addrs[i].ai = ai;
addrs[i].aval = j;
if (needsort == 0 && i > 0 && j < addrs[i - 1].aval)
needsort = i;
i++;
}
if (!needsort) {
free(addrs);
return 0;
}
while (needsort < naddrs) {
for (j = needsort - 1; j >= 0; j--) {
if (addrs[j].aval > addrs[j+1].aval) {
addr = addrs[j];
addrs[j] = addrs[j + 1];
addrs[j + 1] = addr;
} else
break;
}
needsort++;
}
ai = sentinel;
for (i = 0; i < naddrs; ++i) {
ai->ai_next = addrs[i].ai;
ai = ai->ai_next;
}
ai->ai_next = NULL;
free(addrs);
return 0;
}
#endif /*RESOLVSORT*/
/*ARGSUSED*/
static int
_dns_getaddrinfo(void *rv, void *cb_data, va_list ap)
{
struct addrinfo *ai, ai0;
querybuf *buf, *buf2;
const char *hostname;
const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
struct res_target q, q2;
res_state res;
ai = NULL;
hostname = va_arg(ap, char *);
pai = va_arg(ap, const struct addrinfo *);
memset(&q, 0, sizeof(q));
memset(&q2, 0, sizeof(q2));
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
res = __res_state();
buf = malloc(sizeof(*buf));
if (!buf) {
RES_SET_H_ERRNO(res, NETDB_INTERNAL);
return NS_NOTFOUND;
}
buf2 = malloc(sizeof(*buf2));
if (!buf2) {
free(buf);
RES_SET_H_ERRNO(res, NETDB_INTERNAL);
return NS_NOTFOUND;
}
if (pai->ai_family == AF_INET6 &&
(pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) {
ai0 = *pai;
ai0.ai_family = AF_UNSPEC;
pai = &ai0;
}
switch (pai->ai_family) {
case AF_UNSPEC:
q.name = hostname;
q.qclass = C_IN;
q.qtype = T_A;
q.answer = buf->buf;
q.anslen = sizeof(buf->buf);
q.next = &q2;
q2.name = hostname;
q2.qclass = C_IN;
q2.qtype = T_AAAA;
q2.answer = buf2->buf;
q2.anslen = sizeof(buf2->buf);
break;
case AF_INET:
q.name = hostname;
q.qclass = C_IN;
q.qtype = T_A;
q.answer = buf->buf;
q.anslen = sizeof(buf->buf);
break;
case AF_INET6:
q.name = hostname;
q.qclass = C_IN;
q.qtype = T_AAAA;
q.answer = buf->buf;
q.anslen = sizeof(buf->buf);
break;
default:
free(buf);
free(buf2);
return NS_UNAVAIL;
}
if ((res->options & RES_INIT) == 0 && res_ninit(res) == -1) {
RES_SET_H_ERRNO(res, NETDB_INTERNAL);
free(buf);
free(buf2);
return NS_NOTFOUND;
}
if (res_searchN(hostname, &q, res) < 0) {
free(buf);
free(buf2);
if (res->res_h_errno == NO_DATA)
return (NS_ADDRFAMILY);
return (NS_NOTFOUND);
}
/* prefer IPv6 */
if (q.next) {
ai = getanswer(buf2, q2.n, q2.name, q2.qtype, pai, res);
if (ai != NULL) {
cur->ai_next = ai;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
}
if (ai == NULL || pai->ai_family != AF_UNSPEC ||
(pai->ai_flags & (AI_ALL | AI_V4MAPPED)) != AI_V4MAPPED) {
ai = getanswer(buf, q.n, q.name, q.qtype, pai, res);
if (ai != NULL)
cur->ai_next = ai;
}
free(buf);
free(buf2);
if (sentinel.ai_next == NULL)
switch (res->res_h_errno) {
case HOST_NOT_FOUND:
return (NS_NOTFOUND);
case NO_DATA:
return (NS_ADDRFAMILY);
case TRY_AGAIN:
return (NS_TRYAGAIN);
default:
return (NS_UNAVAIL);
}
*((struct addrinfo **)rv) = sentinel.ai_next;
return (NS_SUCCESS);
}
static void
_sethtent(FILE **hostf)
{
if (!*hostf)
*hostf = fopen(_PATH_HOSTS, "re");
else
rewind(*hostf);
}
static void
_endhtent(FILE **hostf)
{
if (*hostf) {
(void) fclose(*hostf);
*hostf = NULL;
}
}
static struct addrinfo *
_gethtent(FILE **hostf, const char *name, const struct addrinfo *pai)
{
char *p;
char *cp, *tname, *cname;
struct addrinfo hints, *res0, *res;
int error;
const char *addr;
char hostbuf[8*1024];
if (!*hostf && !(*hostf = fopen(_PATH_HOSTS, "re")))
return (NULL);
again:
if (!(p = fgets(hostbuf, sizeof hostbuf, *hostf)))
return (NULL);
if (*p == '#')
goto again;
cp = strpbrk(p, "#\n");
if (cp != NULL)
*cp = '\0';
if (!(cp = strpbrk(p, " \t")))
goto again;
*cp++ = '\0';
addr = p;
cname = NULL;
/* if this is not something we're looking for, skip it. */
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
tname = cp;
if (cname == NULL)
cname = cp;
if ((cp = strpbrk(cp, " \t")) != NULL)
*cp++ = '\0';
if (strcasecmp(name, tname) == 0)
goto found;
}
goto again;
found:
/* we should not glob socktype/protocol here */
memset(&hints, 0, sizeof(hints));
hints.ai_family = pai->ai_family;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = 0;
hints.ai_flags = AI_NUMERICHOST;
if (pai->ai_family == AF_INET6 &&
(pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED)
hints.ai_flags |= AI_V4MAPPED;
error = getaddrinfo(addr, "0", &hints, &res0);
if (error)
goto again;
#ifdef FILTER_V4MAPPED
/* XXX should check all items in the chain */
if (res0->ai_family == AF_INET6 &&
IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)res0->ai_addr)->sin6_addr)) {
freeaddrinfo(res0);
goto again;
}
#endif
for (res = res0; res; res = res->ai_next) {
/* cover it up */
res->ai_flags = pai->ai_flags;
res->ai_socktype = pai->ai_socktype;
res->ai_protocol = pai->ai_protocol;
if (pai->ai_flags & AI_CANONNAME) {
if (get_canonname(pai, res, cname) != 0) {
freeaddrinfo(res0);
goto again;
}
}
}
return res0;
}
static struct addrinfo *
_getht(FILE **hostf, const char *name, const struct addrinfo *pai,
struct addrinfo *cur)
{
struct addrinfo *p;
while ((p = _gethtent(hostf, name, pai)) != NULL) {
cur->ai_next = p;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
return (cur);
}
/*ARGSUSED*/
static int
_files_getaddrinfo(void *rv, void *cb_data, va_list ap)
{
const char *name;
const struct addrinfo *pai;
struct addrinfo sentinel, *cur;
FILE *hostf = NULL;
name = va_arg(ap, char *);
pai = va_arg(ap, struct addrinfo *);
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
_sethtent(&hostf);
if (pai->ai_family == AF_INET6 &&
(pai->ai_flags & (AI_ALL | AI_V4MAPPED)) == AI_V4MAPPED) {
struct addrinfo ai0 = *pai;
ai0.ai_flags &= ~AI_V4MAPPED;
cur = _getht(&hostf, name, &ai0, cur);
if (sentinel.ai_next == NULL) {
_sethtent(&hostf);
ai0.ai_flags |= AI_V4MAPPED;
cur = _getht(&hostf, name, &ai0, cur);
}
} else
cur = _getht(&hostf, name, pai, cur);
_endhtent(&hostf);
*((struct addrinfo **)rv) = sentinel.ai_next;
if (sentinel.ai_next == NULL)
return NS_NOTFOUND;
return NS_SUCCESS;
}
#ifdef YP
/*ARGSUSED*/
static struct addrinfo *
_yphostent(char *line, const struct addrinfo *pai)
{
struct addrinfo sentinel, *cur;
struct addrinfo hints, *res, *res0;
int error;
char *p = line;
const char *addr, *canonname;
char *nextline;
char *cp;
addr = canonname = NULL;
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
nextline:
/* terminate line */
cp = strchr(p, '\n');
if (cp) {
*cp++ = '\0';
nextline = cp;
} else
nextline = NULL;
cp = strpbrk(p, " \t");
if (cp == NULL) {
if (canonname == NULL)
return (NULL);
else
goto done;
}
*cp++ = '\0';
addr = p;
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (!canonname)
canonname = cp;
if ((cp = strpbrk(cp, " \t")) != NULL)
*cp++ = '\0';
}
hints = *pai;
hints.ai_flags = AI_NUMERICHOST;
if (pai->ai_family == AF_INET6 &&
(pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED)
hints.ai_flags |= AI_V4MAPPED;
error = getaddrinfo(addr, NULL, &hints, &res0);
if (error == 0) {
for (res = res0; res; res = res->ai_next) {
/* cover it up */
res->ai_flags = pai->ai_flags;
if (pai->ai_flags & AI_CANONNAME)
(void)get_canonname(pai, res, canonname);
}
} else
res0 = NULL;
if (res0) {
cur->ai_next = res0;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
if (nextline) {
p = nextline;
goto nextline;
}
done:
return sentinel.ai_next;
}
/*ARGSUSED*/
static int
_yp_getaddrinfo(void *rv, void *cb_data, va_list ap)
{
struct addrinfo sentinel, *cur;
struct addrinfo *ai = NULL;
char *ypbuf;
int ypbuflen, r;
const char *name;
const struct addrinfo *pai;
char *ypdomain;
if (_yp_check(&ypdomain) == 0)
return NS_UNAVAIL;
name = va_arg(ap, char *);
pai = va_arg(ap, const struct addrinfo *);
memset(&sentinel, 0, sizeof(sentinel));
cur = &sentinel;
/* ipnodes.byname can hold both IPv4/v6 */
r = yp_match(ypdomain, "ipnodes.byname", name,
(int)strlen(name), &ypbuf, &ypbuflen);
if (r == 0) {
ai = _yphostent(ypbuf, pai);
if (ai) {
cur->ai_next = ai;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
free(ypbuf);
}
if (ai != NULL) {
struct sockaddr_in6 *sin6;
switch (ai->ai_family) {
case AF_INET:
goto done;
case AF_INET6:
sin6 = (struct sockaddr_in6 *)ai->ai_addr;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
goto done;
break;
}
}
/* hosts.byname is only for IPv4 (Solaris8) */
if (pai->ai_family == AF_UNSPEC || pai->ai_family == AF_INET ||
((pai->ai_family == AF_INET6 &&
(pai->ai_flags & AI_V4MAPPED) == AI_V4MAPPED) &&
(ai == NULL || (pai->ai_flags & AI_ALL) == AI_ALL))) {
r = yp_match(ypdomain, "hosts.byname", name,
(int)strlen(name), &ypbuf, &ypbuflen);
if (r == 0) {
struct addrinfo ai4;
ai4 = *pai;
if (pai->ai_family == AF_UNSPEC)
ai4.ai_family = AF_INET;
ai = _yphostent(ypbuf, &ai4);
if (ai) {
cur->ai_next = ai;
while (cur && cur->ai_next)
cur = cur->ai_next;
}
free(ypbuf);
}
}
done:
if (sentinel.ai_next == NULL) {
RES_SET_H_ERRNO(__res_state(), HOST_NOT_FOUND);
return NS_NOTFOUND;
}
*((struct addrinfo **)rv) = sentinel.ai_next;
return NS_SUCCESS;
}
#endif
/* resolver logic */
/*
* Formulate a normal query, send, and await answer.
* Returned answer is placed in supplied buffer "answer".
* Perform preliminary check of answer, returning success only
* if no error is indicated and the answer count is nonzero.
* Return the size of the response on success, -1 on error.
* Error number is left in h_errno.
*
* Caller must parse answer and determine whether it answers the question.
*/
static int
res_queryN(const char *name, struct res_target *target, res_state res)
{
u_char *buf;
HEADER *hp;
int n;
u_int oflags;
struct res_target *t;
int rcode;
int ancount;
rcode = NOERROR;
ancount = 0;
buf = malloc(MAXPACKET);
if (!buf) {
RES_SET_H_ERRNO(res, NETDB_INTERNAL);
return -1;
}
for (t = target; t; t = t->next) {
int class, type;
u_char *answer;
int anslen;
hp = (HEADER *)(void *)t->answer;
/* make it easier... */
class = t->qclass;
type = t->qtype;
answer = t->answer;
anslen = t->anslen;
oflags = res->_flags;
again:
hp->rcode = NOERROR; /* default */
#ifdef DEBUG
if (res->options & RES_DEBUG)
printf(";; res_query(%s, %d, %d)\n", name, class, type);
#endif
n = res_nmkquery(res, QUERY, name, class, type, NULL, 0, NULL,
buf, MAXPACKET);
if (n > 0 && (res->_flags & RES_F_EDNS0ERR) == 0 &&
(res->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U)
n = res_nopt(res, n, buf, MAXPACKET, anslen);
if (n <= 0) {
#ifdef DEBUG
if (res->options & RES_DEBUG)
printf(";; res_query: mkquery failed\n");
#endif
free(buf);
RES_SET_H_ERRNO(res, NO_RECOVERY);
return (n);
}
n = res_nsend(res, buf, n, answer, anslen);
if (n < 0) {
/*
* if the query choked with EDNS0, retry
* without EDNS0
*/
if ((res->options & (RES_USE_EDNS0|RES_USE_DNSSEC))
!= 0U &&
((oflags ^ res->_flags) & RES_F_EDNS0ERR) != 0) {
res->_flags |= RES_F_EDNS0ERR;
if (res->options & RES_DEBUG)
printf(";; res_nquery: retry without EDNS0\n");
goto again;
}
rcode = hp->rcode; /* record most recent error */
#ifdef DEBUG
if (res->options & RES_DEBUG)
printf(";; res_query: send error\n");
#endif
continue;
}
if (n > anslen)
hp->rcode = FORMERR; /* XXX not very informative */
if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
rcode = hp->rcode; /* record most recent error */
#ifdef DEBUG
if (res->options & RES_DEBUG)
printf(";; rcode = %u, ancount=%u\n", hp->rcode,
ntohs(hp->ancount));
#endif
continue;
}
ancount += ntohs(hp->ancount);
t->n = n;
}
free(buf);
if (ancount == 0) {
switch (rcode) {
case NXDOMAIN:
RES_SET_H_ERRNO(res, HOST_NOT_FOUND);
break;
case SERVFAIL:
RES_SET_H_ERRNO(res, TRY_AGAIN);
break;
case NOERROR:
RES_SET_H_ERRNO(res, NO_DATA);
break;
case FORMERR:
case NOTIMP:
case REFUSED:
default:
RES_SET_H_ERRNO(res, NO_RECOVERY);
break;
}
return (-1);
}
return (ancount);
}
/*
* Formulate a normal query, send, and retrieve answer in supplied buffer.
* Return the size of the response on success, -1 on error.
* If enabled, implement search rules until answer or unrecoverable failure
* is detected. Error code, if any, is left in h_errno.
*/
static int
res_searchN(const char *name, struct res_target *target, res_state res)
{
const char *cp, * const *domain;
HEADER *hp = (HEADER *)(void *)target->answer; /*XXX*/
u_int dots;
int trailing_dot, ret, saved_herrno;
int got_nodata = 0, got_servfail = 0, root_on_list = 0;
int tried_as_is = 0;
int searched = 0;
char abuf[MAXDNAME];
errno = 0;
RES_SET_H_ERRNO(res, HOST_NOT_FOUND); /* default, if we never query */
dots = 0;
for (cp = name; *cp; cp++)
dots += (*cp == '.');
trailing_dot = 0;
if (cp > name && *--cp == '.')
trailing_dot++;
/*
* if there aren't any dots, it could be a user-level alias
*/
if (!dots &&
(cp = res_hostalias(res, name, abuf, sizeof(abuf))) != NULL)
return (res_queryN(cp, target, res));
/*
* If there are enough dots in the name, let's just give it a
* try 'as is'. The threshold can be set with the "ndots" option.
* Also, query 'as is', if there is a trailing dot in the name.
*/
saved_herrno = -1;
if (dots >= res->ndots || trailing_dot) {
ret = res_querydomainN(name, NULL, target, res);
if (ret > 0 || trailing_dot)
return (ret);
if (errno == ECONNREFUSED) {
RES_SET_H_ERRNO(res, TRY_AGAIN);
return (-1);
}
switch (res->res_h_errno) {
case NO_DATA:
case HOST_NOT_FOUND:
break;
case TRY_AGAIN:
if (hp->rcode == SERVFAIL)
break;
/* FALLTHROUGH */
default:
return (-1);
}
saved_herrno = res->res_h_errno;
tried_as_is++;
}
/*
* We do at least one level of search if
* - there is no dot and RES_DEFNAME is set, or
* - there is at least one dot, there is no trailing dot,
* and RES_DNSRCH is set.
*/
if ((!dots && (res->options & RES_DEFNAMES)) ||
(dots && !trailing_dot && (res->options & RES_DNSRCH))) {
int done = 0;
for (domain = (const char * const *)res->dnsrch;
*domain && !done;
domain++) {
searched = 1;
if (domain[0][0] == '\0' ||
(domain[0][0] == '.' && domain[0][1] == '\0'))
root_on_list++;
if (root_on_list && tried_as_is)
continue;
ret = res_querydomainN(name, *domain, target, res);
if (ret > 0)
return (ret);
/*
* If no server present, give up.
* If name isn't found in this domain,
* keep trying higher domains in the search list
* (if that's enabled).
* On a NO_DATA error, keep trying, otherwise
* a wildcard entry of another type could keep us
* from finding this entry higher in the domain.
* If we get some other error (negative answer or
* server failure), then stop searching up,
* but try the input name below in case it's
* fully-qualified.
*/
if (errno == ECONNREFUSED) {
RES_SET_H_ERRNO(res, TRY_AGAIN);
return (-1);
}
switch (res->res_h_errno) {
case NO_DATA:
got_nodata++;
/* FALLTHROUGH */
case HOST_NOT_FOUND:
/* keep trying */
break;
case TRY_AGAIN:
got_servfail++;
if (hp->rcode == SERVFAIL) {
/* try next search element, if any */
break;
}
/* FALLTHROUGH */
default:
/* anything else implies that we're done */
done++;
}
/*
* if we got here for some reason other than DNSRCH,
* we only wanted one iteration of the loop, so stop.
*/
if (!(res->options & RES_DNSRCH))
done++;
}
}
switch (res->res_h_errno) {
case NO_DATA:
case HOST_NOT_FOUND:
break;
case TRY_AGAIN:
if (hp->rcode == SERVFAIL)
break;
/* FALLTHROUGH */
default:
goto giveup;
}
/*
* If the query has not already been tried as is then try it
* unless RES_NOTLDQUERY is set and there were no dots.
*/
if ((dots || !searched || !(res->options & RES_NOTLDQUERY)) &&
!(tried_as_is || root_on_list)) {
ret = res_querydomainN(name, NULL, target, res);
if (ret > 0)
return (ret);
}
/*
* if we got here, we didn't satisfy the search.
* if we did an initial full query, return that query's h_errno
* (note that we wouldn't be here if that query had succeeded).
* else if we ever got a nodata, send that back as the reason.
* else send back meaningless h_errno, that being the one from
* the last DNSRCH we did.
*/
giveup:
if (saved_herrno != -1)
RES_SET_H_ERRNO(res, saved_herrno);
else if (got_nodata)
RES_SET_H_ERRNO(res, NO_DATA);
else if (got_servfail)
RES_SET_H_ERRNO(res, TRY_AGAIN);
return (-1);
}
/*
* Perform a call on res_query on the concatenation of name and domain,
* removing a trailing dot from name if domain is NULL.
*/
static int
res_querydomainN(const char *name, const char *domain,
struct res_target *target, res_state res)
{
char nbuf[MAXDNAME];
const char *longname = nbuf;
size_t n, d;
#ifdef DEBUG
if (res->options & RES_DEBUG)
printf(";; res_querydomain(%s, %s)\n",
name, domain?domain:"<Nil>");
#endif
if (domain == NULL) {
/*
* Check for trailing '.';
* copy without '.' if present.
*/
n = strlen(name);
if (n >= MAXDNAME) {
RES_SET_H_ERRNO(res, NO_RECOVERY);
return (-1);
}
if (n > 0 && name[--n] == '.') {
strncpy(nbuf, name, n);
nbuf[n] = '\0';
} else
longname = name;
} else {
n = strlen(name);
d = strlen(domain);
if (n + d + 1 >= MAXDNAME) {
RES_SET_H_ERRNO(res, NO_RECOVERY);
return (-1);
}
snprintf(nbuf, sizeof(nbuf), "%s.%s", name, domain);
}
return (res_queryN(longname, target, res));
}
diff --git a/lib/libc/net/gethostbydns.c b/lib/libc/net/gethostbydns.c
index 4fa86acef139..415a3c32819c 100644
--- a/lib/libc/net/gethostbydns.c
+++ b/lib/libc/net/gethostbydns.c
@@ -1,778 +1,777 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* ++Copyright++ 1985, 1988, 1993
* -
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* -
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
* -
* --Copyright--
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
static char fromrcsid[] = "From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netdb.h>
#include <resolv.h>
#include <ctype.h>
#include <errno.h>
#include <syslog.h>
#include <stdarg.h>
#include <nsswitch.h>
#include "netdb_private.h"
#include "res_config.h"
#define SPRINTF(x) ((size_t)sprintf x)
static const char AskedForGot[] =
"gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
#ifdef RESOLVSORT
static void addrsort(char **, int, res_state);
#endif
#ifdef DEBUG
static void dbg_printf(char *, int, res_state) __printflike(1, 0);
#endif
#define MAXPACKET (64*1024)
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf;
typedef union {
int32_t al;
char ac;
} align;
int _dns_ttl_;
#ifdef DEBUG
static void
dbg_printf(char *msg, int num, res_state res)
{
if (res->options & RES_DEBUG) {
int save = errno;
printf(msg, num);
errno = save;
}
}
#else
# define dbg_printf(msg, num, res) /*nada*/
#endif
#define BOUNDED_INCR(x) \
do { \
cp += x; \
if (cp > eom) { \
RES_SET_H_ERRNO(statp, NO_RECOVERY); \
return (-1); \
} \
} while (0)
#define BOUNDS_CHECK(ptr, count) \
do { \
if ((ptr) + (count) > eom) { \
RES_SET_H_ERRNO(statp, NO_RECOVERY); \
return (-1); \
} \
} while (0)
static int
gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
struct hostent *he, struct hostent_data *hed, res_state statp)
{
const HEADER *hp;
const u_char *cp;
int n;
const u_char *eom, *erdata;
char *bp, *ep, **ap, **hap;
int type, class, ancount, qdcount;
int haveanswer, had_error;
int toobig = 0;
char tbuf[MAXDNAME];
const char *tname;
int (*name_ok)(const char *);
tname = qname;
he->h_name = NULL;
eom = answer->buf + anslen;
switch (qtype) {
case T_A:
case T_AAAA:
name_ok = res_hnok;
break;
case T_PTR:
name_ok = res_dnok;
break;
default:
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1); /* XXX should be abort(); */
}
/*
* find first satisfactory answer
*/
hp = &answer->hdr;
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
bp = hed->hostbuf;
ep = hed->hostbuf + sizeof hed->hostbuf;
cp = answer->buf;
BOUNDED_INCR(HFIXEDSZ);
if (qdcount != 1) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !(*name_ok)(bp)) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
BOUNDED_INCR(n + QFIXEDSZ);
if (qtype == T_A || qtype == T_AAAA) {
/* res_send() has already verified that the query name is the
* same as the one we sent; this just gets the expanded name
* (i.e., with the succeeding search-domain tacked on).
*/
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
he->h_name = bp;
bp += n;
/* The qname can be abbreviated, but h_name is now absolute. */
qname = he->h_name;
}
ap = hed->host_aliases;
*ap = NULL;
he->h_aliases = hed->host_aliases;
hap = hed->h_addr_ptrs;
*hap = NULL;
he->h_addr_list = hed->h_addr_ptrs;
haveanswer = 0;
had_error = 0;
_dns_ttl_ = -1;
while (ancount-- > 0 && cp < eom && !had_error) {
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !(*name_ok)(bp)) {
had_error++;
continue;
}
cp += n; /* name */
BOUNDS_CHECK(cp, 3 * INT16SZ + INT32SZ);
type = _getshort(cp);
cp += INT16SZ; /* type */
class = _getshort(cp);
cp += INT16SZ; /* class */
if (qtype == T_A && type == T_A)
_dns_ttl_ = _getlong(cp);
cp += INT32SZ; /* TTL */
n = _getshort(cp);
cp += INT16SZ; /* len */
BOUNDS_CHECK(cp, n);
erdata = cp + n;
if (class != C_IN) {
/* XXX - debug? syslog? */
cp += n;
continue; /* XXX - had_error++ ? */
}
if ((qtype == T_A || qtype == T_AAAA) && type == T_CNAME) {
if (ap >= &hed->host_aliases[_MAXALIASES-1])
continue;
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
if ((n < 0) || !(*name_ok)(tbuf)) {
had_error++;
continue;
}
cp += n;
if (cp != erdata) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
/* Store alias. */
*ap++ = bp;
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
had_error++;
continue;
}
bp += n;
/* Get canonical name. */
n = strlen(tbuf) + 1; /* for the \0 */
if (n > ep - bp || n >= MAXHOSTNAMELEN) {
had_error++;
continue;
}
strcpy(bp, tbuf);
he->h_name = bp;
bp += n;
continue;
}
if (qtype == T_PTR && type == T_CNAME) {
n = dn_expand(answer->buf, eom, cp, tbuf, sizeof tbuf);
if (n < 0 || !res_dnok(tbuf)) {
had_error++;
continue;
}
cp += n;
if (cp != erdata) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
/* Get canonical name. */
n = strlen(tbuf) + 1; /* for the \0 */
if (n > ep - bp || n >= MAXHOSTNAMELEN) {
had_error++;
continue;
}
strcpy(bp, tbuf);
tname = bp;
bp += n;
continue;
}
if (type != qtype) {
#ifdef DEBUG
if (type != T_KEY && type != T_SIG &&
type != T_DNAME && type != T_RRSIG)
syslog(LOG_NOTICE|LOG_AUTH,
"gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
qname, p_class(C_IN), p_type(qtype),
p_type(type));
#endif
cp += n;
continue; /* XXX - had_error++ ? */
}
switch (type) {
case T_PTR:
if (strcasecmp(tname, bp) != 0) {
syslog(LOG_NOTICE|LOG_AUTH,
AskedForGot, qname, bp);
cp += n;
continue; /* XXX - had_error++ ? */
}
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !res_hnok(bp)) {
had_error++;
break;
}
#if MULTI_PTRS_ARE_ALIASES
cp += n;
if (cp != erdata) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
if (!haveanswer)
he->h_name = bp;
else if (ap < &hed->host_aliases[_MAXALIASES-1])
*ap++ = bp;
else
n = -1;
if (n != -1) {
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
had_error++;
break;
}
bp += n;
}
break;
#else
he->h_name = bp;
if (statp->options & RES_USE_INET6) {
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
had_error++;
break;
}
bp += n;
_map_v4v6_hostent(he, &bp, ep);
}
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
return (0);
#endif
case T_A:
case T_AAAA:
if (strcasecmp(he->h_name, bp) != 0) {
syslog(LOG_NOTICE|LOG_AUTH,
AskedForGot, he->h_name, bp);
cp += n;
continue; /* XXX - had_error++ ? */
}
if (n != he->h_length) {
cp += n;
continue;
}
if (!haveanswer) {
int nn;
he->h_name = bp;
nn = strlen(bp) + 1; /* for the \0 */
bp += nn;
}
bp += sizeof(align) - ((u_long)bp % sizeof(align));
if (bp + n >= ep) {
dbg_printf("size (%d) too big\n", n, statp);
had_error++;
continue;
}
if (hap >= &hed->h_addr_ptrs[_MAXADDRS-1]) {
if (!toobig++)
dbg_printf("Too many addresses (%d)\n",
_MAXADDRS, statp);
cp += n;
continue;
}
memcpy(*hap++ = bp, cp, n);
bp += n;
cp += n;
if (cp != erdata) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
break;
default:
dbg_printf("Impossible condition (type=%d)\n", type,
statp);
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
/* BIND has abort() here, too risky on bad data */
}
if (!had_error)
haveanswer++;
}
if (haveanswer) {
*ap = NULL;
*hap = NULL;
# if defined(RESOLVSORT)
/*
* Note: we sort even if host can take only one address
* in its return structures - should give it the "best"
* address in that case, not some random one
*/
if (statp->nsort && haveanswer > 1 && qtype == T_A)
addrsort(hed->h_addr_ptrs, haveanswer, statp);
# endif /*RESOLVSORT*/
if (!he->h_name) {
n = strlen(qname) + 1; /* for the \0 */
if (n > ep - bp || n >= MAXHOSTNAMELEN)
goto no_recovery;
strcpy(bp, qname);
he->h_name = bp;
bp += n;
}
if (statp->options & RES_USE_INET6)
_map_v4v6_hostent(he, &bp, ep);
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
return (0);
}
no_recovery:
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
/* XXX: for async DNS resolver in ypserv */
struct hostent *
__dns_getanswer(const char *answer, int anslen, const char *qname, int qtype)
{
struct hostent *he;
struct hostent_data *hed;
int error;
res_state statp;
statp = __res_state();
if ((he = __hostent_init()) == NULL ||
(hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (NULL);
}
switch (qtype) {
case T_AAAA:
he->h_addrtype = AF_INET6;
he->h_length = NS_IN6ADDRSZ;
break;
case T_A:
default:
he->h_addrtype = AF_INET;
he->h_length = NS_INADDRSZ;
break;
}
error = gethostanswer((const querybuf *)answer, anslen, qname, qtype,
he, hed, statp);
return (error == 0) ? he : NULL;
}
int
_dns_gethostbyname(void *rval, void *cb_data, va_list ap)
{
const char *name;
int af;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct hostent *hptr, he;
struct hostent_data *hed;
querybuf *buf;
int n, type, error;
res_state statp;
name = va_arg(ap, const char *);
af = va_arg(ap, int);
hptr = va_arg(ap, struct hostent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
*((struct hostent **)rval) = NULL;
statp = __res_state();
if ((hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
he.h_addrtype = af;
switch (af) {
case AF_INET:
he.h_length = NS_INADDRSZ;
type = T_A;
break;
case AF_INET6:
he.h_length = NS_IN6ADDRSZ;
type = T_AAAA;
break;
default:
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
errno = EAFNOSUPPORT;
return (NS_UNAVAIL);
}
if ((buf = malloc(sizeof(*buf))) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
n = res_nsearch(statp, name, C_IN, type, buf->buf, sizeof(buf->buf));
if (n < 0) {
free(buf);
dbg_printf("res_nsearch failed (%d)\n", n, statp);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
} else if (n > sizeof(buf->buf)) {
free(buf);
dbg_printf("static buffer is too small (%d)\n", n, statp);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
error = gethostanswer(buf, n, name, type, &he, hed, statp);
free(buf);
if (error != 0) {
*h_errnop = statp->res_h_errno;
switch (statp->res_h_errno) {
case HOST_NOT_FOUND:
return (NS_NOTFOUND);
case TRY_AGAIN:
return (NS_TRYAGAIN);
default:
return (NS_UNAVAIL);
}
/*NOTREACHED*/
}
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
*((struct hostent **)rval) = hptr;
return (NS_SUCCESS);
}
int
_dns_gethostbyaddr(void *rval, void *cb_data, va_list ap)
{
const void *addr;
socklen_t len;
int af;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
const u_char *uaddr;
struct hostent *hptr, he;
struct hostent_data *hed;
int n;
querybuf *buf;
char qbuf[MAXDNAME+1], *qp;
res_state statp;
#ifdef SUNSECURITY
struct hostdata rhd;
struct hostent *rhe;
char **haddr;
u_long old_options;
char hname2[MAXDNAME+1], numaddr[46];
int ret_h_error;
#endif /*SUNSECURITY*/
addr = va_arg(ap, const void *);
len = va_arg(ap, socklen_t);
af = va_arg(ap, int);
hptr = va_arg(ap, struct hostent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
uaddr = (const u_char *)addr;
*((struct hostent **)rval) = NULL;
statp = __res_state();
if ((hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
switch (af) {
case AF_INET:
(void) sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa",
(uaddr[3] & 0xff),
(uaddr[2] & 0xff),
(uaddr[1] & 0xff),
(uaddr[0] & 0xff));
break;
case AF_INET6:
qp = qbuf;
for (n = NS_IN6ADDRSZ - 1; n >= 0; n--) {
qp += SPRINTF((qp, "%x.%x.",
uaddr[n] & 0xf,
(uaddr[n] >> 4) & 0xf));
}
strlcat(qbuf, "ip6.arpa", sizeof(qbuf));
break;
default:
abort();
}
if ((buf = malloc(sizeof(*buf))) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return NS_NOTFOUND;
}
n = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf->buf,
sizeof buf->buf);
if (n < 0) {
free(buf);
dbg_printf("res_nquery failed (%d)\n", n, statp);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
if (n > sizeof buf->buf) {
free(buf);
dbg_printf("static buffer is too small (%d)\n", n, statp);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
if (gethostanswer(buf, n, qbuf, T_PTR, &he, hed, statp) != 0) {
free(buf);
*h_errnop = statp->res_h_errno;
switch (statp->res_h_errno) {
case HOST_NOT_FOUND:
return (NS_NOTFOUND);
case TRY_AGAIN:
return (NS_TRYAGAIN);
default:
return (NS_UNAVAIL);
}
/*NOTREACHED*/
}
free(buf);
#ifdef SUNSECURITY
if (af == AF_INET) {
/*
* turn off search as the name should be absolute,
* 'localhost' should be matched by defnames
*/
strncpy(hname2, he.h_name, MAXDNAME);
hname2[MAXDNAME] = '\0';
old_options = statp->options;
statp->options &= ~RES_DNSRCH;
statp->options |= RES_DEFNAMES;
memset(&rhd, 0, sizeof rhd);
rhe = gethostbyname_r(hname2, &rhd.host, &rhd.data,
sizeof(rhd.data), &ret_h_error);
if (rhe == NULL) {
if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL)
strlcpy(numaddr, "UNKNOWN", sizeof(numaddr));
syslog(LOG_NOTICE|LOG_AUTH,
"gethostbyaddr: No A record for %s (verifying [%s])",
hname2, numaddr);
statp->options = old_options;
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
statp->options = old_options;
for (haddr = rhe->h_addr_list; *haddr; haddr++)
if (!memcmp(*haddr, addr, NS_INADDRSZ))
break;
if (!*haddr) {
if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL)
strlcpy(numaddr, "UNKNOWN", sizeof(numaddr));
syslog(LOG_NOTICE|LOG_AUTH,
"gethostbyaddr: A record of %s != PTR record [%s]",
hname2, numaddr);
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
}
#endif /*SUNSECURITY*/
he.h_addrtype = af;
he.h_length = len;
memcpy(hed->host_addr, uaddr, len);
hed->h_addr_ptrs[0] = (char *)hed->host_addr;
hed->h_addr_ptrs[1] = NULL;
if (af == AF_INET && (statp->options & RES_USE_INET6)) {
_map_v4v6_address((char*)hed->host_addr, (char*)hed->host_addr);
he.h_addrtype = AF_INET6;
he.h_length = NS_IN6ADDRSZ;
}
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
*((struct hostent **)rval) = hptr;
return (NS_SUCCESS);
}
#ifdef RESOLVSORT
static void
addrsort(char **ap, int num, res_state res)
{
int i, j;
char **p;
short aval[_MAXADDRS];
int needsort = 0;
p = ap;
for (i = 0; i < num; i++, p++) {
for (j = 0 ; (unsigned)j < res->nsort; j++)
if (res->sort_list[j].addr.s_addr ==
(((struct in_addr *)(*p))->s_addr & res->sort_list[j].mask))
break;
aval[i] = j;
if (needsort == 0 && i > 0 && j < aval[i-1])
needsort = i;
}
if (!needsort)
return;
while (needsort < num) {
for (j = needsort - 1; j >= 0; j--) {
if (aval[j] > aval[j+1]) {
char *hp;
i = aval[j];
aval[j] = aval[j+1];
aval[j+1] = i;
hp = ap[j];
ap[j] = ap[j+1];
ap[j+1] = hp;
} else
break;
}
needsort++;
}
}
#endif
void
_sethostdnsent(int stayopen)
{
res_state statp;
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
return;
if (stayopen)
statp->options |= RES_STAYOPEN | RES_USEVC;
}
void
_endhostdnsent(void)
{
res_state statp;
statp = __res_state();
statp->options &= ~(RES_STAYOPEN | RES_USEVC);
res_nclose(statp);
}
diff --git a/lib/libc/net/gethostbyht.c b/lib/libc/net/gethostbyht.c
index ee51b4056d00..15ed0d313c23 100644
--- a/lib/libc/net/gethostbyht.c
+++ b/lib/libc/net/gethostbyht.c
@@ -1,339 +1,338 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* -
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
* -
* --Copyright--
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX */
#include <resolv.h> /* XXX */
#include "netdb_private.h"
void
_sethosthtent(int f, struct hostent_data *hed)
{
if (!hed->hostf)
hed->hostf = fopen(_PATH_HOSTS, "re");
else
rewind(hed->hostf);
hed->stayopen = f;
}
void
_endhosthtent(struct hostent_data *hed)
{
if (hed->hostf && !hed->stayopen) {
(void) fclose(hed->hostf);
hed->hostf = NULL;
}
}
static int
gethostent_p(struct hostent *he, struct hostent_data *hed, int mapped,
res_state statp)
{
char *p, *bp, *ep;
char *cp, **q;
int af, len;
char hostbuf[BUFSIZ + 1];
if (!hed->hostf && !(hed->hostf = fopen(_PATH_HOSTS, "re"))) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
again:
if (!(p = fgets(hostbuf, sizeof hostbuf, hed->hostf))) {
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
return (-1);
}
if (*p == '#')
goto again;
cp = strpbrk(p, "#\n");
if (cp != NULL)
*cp = '\0';
if (!(cp = strpbrk(p, " \t")))
goto again;
*cp++ = '\0';
if (inet_pton(AF_INET6, p, hed->host_addr) > 0) {
af = AF_INET6;
len = IN6ADDRSZ;
} else if (inet_pton(AF_INET, p, hed->host_addr) > 0) {
if (mapped) {
_map_v4v6_address((char *)hed->host_addr,
(char *)hed->host_addr);
af = AF_INET6;
len = IN6ADDRSZ;
} else {
af = AF_INET;
len = INADDRSZ;
}
} else {
goto again;
}
hed->h_addr_ptrs[0] = (char *)hed->host_addr;
hed->h_addr_ptrs[1] = NULL;
he->h_addr_list = hed->h_addr_ptrs;
he->h_length = len;
he->h_addrtype = af;
while (*cp == ' ' || *cp == '\t')
cp++;
bp = hed->hostbuf;
ep = hed->hostbuf + sizeof hed->hostbuf;
he->h_name = bp;
q = he->h_aliases = hed->host_aliases;
if ((p = strpbrk(cp, " \t")) != NULL)
*p++ = '\0';
len = strlen(cp) + 1;
if (ep - bp < len) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
strlcpy(bp, cp, ep - bp);
bp += len;
cp = p;
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q >= &hed->host_aliases[_MAXALIASES - 1])
break;
if ((p = strpbrk(cp, " \t")) != NULL)
*p++ = '\0';
len = strlen(cp) + 1;
if (ep - bp < len)
break;
strlcpy(bp, cp, ep - bp);
*q++ = bp;
bp += len;
cp = p;
}
*q = NULL;
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
return (0);
}
int
gethostent_r(struct hostent *hptr, char *buffer, size_t buflen,
struct hostent **result, int *h_errnop)
{
struct hostent_data *hed;
struct hostent he;
res_state statp;
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (-1);
}
if ((hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (-1);
}
if (gethostent_p(&he, hed, statp->options & RES_USE_INET6, statp) != 0)
return (-1);
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return ((errno != 0) ? errno : -1);
}
*result = hptr;
return (0);
}
struct hostent *
gethostent(void)
{
struct hostdata *hd;
struct hostent *rval;
int ret_h_errno;
if ((hd = __hostdata_init()) == NULL)
return (NULL);
if (gethostent_r(&hd->host, hd->data, sizeof(hd->data), &rval,
&ret_h_errno) != 0)
return (NULL);
return (rval);
}
int
_ht_gethostbyname(void *rval, void *cb_data, va_list ap)
{
const char *name;
int af;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct hostent *hptr, he;
struct hostent_data *hed;
char **cp;
res_state statp;
int error;
name = va_arg(ap, const char *);
af = va_arg(ap, int);
hptr = va_arg(ap, struct hostent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
*((struct hostent **)rval) = NULL;
statp = __res_state();
if ((hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
_sethosthtent(0, hed);
while ((error = gethostent_p(&he, hed, 0, statp)) == 0) {
if (he.h_addrtype != af)
continue;
if (he.h_addrtype == AF_INET &&
statp->options & RES_USE_INET6) {
_map_v4v6_address(he.h_addr, he.h_addr);
he.h_length = IN6ADDRSZ;
he.h_addrtype = AF_INET6;
}
if (strcasecmp(he.h_name, name) == 0)
break;
for (cp = he.h_aliases; *cp != 0; cp++)
if (strcasecmp(*cp, name) == 0)
goto found;
}
found:
_endhosthtent(hed);
if (error != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct hostent **)rval) = hptr;
return (NS_SUCCESS);
}
int
_ht_gethostbyaddr(void *rval, void *cb_data, va_list ap)
{
const void *addr;
socklen_t len;
int af;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct hostent *hptr, he;
struct hostent_data *hed;
res_state statp;
int error;
addr = va_arg(ap, const void *);
len = va_arg(ap, socklen_t);
af = va_arg(ap, int);
hptr = va_arg(ap, struct hostent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
*((struct hostent **)rval) = NULL;
statp = __res_state();
if ((hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
_sethosthtent(0, hed);
while ((error = gethostent_p(&he, hed, 0, statp)) == 0)
if (he.h_addrtype == af && !bcmp(he.h_addr, addr, len)) {
if (he.h_addrtype == AF_INET &&
statp->options & RES_USE_INET6) {
_map_v4v6_address(he.h_addr, he.h_addr);
he.h_length = IN6ADDRSZ;
he.h_addrtype = AF_INET6;
}
break;
}
_endhosthtent(hed);
if (error != 0)
return (NS_NOTFOUND);
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct hostent **)rval) = hptr;
return (NS_SUCCESS);
}
diff --git a/lib/libc/net/gethostbynis.c b/lib/libc/net/gethostbynis.c
index ea503c9dd4c8..2d6abb49b44f 100644
--- a/lib/libc/net/gethostbynis.c
+++ b/lib/libc/net/gethostbynis.c
@@ -1,298 +1,297 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994, Garrett Wollman
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <nsswitch.h>
#include <resolv.h> /* XXX */
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include "netdb_private.h"
#ifdef YP
static int
_gethostbynis(const char *name, char *map, int af, struct hostent *he,
struct hostent_data *hed)
{
char *p, *bp, *ep;
char *cp, **q;
char *result;
int resultlen, size, addrok = 0;
char *ypbuf;
res_state statp;
statp = __res_state();
switch(af) {
case AF_INET:
size = NS_INADDRSZ;
break;
case AF_INET6:
size = NS_IN6ADDRSZ;
break;
default:
errno = EAFNOSUPPORT;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
if (hed->yp_domain == (char *)NULL)
if (yp_get_default_domain (&hed->yp_domain)) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
if (yp_match(hed->yp_domain, map, name, strlen(name), &result,
&resultlen)) {
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
return (-1);
}
/* avoid potential memory leak */
ypbuf = alloca(resultlen + 2);
bcopy(result, ypbuf, resultlen);
ypbuf[resultlen] = '\0';
free(result);
result = ypbuf;
if ((cp = strchr(result, '\n')))
*cp = '\0';
cp = strpbrk(result, " \t");
*cp++ = '\0';
he->h_addr_list = hed->h_addr_ptrs;
he->h_addr = (char *)hed->host_addr;
switch (af) {
case AF_INET:
addrok = inet_aton(result, (struct in_addr *)hed->host_addr);
if (addrok != 1)
break;
if (statp->options & RES_USE_INET6) {
_map_v4v6_address((char *)hed->host_addr,
(char *)hed->host_addr);
af = AF_INET6;
size = NS_IN6ADDRSZ;
}
break;
case AF_INET6:
addrok = inet_pton(af, result, hed->host_addr);
break;
}
if (addrok != 1) {
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
return (-1);
}
he->h_addr_list[1] = NULL;
he->h_length = size;
he->h_addrtype = af;
while (*cp == ' ' || *cp == '\t')
cp++;
bp = hed->hostbuf;
ep = hed->hostbuf + sizeof hed->hostbuf;
he->h_name = bp;
q = he->h_aliases = hed->host_aliases;
p = strpbrk(cp, " \t");
if (p != NULL)
*p++ = '\0';
size = strlen(cp) + 1;
if (ep - bp < size) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
strlcpy(bp, cp, ep - bp);
bp += size;
cp = p;
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q >= &hed->host_aliases[_MAXALIASES - 1])
break;
p = strpbrk(cp, " \t");
if (p != NULL)
*p++ = '\0';
size = strlen(cp) + 1;
if (ep - bp < size)
break;
strlcpy(bp, cp, ep - bp);
*q++ = bp;
bp += size;
cp = p;
}
*q = NULL;
return (0);
}
static int
_gethostbynisname_r(const char *name, int af, struct hostent *he,
struct hostent_data *hed)
{
char *map;
switch (af) {
case AF_INET:
map = "hosts.byname";
break;
default:
map = "ipnodes.byname";
break;
}
return (_gethostbynis(name, map, af, he, hed));
}
static int
_gethostbynisaddr_r(const void *addr, socklen_t len, int af,
struct hostent *he, struct hostent_data *hed)
{
char *map;
char numaddr[46];
switch (af) {
case AF_INET:
map = "hosts.byaddr";
break;
default:
map = "ipnodes.byaddr";
break;
}
if (inet_ntop(af, addr, numaddr, sizeof(numaddr)) == NULL)
return (-1);
return (_gethostbynis(numaddr, map, af, he, hed));
}
#endif /* YP */
int
_nis_gethostbyname(void *rval, void *cb_data, va_list ap)
{
#ifdef YP
const char *name;
int af;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct hostent *hptr, he;
struct hostent_data *hed;
res_state statp;
name = va_arg(ap, const char *);
af = va_arg(ap, int);
hptr = va_arg(ap, struct hostent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
*((struct hostent **)rval) = NULL;
statp = __res_state();
if ((hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (_gethostbynisname_r(name, af, &he, hed) != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct hostent **)rval) = hptr;
return (NS_SUCCESS);
#else
*((struct hostent **)rval) = NULL;
return (NS_UNAVAIL);
#endif
}
int
_nis_gethostbyaddr(void *rval, void *cb_data, va_list ap)
{
#ifdef YP
const void *addr;
socklen_t len;
int af;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct hostent *hptr, he;
struct hostent_data *hed;
res_state statp;
addr = va_arg(ap, const void *);
len = va_arg(ap, socklen_t);
af = va_arg(ap, int);
hptr = va_arg(ap, struct hostent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
*((struct hostent **)rval) = NULL;
statp = __res_state();
if ((hed = __hostent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (_gethostbynisaddr_r(addr, len, af, &he, hed) != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct hostent **)rval) = hptr;
return (NS_SUCCESS);
#else
*((struct hostent **)rval) = NULL;
return (NS_UNAVAIL);
#endif
}
diff --git a/lib/libc/net/gethostnamadr.c b/lib/libc/net/gethostnamadr.c
index 1b60ab0fa00f..b54ca8b2998e 100644
--- a/lib/libc/net/gethostnamadr.c
+++ b/lib/libc/net/gethostnamadr.c
@@ -1,727 +1,726 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994, Garrett Wollman
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <nsswitch.h>
#include <arpa/nameser.h> /* XXX hack for _res */
#include <resolv.h> /* XXX hack for _res */
#include "un-namespace.h"
#include "netdb_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
static int gethostbyname_internal(const char *, int, struct hostent *, char *,
size_t, struct hostent **, int *, res_state);
/* Host lookup order if nsswitch.conf is broken or nonexistent */
static const ns_src default_src[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NSSRC_DNS, NS_SUCCESS },
{ 0 }
};
#ifdef NS_CACHING
static int host_id_func(char *, size_t *, va_list, void *);
static int host_marshal_func(char *, size_t *, void *, va_list, void *);
static int host_unmarshal_func(char *, size_t, void *, va_list, void *);
#endif
NETDB_THREAD_ALLOC(hostent)
NETDB_THREAD_ALLOC(hostent_data)
NETDB_THREAD_ALLOC(hostdata)
static void
hostent_free(void *ptr)
{
free(ptr);
}
static void
hostent_data_free(void *ptr)
{
struct hostent_data *hed = ptr;
if (hed == NULL)
return;
hed->stayopen = 0;
_endhosthtent(hed);
free(hed);
}
static void
hostdata_free(void *ptr)
{
free(ptr);
}
int
__copy_hostent(struct hostent *he, struct hostent *hptr, char *buf,
size_t buflen)
{
char *cp;
char **ptr;
int i, n;
int nptr, len;
/* Find out the amount of space required to store the answer. */
nptr = 2; /* NULL ptrs */
len = (char *)ALIGN(buf) - buf;
for (i = 0; he->h_addr_list[i]; i++, nptr++) {
len += he->h_length;
}
for (i = 0; he->h_aliases[i]; i++, nptr++) {
len += strlen(he->h_aliases[i]) + 1;
}
len += strlen(he->h_name) + 1;
len += nptr * sizeof(char*);
if (len > buflen) {
errno = ERANGE;
return (-1);
}
/* copy address size and type */
hptr->h_addrtype = he->h_addrtype;
n = hptr->h_length = he->h_length;
ptr = (char **)ALIGN(buf);
cp = (char *)ALIGN(buf) + nptr * sizeof(char *);
/* copy address list */
hptr->h_addr_list = ptr;
for (i = 0; he->h_addr_list[i]; i++ , ptr++) {
memcpy(cp, he->h_addr_list[i], n);
hptr->h_addr_list[i] = cp;
cp += n;
}
hptr->h_addr_list[i] = NULL;
ptr++;
/* copy official name */
n = strlen(he->h_name) + 1;
strcpy(cp, he->h_name);
hptr->h_name = cp;
cp += n;
/* copy aliases */
hptr->h_aliases = ptr;
for (i = 0 ; he->h_aliases[i]; i++) {
n = strlen(he->h_aliases[i]) + 1;
strcpy(cp, he->h_aliases[i]);
hptr->h_aliases[i] = cp;
cp += n;
}
hptr->h_aliases[i] = NULL;
return (0);
}
#ifdef NS_CACHING
static int
host_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
{
res_state statp;
u_long res_options;
const int op_id = 1;
char *str;
void *addr;
socklen_t len;
int type;
size_t desired_size, size;
enum nss_lookup_type lookup_type;
char *p;
int res = NS_UNAVAIL;
statp = __res_state();
res_options = statp->options & (RES_RECURSE | RES_DEFNAMES |
RES_DNSRCH | RES_NOALIASES | RES_USE_INET6);
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
switch (lookup_type) {
case nss_lt_name:
str = va_arg(ap, char *);
type = va_arg(ap, int);
size = strlen(str);
desired_size = sizeof(res_options) + sizeof(int) +
sizeof(enum nss_lookup_type) + sizeof(int) + size + 1;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
p = buffer;
memcpy(p, &res_options, sizeof(res_options));
p += sizeof(res_options);
memcpy(p, &op_id, sizeof(int));
p += sizeof(int);
memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
p += sizeof(int);
memcpy(p, &type, sizeof(int));
p += sizeof(int);
memcpy(p, str, size + 1);
res = NS_SUCCESS;
break;
case nss_lt_id:
addr = va_arg(ap, void *);
len = va_arg(ap, socklen_t);
type = va_arg(ap, int);
desired_size = sizeof(res_options) + sizeof(int) +
sizeof(enum nss_lookup_type) + sizeof(int) +
sizeof(socklen_t) + len;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
p = buffer;
memcpy(p, &res_options, sizeof(res_options));
p += sizeof(res_options);
memcpy(p, &op_id, sizeof(int));
p += sizeof(int);
memcpy(p, &lookup_type, sizeof(enum nss_lookup_type));
p += sizeof(int);
memcpy(p, &type, sizeof(int));
p += sizeof(int);
memcpy(p, &len, sizeof(socklen_t));
p += sizeof(socklen_t);
memcpy(p, addr, len);
res = NS_SUCCESS;
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
fin:
*buffer_size = desired_size;
return (res);
}
static int
host_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *str __unused;
void *addr __unused;
socklen_t len __unused;
int type __unused;
struct hostent *ht;
struct hostent new_ht;
size_t desired_size, aliases_size, addr_size, size;
char *p, **iter;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
str = va_arg(ap, char *);
type = va_arg(ap, int);
break;
case nss_lt_id:
addr = va_arg(ap, void *);
len = va_arg(ap, socklen_t);
type = va_arg(ap, int);
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
ht = va_arg(ap, struct hostent *);
desired_size = _ALIGNBYTES + sizeof(struct hostent) + sizeof(char *);
if (ht->h_name != NULL)
desired_size += strlen(ht->h_name) + 1;
if (ht->h_aliases != NULL) {
aliases_size = 0;
for (iter = ht->h_aliases; *iter; ++iter) {
desired_size += strlen(*iter) + 1;
++aliases_size;
}
desired_size += _ALIGNBYTES +
(aliases_size + 1) * sizeof(char *);
}
if (ht->h_addr_list != NULL) {
addr_size = 0;
for (iter = ht->h_addr_list; *iter; ++iter)
++addr_size;
desired_size += addr_size * _ALIGN(ht->h_length);
desired_size += _ALIGNBYTES + (addr_size + 1) * sizeof(char *);
}
if (desired_size > *buffer_size) {
/* this assignment is here for future use */
*buffer_size = desired_size;
return (NS_RETURN);
}
memcpy(&new_ht, ht, sizeof(struct hostent));
memset(buffer, 0, desired_size);
*buffer_size = desired_size;
p = buffer + sizeof(struct hostent) + sizeof(char *);
memcpy(buffer + sizeof(struct hostent), &p, sizeof(char *));
p = (char *)_ALIGN(p);
if (new_ht.h_name != NULL) {
size = strlen(new_ht.h_name);
memcpy(p, new_ht.h_name, size);
new_ht.h_name = p;
p += size + 1;
}
if (new_ht.h_aliases != NULL) {
p = (char *)_ALIGN(p);
memcpy(p, new_ht.h_aliases, sizeof(char *) * aliases_size);
new_ht.h_aliases = (char **)p;
p += sizeof(char *) * (aliases_size + 1);
for (iter = new_ht.h_aliases; *iter; ++iter) {
size = strlen(*iter);
memcpy(p, *iter, size);
*iter = p;
p += size + 1;
}
}
if (new_ht.h_addr_list != NULL) {
p = (char *)_ALIGN(p);
memcpy(p, new_ht.h_addr_list, sizeof(char *) * addr_size);
new_ht.h_addr_list = (char **)p;
p += sizeof(char *) * (addr_size + 1);
size = _ALIGN(new_ht.h_length);
for (iter = new_ht.h_addr_list; *iter; ++iter) {
memcpy(p, *iter, size);
*iter = p;
p += size + 1;
}
}
memcpy(buffer, &new_ht, sizeof(struct hostent));
return (NS_SUCCESS);
}
static int
host_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *str __unused;
void *addr __unused;
socklen_t len __unused;
int type __unused;
struct hostent *ht;
char *p;
char **iter;
char *orig_buf;
size_t orig_buf_size;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
str = va_arg(ap, char *);
type = va_arg(ap, int);
break;
case nss_lt_id:
addr = va_arg(ap, void *);
len = va_arg(ap, socklen_t);
type = va_arg(ap, int);
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
ht = va_arg(ap, struct hostent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
if (orig_buf_size <
buffer_size - sizeof(struct hostent) - sizeof(char *)) {
errno = ERANGE;
return (NS_RETURN);
}
memcpy(ht, buffer, sizeof(struct hostent));
memcpy(&p, buffer + sizeof(struct hostent), sizeof(char *));
orig_buf = (char *)_ALIGN(orig_buf);
memcpy(orig_buf, buffer + sizeof(struct hostent) + sizeof(char *) +
_ALIGN(p) - (size_t)p,
buffer_size - sizeof(struct hostent) - sizeof(char *) -
_ALIGN(p) + (size_t)p);
p = (char *)_ALIGN(p);
NS_APPLY_OFFSET(ht->h_name, orig_buf, p, char *);
if (ht->h_aliases != NULL) {
NS_APPLY_OFFSET(ht->h_aliases, orig_buf, p, char **);
for (iter = ht->h_aliases; *iter; ++iter)
NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
}
if (ht->h_addr_list != NULL) {
NS_APPLY_OFFSET(ht->h_addr_list, orig_buf, p, char **);
for (iter = ht->h_addr_list; *iter; ++iter)
NS_APPLY_OFFSET(*iter, orig_buf, p, char *);
}
*((struct hostent **)retval) = ht;
return (NS_SUCCESS);
}
#endif /* NS_CACHING */
static int
fakeaddr(const char *name, int af, struct hostent *hp, char *buf,
size_t buflen, res_state statp)
{
struct hostent_data *hed;
struct hostent he;
if ((hed = __hostent_data_init()) == NULL) {
errno = ENOMEM;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
if ((af != AF_INET ||
inet_aton(name, (struct in_addr *)hed->host_addr) != 1) &&
inet_pton(af, name, hed->host_addr) != 1) {
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
return (-1);
}
strncpy(hed->hostbuf, name, MAXDNAME);
hed->hostbuf[MAXDNAME] = '\0';
if (af == AF_INET && (statp->options & RES_USE_INET6) != 0U) {
_map_v4v6_address((char *)hed->host_addr,
(char *)hed->host_addr);
af = AF_INET6;
}
he.h_addrtype = af;
switch(af) {
case AF_INET:
he.h_length = NS_INADDRSZ;
break;
case AF_INET6:
he.h_length = NS_IN6ADDRSZ;
break;
default:
errno = EAFNOSUPPORT;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
he.h_name = hed->hostbuf;
he.h_aliases = hed->host_aliases;
hed->host_aliases[0] = NULL;
hed->h_addr_ptrs[0] = (char *)hed->host_addr;
hed->h_addr_ptrs[1] = NULL;
he.h_addr_list = hed->h_addr_ptrs;
if (__copy_hostent(&he, hp, buf, buflen) != 0) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
return (0);
}
int
gethostbyname_r(const char *name, struct hostent *he, char *buffer,
size_t buflen, struct hostent **result, int *h_errnop)
{
res_state statp;
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
if (statp->options & RES_USE_INET6) {
if (fakeaddr(name, AF_INET, he, buffer, buflen, statp) == 0) {
*result = he;
return (0);
}
if (gethostbyname_internal(name, AF_INET6, he, buffer, buflen,
result, h_errnop, statp) == 0)
return (0);
}
return (gethostbyname_internal(name, AF_INET, he, buffer, buflen,
result, h_errnop, statp));
}
int
gethostbyname2_r(const char *name, int af, struct hostent *he, char *buffer,
size_t buflen, struct hostent **result, int *h_errnop)
{
res_state statp;
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (gethostbyname_internal(name, af, he, buffer, buflen, result,
h_errnop, statp));
}
int
gethostbyname_internal(const char *name, int af, struct hostent *hp, char *buf,
size_t buflen, struct hostent **result, int *h_errnop, res_state statp)
{
const char *cp;
int rval, ret_errno = 0;
char abuf[MAXDNAME];
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
hosts, (void *)nss_lt_name,
host_id_func, host_marshal_func, host_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
NS_FILES_CB(_ht_gethostbyname, NULL)
{ NSSRC_DNS, _dns_gethostbyname, NULL },
NS_NIS_CB(_nis_gethostbyname, NULL) /* force -DHESIOD */
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ 0 }
};
switch (af) {
case AF_INET:
case AF_INET6:
break;
default:
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
errno = EAFNOSUPPORT;
return (-1);
}
/*
* if there aren't any dots, it could be a user-level alias.
* this is also done in res_query() since we are not the only
* function that looks up host names.
*/
if (!strchr(name, '.') &&
(cp = res_hostalias(statp, name, abuf, sizeof abuf)))
name = cp;
if (fakeaddr(name, af, hp, buf, buflen, statp) == 0) {
*result = hp;
return (0);
}
rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
"gethostbyname2_r", default_src, name, af, hp, buf, buflen,
&ret_errno, h_errnop);
if (rval != NS_SUCCESS) {
errno = ret_errno;
return ((ret_errno != 0) ? ret_errno : -1);
}
return (0);
}
int
gethostbyaddr_r(const void *addr, socklen_t len, int af, struct hostent *hp,
char *buf, size_t buflen, struct hostent **result, int *h_errnop)
{
const u_char *uaddr = (const u_char *)addr;
const struct in6_addr *addr6;
socklen_t size;
int rval, ret_errno = 0;
res_state statp;
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
hosts, (void *)nss_lt_id,
host_id_func, host_marshal_func, host_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
NS_FILES_CB(_ht_gethostbyaddr, NULL)
{ NSSRC_DNS, _dns_gethostbyaddr, NULL },
NS_NIS_CB(_nis_gethostbyaddr, NULL) /* force -DHESIOD */
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ 0 }
};
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (-1);
}
if (af == AF_INET6 && len == NS_IN6ADDRSZ) {
addr6 = (const struct in6_addr *)addr;
if (IN6_IS_ADDR_LINKLOCAL(addr6)) {
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
*h_errnop = statp->res_h_errno;
return (-1);
}
if (IN6_IS_ADDR_V4MAPPED(addr6) ||
IN6_IS_ADDR_V4COMPAT(addr6)) {
/* Unmap. */
uaddr += NS_IN6ADDRSZ - NS_INADDRSZ;
af = AF_INET;
len = NS_INADDRSZ;
}
}
switch (af) {
case AF_INET:
size = NS_INADDRSZ;
break;
case AF_INET6:
size = NS_IN6ADDRSZ;
break;
default:
errno = EAFNOSUPPORT;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (-1);
}
if (size != len) {
errno = EINVAL;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (-1);
}
rval = _nsdispatch((void *)result, dtab, NSDB_HOSTS,
"gethostbyaddr_r", default_src, uaddr, len, af, hp, buf, buflen,
&ret_errno, h_errnop);
if (rval != NS_SUCCESS) {
errno = ret_errno;
return ((ret_errno != 0) ? ret_errno : -1);
}
return (0);
}
struct hostent *
gethostbyname(const char *name)
{
struct hostdata *hd;
struct hostent *rval;
int ret_h_errno;
if ((hd = __hostdata_init()) == NULL)
return (NULL);
if (gethostbyname_r(name, &hd->host, hd->data, sizeof(hd->data), &rval,
&ret_h_errno) != 0)
return (NULL);
return (rval);
}
struct hostent *
gethostbyname2(const char *name, int af)
{
struct hostdata *hd;
struct hostent *rval;
int ret_h_errno;
if ((hd = __hostdata_init()) == NULL)
return (NULL);
if (gethostbyname2_r(name, af, &hd->host, hd->data, sizeof(hd->data),
&rval, &ret_h_errno) != 0)
return (NULL);
return (rval);
}
struct hostent *
gethostbyaddr(const void *addr, socklen_t len, int af)
{
struct hostdata *hd;
struct hostent *rval;
int ret_h_errno;
if ((hd = __hostdata_init()) == NULL)
return (NULL);
if (gethostbyaddr_r(addr, len, af, &hd->host, hd->data,
sizeof(hd->data), &rval, &ret_h_errno) != 0)
return (NULL);
return (rval);
}
void
sethostent(int stayopen)
{
struct hostent_data *hed;
if ((hed = __hostent_data_init()) == NULL)
return;
_sethosthtent(stayopen, hed);
_sethostdnsent(stayopen);
}
void
endhostent(void)
{
struct hostent_data *hed;
if ((hed = __hostent_data_init()) == NULL)
return;
_endhosthtent(hed);
_endhostdnsent();
}
diff --git a/lib/libc/net/getifaddrs.c b/lib/libc/net/getifaddrs.c
index f42093b76ca6..35d31d46af78 100644
--- a/lib/libc/net/getifaddrs.c
+++ b/lib/libc/net/getifaddrs.c
@@ -1,344 +1,343 @@
/* $KAME: getifaddrs.c,v 1.9 2001/08/20 02:31:20 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-1-Clause
*
* Copyright (c) 1995, 1999
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI getifaddrs.c,v 2.12 2000/02/23 14:51:59 dab Exp
*/
/*
* NOTE: SIOCGIFCONF case is not LP64 friendly. it also does not perform
* try-and-error for region size.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#ifdef NET_RT_IFLIST
#include <sys/param.h>
#include <net/route.h>
#include <sys/sysctl.h>
#include <net/if_dl.h>
#endif
#include <errno.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#if !defined(AF_LINK)
#define SA_LEN(sa) sizeof(struct sockaddr)
#endif
#if !defined(SA_LEN)
#define SA_LEN(sa) (sa)->sa_len
#endif
#define SALIGN (sizeof(long) - 1)
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : (SALIGN + 1))
#ifndef ALIGNBYTES
/*
* On systems with a routing socket, ALIGNBYTES should match the value
* that the kernel uses when building the messages.
*/
#define ALIGNBYTES XXX
#endif
#ifndef ALIGN
#define ALIGN(p) (((u_long)(p) + ALIGNBYTES) &~ ALIGNBYTES)
#endif
#define MAX_SYSCTL_TRY 5
int
getifaddrs(struct ifaddrs **pif)
{
int icnt = 1;
int dcnt = 0;
int ncnt = 0;
int ntry = 0;
int mib[6];
size_t needed;
char *buf;
char *next;
struct ifaddrs *cif;
char *p, *p0;
struct rt_msghdr *rtm;
struct if_msghdrl *ifm;
struct ifa_msghdrl *ifam;
struct sockaddr_dl *dl;
struct sockaddr *sa;
struct ifaddrs *ifa, *ift;
struct if_data *if_data;
u_short idx = 0;
int i;
size_t len, alen;
char *data;
char *names;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
mib[3] = 0; /* wildcard address family */
mib[4] = NET_RT_IFLISTL;/* extra fields for extensible msghdr structs */
mib[5] = 0; /* no flags */
do {
/*
* We'll try to get addresses several times in case that
* the number of addresses is unexpectedly increased during
* the two sysctl calls. This should rarely happen, but we'll
* try to do our best for applications that assume success of
* this library (which should usually be the case).
* Portability note: since FreeBSD does not add margin of
* memory at the first sysctl, the possibility of failure on
* the second sysctl call is a bit higher.
*/
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return (-1);
if ((buf = malloc(needed)) == NULL)
return (-1);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
free(buf);
return (-1);
}
free(buf);
buf = NULL;
}
} while (buf == NULL);
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case RTM_IFINFO:
ifm = (struct if_msghdrl *)(void *)rtm;
if (ifm->ifm_addrs & RTA_IFP) {
idx = ifm->ifm_index;
++icnt;
if_data = IF_MSGHDRL_IFM_DATA(ifm);
dcnt += if_data->ifi_datalen;
dl = (struct sockaddr_dl *)IF_MSGHDRL_RTA(ifm);
dcnt += SA_RLEN((struct sockaddr *)(void*)dl) +
ALIGNBYTES;
ncnt += dl->sdl_nlen + 1;
} else
idx = 0;
break;
case RTM_NEWADDR:
ifam = (struct ifa_msghdrl *)(void *)rtm;
if (idx && ifam->ifam_index != idx)
abort(); /* this cannot happen */
#define RTA_MASKS (RTA_NETMASK | RTA_IFA | RTA_BRD)
if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
break;
p = (char *)IFA_MSGHDRL_RTA(ifam);
++icnt;
if_data = IFA_MSGHDRL_IFAM_DATA(ifam);
dcnt += if_data->ifi_datalen + ALIGNBYTES;
/* Scan to look for length of address */
alen = 0;
for (p0 = p, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
if (i == RTAX_IFA) {
alen = len;
break;
}
p += len;
}
for (p = p0, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
if (i == RTAX_NETMASK && SA_LEN(sa) == 0)
dcnt += alen;
else
dcnt += len;
p += len;
}
break;
}
}
if (icnt + dcnt + ncnt == 1) {
*pif = NULL;
free(buf);
return (0);
}
data = malloc(sizeof(struct ifaddrs) * icnt + dcnt + ncnt);
if (data == NULL) {
free(buf);
return(-1);
}
ifa = (struct ifaddrs *)(void *)data;
data += sizeof(struct ifaddrs) * icnt;
names = data + dcnt;
memset(ifa, 0, sizeof(struct ifaddrs) * icnt);
ift = ifa;
idx = 0;
cif = NULL;
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case RTM_IFINFO:
ifm = (struct if_msghdrl *)(void *)rtm;
if ((ifm->ifm_addrs & RTA_IFP) == 0) {
idx = 0;
break;
}
idx = ifm->ifm_index;
dl = (struct sockaddr_dl *)IF_MSGHDRL_RTA(ifm);
cif = ift;
ift->ifa_name = names;
ift->ifa_flags = (int)ifm->ifm_flags;
memcpy(names, dl->sdl_data, (size_t)dl->sdl_nlen);
names[dl->sdl_nlen] = 0;
names += dl->sdl_nlen + 1;
ift->ifa_addr = (struct sockaddr *)(void *)data;
memcpy(data, dl, (size_t)SA_LEN((struct sockaddr *)
(void *)dl));
data += SA_RLEN((struct sockaddr *)(void *)dl);
if_data = IF_MSGHDRL_IFM_DATA(ifm);
/* ifm_data needs to be aligned */
ift->ifa_data = data = (void *)ALIGN(data);
memcpy(data, if_data, if_data->ifi_datalen);
data += if_data->ifi_datalen;
ift = (ift->ifa_next = ift + 1);
break;
case RTM_NEWADDR:
ifam = (struct ifa_msghdrl *)(void *)rtm;
if (idx && ifam->ifam_index != idx)
abort(); /* this cannot happen */
if (idx == 0 || (ifam->ifam_addrs & RTA_MASKS) == 0)
break;
ift->ifa_name = cif->ifa_name;
ift->ifa_flags = cif->ifa_flags;
ift->ifa_data = NULL;
p = (char *)IFA_MSGHDRL_RTA(ifam);
/* Scan to look for length of address */
alen = 0;
for (p0 = p, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
if (i == RTAX_IFA) {
alen = len;
break;
}
p += len;
}
for (p = p0, i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifam->ifam_addrs & (1 << i))
== 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
switch (i) {
case RTAX_IFA:
ift->ifa_addr =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_NETMASK:
ift->ifa_netmask =
(struct sockaddr *)(void *)data;
if (SA_LEN(sa) == 0) {
memset(data, 0, alen);
data += alen;
break;
}
memcpy(data, p, len);
data += len;
break;
case RTAX_BRD:
ift->ifa_broadaddr =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
}
p += len;
}
if_data = IFA_MSGHDRL_IFAM_DATA(ifam);
/* ifam_data needs to be aligned */
ift->ifa_data = data = (void *)ALIGN(data);
memcpy(data, if_data, if_data->ifi_datalen);
data += if_data->ifi_datalen;
ift = (ift->ifa_next = ift + 1);
break;
}
}
free(buf);
if (--ift >= ifa) {
ift->ifa_next = NULL;
*pif = ifa;
} else {
*pif = NULL;
free(ifa);
}
return (0);
}
void
freeifaddrs(struct ifaddrs *ifp)
{
free(ifp);
}
diff --git a/lib/libc/net/getifmaddrs.c b/lib/libc/net/getifmaddrs.c
index d2f41e341568..415c25f11968 100644
--- a/lib/libc/net/getifmaddrs.c
+++ b/lib/libc/net/getifmaddrs.c
@@ -1,197 +1,196 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Bruce M. Simpson.
* All rights reserved
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/route.h>
#include <errno.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#define SALIGN (sizeof(long) - 1)
#define SA_RLEN(sa) ((sa)->sa_len ? (((sa)->sa_len + SALIGN) & ~SALIGN) : \
(SALIGN + 1))
#define MAX_SYSCTL_TRY 5
#define RTA_MASKS (RTA_GATEWAY | RTA_IFP | RTA_IFA)
int
getifmaddrs(struct ifmaddrs **pif)
{
int icnt = 1;
int dcnt = 0;
int ntry = 0;
size_t len;
size_t needed;
int mib[6];
int i;
char *buf;
char *data;
char *next;
char *p;
struct ifma_msghdr *ifmam;
struct ifmaddrs *ifa, *ift;
struct rt_msghdr *rtm;
struct sockaddr *sa;
mib[0] = CTL_NET;
mib[1] = PF_ROUTE;
mib[2] = 0; /* protocol */
mib[3] = 0; /* wildcard address family */
mib[4] = NET_RT_IFMALIST;
mib[5] = 0; /* no flags */
do {
if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
return (-1);
if ((buf = malloc(needed)) == NULL)
return (-1);
if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
free(buf);
return (-1);
}
free(buf);
buf = NULL;
}
} while (buf == NULL);
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case RTM_NEWMADDR:
ifmam = (struct ifma_msghdr *)(void *)rtm;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break;
icnt++;
p = (char *)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs &
(1 << i)) == 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
dcnt += len;
p += len;
}
break;
}
}
data = malloc(sizeof(struct ifmaddrs) * icnt + dcnt);
if (data == NULL) {
free(buf);
return (-1);
}
ifa = (struct ifmaddrs *)(void *)data;
data += sizeof(struct ifmaddrs) * icnt;
memset(ifa, 0, sizeof(struct ifmaddrs) * icnt);
ift = ifa;
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next;
if (rtm->rtm_version != RTM_VERSION)
continue;
switch (rtm->rtm_type) {
case RTM_NEWMADDR:
ifmam = (struct ifma_msghdr *)(void *)rtm;
if ((ifmam->ifmam_addrs & RTA_IFA) == 0)
break;
p = (char *)(ifmam + 1);
for (i = 0; i < RTAX_MAX; i++) {
if ((RTA_MASKS & ifmam->ifmam_addrs &
(1 << i)) == 0)
continue;
sa = (struct sockaddr *)(void *)p;
len = SA_RLEN(sa);
switch (i) {
case RTAX_GATEWAY:
ift->ifma_lladdr =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_IFP:
ift->ifma_name =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
case RTAX_IFA:
ift->ifma_addr =
(struct sockaddr *)(void *)data;
memcpy(data, p, len);
data += len;
break;
default:
data += len;
break;
}
p += len;
}
ift->ifma_next = ift + 1;
ift = ift->ifma_next;
break;
}
}
free(buf);
if (ift > ifa) {
ift--;
ift->ifma_next = NULL;
*pif = ifa;
} else {
*pif = NULL;
free(ifa);
}
return (0);
}
void
freeifmaddrs(struct ifmaddrs *ifmp)
{
free(ifmp);
}
diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c
index b299b596e343..7ab490abb67f 100644
--- a/lib/libc/net/getnameinfo.c
+++ b/lib/libc/net/getnameinfo.c
@@ -1,535 +1,534 @@
/* $KAME: getnameinfo.c,v 1.61 2002/06/27 09:25:47 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* Copyright (c) 2000 Ben Harris.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Issues to be discussed:
* - Thread safe-ness must be checked
* - RFC2553 says that we should raise error on short buffer. X/Open says
* we need to truncate the result. We obey RFC2553 (and X/Open should be
* modified). ipngwg rough consensus seems to follow RFC2553.
* - What is "local" in NI_FQDN?
* - NI_NAMEREQD and NI_NUMERICHOST conflict with each other.
* - (KAME extension) always attach textual scopeid (fe80::1%lo0), if
* sin6_scope_id is filled - standardization status?
* XXX breaks backward compat for code that expects no scopeid.
* beware on merge.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <net/if_types.h>
#include <net/firewire.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <string.h>
#include <stddef.h>
#include <errno.h>
static const struct afd *find_afd(int);
static int getnameinfo_inet(const struct afd *,
const struct sockaddr *, socklen_t, char *,
size_t, char *, size_t, int);
#ifdef INET6
static int ip6_parsenumeric(const struct sockaddr *, const char *, char *,
size_t, int);
static int ip6_sa2str(const struct sockaddr_in6 *, char *, size_t, int);
#endif
static int getnameinfo_link(const struct afd *,
const struct sockaddr *, socklen_t, char *,
size_t, char *, size_t, int);
static int hexname(const u_int8_t *, size_t, char *, size_t);
static int getnameinfo_un(const struct afd *,
const struct sockaddr *, socklen_t, char *,
size_t, char *, size_t, int);
static const struct afd {
int a_af;
size_t a_addrlen;
socklen_t a_socklen;
int a_off;
int (*a_func)(const struct afd *,
const struct sockaddr *, socklen_t, char *,
size_t, char *, size_t, int);
} afdl [] = {
#ifdef INET6
{PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
offsetof(struct sockaddr_in6, sin6_addr),
getnameinfo_inet},
#endif
{PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
offsetof(struct sockaddr_in, sin_addr),
getnameinfo_inet},
#define sizeofmember(type, member) (sizeof(((type *)0)->member))
{PF_LOCAL, sizeofmember(struct sockaddr_un, sun_path),
sizeof(struct sockaddr_un),
offsetof(struct sockaddr_un, sun_path),
getnameinfo_un},
{PF_LINK, sizeofmember(struct sockaddr_dl, sdl_data),
sizeof(struct sockaddr_dl),
offsetof(struct sockaddr_dl, sdl_data),
getnameinfo_link},
{0, 0, 0},
};
int
getnameinfo(const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen,
int flags)
{
const struct afd *afd;
if (sa == NULL)
return (EAI_FAIL);
afd = find_afd(sa->sa_family);
if (afd == NULL)
return (EAI_FAMILY);
/*
* getnameinfo() accepts an salen of sizeof(struct sockaddr_storage)
* at maximum as shown in RFC 4038 Sec.6.2.3.
*/
if (salen > sizeof(struct sockaddr_storage))
return (EAI_FAMILY);
switch (sa->sa_family) {
case PF_LOCAL:
/*
* PF_LOCAL uses variable salen depending on the
* content length of sun_path. Require 1 byte in
* sun_path at least.
*/
if (salen <= afd->a_socklen -
sizeofmember(struct sockaddr_un, sun_path))
return (EAI_FAMILY);
else if (salen > afd->a_socklen)
salen = afd->a_socklen;
break;
case PF_LINK:
if (salen <= afd->a_socklen -
sizeofmember(struct sockaddr_dl, sdl_data))
return (EAI_FAMILY);
break;
default:
if (salen < afd->a_socklen)
return (EAI_FAMILY);
else
salen = afd->a_socklen;
break;
}
return ((*afd->a_func)(afd, sa, salen, host, hostlen,
serv, servlen, flags));
}
static const struct afd *
find_afd(int af)
{
const struct afd *afd;
if (af == PF_UNSPEC)
return (NULL);
for (afd = &afdl[0]; afd->a_af > 0; afd++) {
if (afd->a_af == af)
return (afd);
}
return (NULL);
}
static int
getnameinfo_inet(const struct afd *afd,
const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen,
int flags)
{
struct servent *sp;
struct hostent *hp;
u_short port;
const char *addr;
u_int32_t v4a;
int h_error;
char numserv[512];
char numaddr[512];
/* network byte order */
port = ((const struct sockaddr_in *)sa)->sin_port;
addr = (const char *)sa + afd->a_off;
if (serv == NULL || servlen == 0) {
/*
* do nothing in this case.
* in case you are wondering if "&&" is more correct than
* "||" here: rfc2553bis-03 says that serv == NULL OR
* servlen == 0 means that the caller does not want the result.
*/
} else {
if (flags & NI_NUMERICSERV)
sp = NULL;
else {
sp = getservbyport(port,
(flags & NI_DGRAM) ? "udp" : "tcp");
}
if (sp) {
if (strlen(sp->s_name) + 1 > servlen)
return EAI_MEMORY;
strlcpy(serv, sp->s_name, servlen);
} else {
snprintf(numserv, sizeof(numserv), "%u", ntohs(port));
if (strlen(numserv) + 1 > servlen)
return EAI_MEMORY;
strlcpy(serv, numserv, servlen);
}
}
switch (sa->sa_family) {
case AF_INET:
v4a = (u_int32_t)
ntohl(((const struct sockaddr_in *)sa)->sin_addr.s_addr);
if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a) ||
IN_ZERONET(v4a))
flags |= NI_NUMERICHOST;
break;
#ifdef INET6
case AF_INET6:
{
const struct sockaddr_in6 *sin6;
sin6 = (const struct sockaddr_in6 *)sa;
switch (sin6->sin6_addr.s6_addr[0]) {
case 0x00:
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
;
else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
;
else
flags |= NI_NUMERICHOST;
break;
default:
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
flags |= NI_NUMERICHOST;
}
else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
flags |= NI_NUMERICHOST;
break;
}
}
break;
#endif
}
if (host == NULL || hostlen == 0) {
/*
* do nothing in this case.
* in case you are wondering if "&&" is more correct than
* "||" here: rfc2553bis-03 says that host == NULL or
* hostlen == 0 means that the caller does not want the result.
*/
} else if (flags & NI_NUMERICHOST) {
size_t numaddrlen;
/* NUMERICHOST and NAMEREQD conflicts with each other */
if (flags & NI_NAMEREQD)
return EAI_NONAME;
switch(afd->a_af) {
#ifdef INET6
case AF_INET6:
{
int error;
if ((error = ip6_parsenumeric(sa, addr, host,
hostlen, flags)) != 0)
return(error);
break;
}
#endif
default:
if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
== NULL)
return EAI_SYSTEM;
numaddrlen = strlen(numaddr);
if (numaddrlen + 1 > hostlen) /* don't forget terminator */
return EAI_MEMORY;
strlcpy(host, numaddr, hostlen);
break;
}
} else {
hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
if (hp) {
#if 0
/*
* commented out, since "for local host" is not
* implemented here - see RFC2553 p30
*/
if (flags & NI_NOFQDN) {
char *p;
p = strchr(hp->h_name, '.');
if (p)
*p = '\0';
}
#endif
if (strlen(hp->h_name) + 1 > hostlen) {
freehostent(hp);
return EAI_MEMORY;
}
strlcpy(host, hp->h_name, hostlen);
freehostent(hp);
} else {
if (flags & NI_NAMEREQD)
return EAI_NONAME;
switch(afd->a_af) {
#ifdef INET6
case AF_INET6:
{
int error;
if ((error = ip6_parsenumeric(sa, addr, host,
hostlen,
flags)) != 0)
return(error);
break;
}
#endif
default:
if (inet_ntop(afd->a_af, addr, host,
hostlen) == NULL)
return EAI_SYSTEM;
break;
}
}
}
return(0);
}
#ifdef INET6
static int
ip6_parsenumeric(const struct sockaddr *sa, const char *addr,
char *host, size_t hostlen, int flags)
{
size_t numaddrlen;
char numaddr[512];
if (inet_ntop(AF_INET6, addr, numaddr, sizeof(numaddr)) == NULL)
return EAI_SYSTEM;
numaddrlen = strlen(numaddr);
if (numaddrlen + 1 > hostlen) /* don't forget terminator */
return EAI_OVERFLOW;
strlcpy(host, numaddr, hostlen);
if (((const struct sockaddr_in6 *)sa)->sin6_scope_id) {
char zonebuf[MAXHOSTNAMELEN];
int zonelen;
zonelen = ip6_sa2str(
(const struct sockaddr_in6 *)(const void *)sa,
zonebuf, sizeof(zonebuf), flags);
if (zonelen < 0)
return EAI_OVERFLOW;
if (zonelen + 1 + numaddrlen + 1 > hostlen)
return EAI_OVERFLOW;
/* construct <numeric-addr><delim><zoneid> */
memcpy(host + numaddrlen + 1, zonebuf,
(size_t)zonelen);
host[numaddrlen] = SCOPE_DELIMITER;
host[numaddrlen + 1 + zonelen] = '\0';
}
return 0;
}
/* ARGSUSED */
static int
ip6_sa2str(const struct sockaddr_in6 *sa6, char *buf, size_t bufsiz, int flags)
{
unsigned int ifindex;
const struct in6_addr *a6;
int n;
ifindex = (unsigned int)sa6->sin6_scope_id;
a6 = &sa6->sin6_addr;
if ((flags & NI_NUMERICSCOPE) != 0) {
n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
if (n < 0 || n >= bufsiz)
return -1;
else
return n;
}
/* if_indextoname() does not take buffer size. not a good api... */
if ((IN6_IS_ADDR_LINKLOCAL(a6) || IN6_IS_ADDR_MC_LINKLOCAL(a6) ||
IN6_IS_ADDR_MC_NODELOCAL(a6)) && bufsiz >= IF_NAMESIZE) {
char *p = if_indextoname(ifindex, buf);
if (p) {
return(strlen(p));
}
}
/* last resort */
n = snprintf(buf, bufsiz, "%u", sa6->sin6_scope_id);
if (n < 0 || (size_t)n >= bufsiz)
return -1;
else
return n;
}
#endif /* INET6 */
/*
* getnameinfo_link():
* Format a link-layer address into a printable format, paying attention to
* the interface type.
*/
/* ARGSUSED */
static int
getnameinfo_link(const struct afd *afd,
const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen, int flags)
{
const struct sockaddr_dl *sdl =
(const struct sockaddr_dl *)(const void *)sa;
const struct fw_hwaddr *iha;
int n;
if (serv != NULL && servlen > 0)
*serv = '\0';
if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 && sdl->sdl_slen == 0) {
n = snprintf(host, hostlen, "link#%d", sdl->sdl_index);
if (n >= hostlen) {
*host = '\0';
return (EAI_MEMORY);
}
return (0);
}
if (sdl->sdl_nlen > 0 && sdl->sdl_alen == 0) {
n = sdl->sdl_nlen;
if (n >= hostlen) {
*host = '\0';
return (EAI_MEMORY);
}
memcpy(host, sdl->sdl_data, sdl->sdl_nlen);
host[n] = '\0';
return (0);
}
switch (sdl->sdl_type) {
case IFT_IEEE1394:
if (sdl->sdl_alen < sizeof(iha->sender_unique_ID_hi) +
sizeof(iha->sender_unique_ID_lo))
return EAI_FAMILY;
iha = (const struct fw_hwaddr *)(const void *)LLADDR(sdl);
return hexname((const u_int8_t *)&iha->sender_unique_ID_hi,
sizeof(iha->sender_unique_ID_hi) +
sizeof(iha->sender_unique_ID_lo),
host, hostlen);
/*
* The following have zero-length addresses.
* IFT_GIF (net/if_gif.c)
* IFT_LOOP (net/if_loop.c)
* IFT_PPP (net/if_tuntap.c)
* IFT_SLIP (net/if_sl.c, net/if_strip.c)
* IFT_STF (net/if_stf.c)
* IFT_L2VLAN (net/if_vlan.c)
* IFT_BRIDGE (net/if_bridge.h>
*/
/*
* The following use IPv4 addresses as link-layer addresses:
* IFT_OTHER (net/if_gre.c)
* IFT_OTHER (netinet/ip_ipip.c)
*/
/* default below is believed correct for all these. */
case IFT_ETHER:
case IFT_FDDI:
case IFT_HIPPI:
case IFT_ISO88025:
default:
return hexname((u_int8_t *)LLADDR(sdl), (size_t)sdl->sdl_alen,
host, hostlen);
}
}
static int
hexname(const u_int8_t *cp, size_t len, char *host, size_t hostlen)
{
int i, n;
char *outp = host;
*outp = '\0';
for (i = 0; i < len; i++) {
n = snprintf(outp, hostlen, "%s%02x",
i ? ":" : "", cp[i]);
if (n < 0 || n >= hostlen) {
*host = '\0';
return EAI_MEMORY;
}
outp += n;
hostlen -= n;
}
return 0;
}
/*
* getnameinfo_un():
* Format a UNIX IPC domain address (pathname).
*/
/* ARGSUSED */
static int
getnameinfo_un(const struct afd *afd,
const struct sockaddr *sa, socklen_t salen,
char *host, size_t hostlen, char *serv, size_t servlen, int flags)
{
size_t pathlen;
if (serv != NULL && servlen > 0)
*serv = '\0';
if (host != NULL && hostlen > 0) {
pathlen = salen - afd->a_off;
if (pathlen + 1 > hostlen) {
*host = '\0';
return (EAI_MEMORY);
}
strlcpy(host, (const char *)sa + afd->a_off, pathlen + 1);
}
return (0);
}
diff --git a/lib/libc/net/getnetbydns.c b/lib/libc/net/getnetbydns.c
index c2a8310e4172..f89e22c50571 100644
--- a/lib/libc/net/getnetbydns.c
+++ b/lib/libc/net/getnetbydns.c
@@ -1,465 +1,464 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* -
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
* -
* --Copyright--
*/
/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
* Dep. Matematica Universidade de Coimbra, Portugal, Europe
*
* 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <resolv.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <stdarg.h>
#include <nsswitch.h>
#include "netdb_private.h"
#include "res_config.h"
#define BYADDR 0
#define BYNAME 1
#define MAXPACKET (64*1024)
typedef union {
HEADER hdr;
u_char buf[MAXPACKET];
} querybuf;
typedef union {
long al;
char ac;
} align;
/*
* Reverse the order of first four dotted entries of in.
* Out must contain space for at least strlen(in) characters.
* The result does not include any leading 0s of in.
*/
static void
ipreverse(char *in, char *out)
{
char *pos[4];
int len[4];
char *p, *start;
int i = 0;
int leading = 1;
/* Fill-in element positions and lengths: pos[], len[]. */
start = p = in;
for (;;) {
if (*p == '.' || *p == '\0') {
/* Leading 0? */
if (leading && p - start == 1 && *start == '0')
len[i] = 0;
else {
len[i] = p - start;
leading = 0;
}
pos[i] = start;
start = p + 1;
i++;
}
if (i == 4)
break;
if (*p == 0) {
for (; i < 4; i++) {
pos[i] = p;
len[i] = 0;
}
break;
}
p++;
}
/* Copy the entries in reverse order */
p = out;
leading = 1;
for (i = 3; i >= 0; i--) {
memcpy(p, pos[i], len[i]);
if (len[i])
leading = 0;
p += len[i];
/* Need a . separator? */
if (!leading && i > 0 && len[i - 1])
*p++ = '.';
}
*p = '\0';
}
static int
getnetanswer(querybuf *answer, int anslen, int net_i, struct netent *ne,
struct netent_data *ned, res_state statp)
{
HEADER *hp;
u_char *cp;
int n;
u_char *eom;
int type, class, ancount, qdcount, haveanswer;
char aux[MAXHOSTNAMELEN];
char ans[MAXHOSTNAMELEN];
char *in, *bp, *ep, **ap;
/*
* find first satisfactory answer
*
* answer --> +------------+ ( MESSAGE )
* | Header |
* +------------+
* | Question | the question for the name server
* +------------+
* | Answer | RRs answering the question
* +------------+
* | Authority | RRs pointing toward an authority
* | Additional | RRs holding additional information
* +------------+
*/
eom = answer->buf + anslen;
hp = &answer->hdr;
ancount = ntohs(hp->ancount); /* #/records in the answer section */
qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
bp = ned->netbuf;
ep = ned->netbuf + sizeof(ned->netbuf);
cp = answer->buf + HFIXEDSZ;
if (!qdcount) {
if (hp->aa)
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
else
RES_SET_H_ERRNO(statp, TRY_AGAIN);
return (-1);
}
while (qdcount-- > 0)
cp += __dn_skipname(cp, eom) + QFIXEDSZ;
ap = ned->net_aliases;
*ap = NULL;
ne->n_aliases = ned->net_aliases;
haveanswer = 0;
while (--ancount >= 0 && cp < eom) {
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !res_dnok(bp))
break;
cp += n;
ans[0] = '\0';
(void)strncpy(&ans[0], bp, sizeof(ans) - 1);
ans[sizeof(ans) - 1] = '\0';
GETSHORT(type, cp);
GETSHORT(class, cp);
cp += INT32SZ; /* TTL */
GETSHORT(n, cp);
if (class == C_IN && type == T_PTR) {
n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
if ((n < 0) || !res_hnok(bp)) {
cp += n;
return (-1);
}
cp += n;
*ap++ = bp;
n = strlen(bp) + 1;
bp += n;
ne->n_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
haveanswer++;
}
}
if (haveanswer) {
*ap = NULL;
switch (net_i) {
case BYADDR:
ne->n_name = *ne->n_aliases;
ne->n_net = 0L;
break;
case BYNAME:
in = *ne->n_aliases;
n = strlen(ans) + 1;
if (ep - bp < n) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
errno = ENOBUFS;
return (-1);
}
strlcpy(bp, ans, ep - bp);
ne->n_name = bp;
if (strlen(in) + 1 > sizeof(aux)) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
errno = ENOBUFS;
return (-1);
}
ipreverse(in, aux);
ne->n_net = inet_network(aux);
break;
}
ne->n_aliases++;
return (0);
}
RES_SET_H_ERRNO(statp, TRY_AGAIN);
return (-1);
}
int
_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
uint32_t net;
int net_type;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct netent *nptr, ne;
struct netent_data *ned;
unsigned int netbr[4];
int nn, anslen, error;
querybuf *buf;
char qbuf[MAXDNAME];
uint32_t net2;
res_state statp;
net = va_arg(ap, uint32_t);
net_type = va_arg(ap, int);
nptr = va_arg(ap, struct netent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
if ((ned = __netent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
*((struct netent **)rval) = NULL;
if (net_type != AF_INET) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
for (nn = 4, net2 = net; net2; net2 >>= 8)
netbr[--nn] = net2 & 0xff;
switch (nn) {
case 3: /* Class A */
sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]);
break;
case 2: /* Class B */
sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]);
break;
case 1: /* Class C */
sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
netbr[1]);
break;
case 0: /* Class D - E */
sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
netbr[1], netbr[0]);
break;
}
if ((buf = malloc(sizeof(*buf))) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
anslen = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
sizeof(*buf));
if (anslen < 0) {
free(buf);
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf("res_nsearch failed\n");
#endif
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
} else if (anslen > sizeof(*buf)) {
free(buf);
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf("res_nsearch static buffer too small\n");
#endif
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
error = getnetanswer(buf, anslen, BYADDR, &ne, ned, statp);
free(buf);
if (error == 0) {
/* Strip trailing zeros */
while ((net & 0xff) == 0 && net != 0)
net >>= 8;
ne.n_net = net;
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct netent **)rval) = nptr;
return (NS_SUCCESS);
}
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
int
_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
{
const char *net;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct netent *nptr, ne;
struct netent_data *ned;
int anslen, error;
querybuf *buf;
char qbuf[MAXDNAME];
res_state statp;
net = va_arg(ap, const char *);
nptr = va_arg(ap, struct netent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
if ((ned = __netent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
if ((buf = malloc(sizeof(*buf))) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
*((struct netent **)rval) = NULL;
strncpy(qbuf, net, sizeof(qbuf) - 1);
qbuf[sizeof(qbuf) - 1] = '\0';
anslen = res_nsearch(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
sizeof(*buf));
if (anslen < 0) {
free(buf);
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf("res_nsearch failed\n");
#endif
return (NS_UNAVAIL);
} else if (anslen > sizeof(*buf)) {
free(buf);
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf("res_search static buffer too small\n");
#endif
return (NS_UNAVAIL);
}
error = getnetanswer(buf, anslen, BYNAME, &ne, ned, statp);
free(buf);
if (error != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct netent **)rval) = nptr;
return (NS_SUCCESS);
}
void
_setnetdnsent(int stayopen)
{
res_state statp;
statp = __res_state();
if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
return;
if (stayopen)
statp->options |= RES_STAYOPEN | RES_USEVC;
}
void
_endnetdnsent(void)
{
res_state statp;
statp = __res_state();
statp->options &= ~(RES_STAYOPEN | RES_USEVC);
res_nclose(statp);
}
diff --git a/lib/libc/net/getnetbyht.c b/lib/libc/net/getnetbyht.c
index 8fb4ccff9cfb..3503df01f6f8 100644
--- a/lib/libc/net/getnetbyht.c
+++ b/lib/libc/net/getnetbyht.c
@@ -1,288 +1,287 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
* Dep. Matematica Universidade de Coimbra, Portugal, Europe
*
* 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.
*
* from getnetent.c 1.1 (Coimbra) 93/06/02
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getnetent.c 8.1 (Berkeley) 6/4/93";
static char orig_rcsid[] = "From: Id: getnetent.c,v 8.4 1997/06/01 20:34:37 vixie Exp";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <nsswitch.h>
#include "netdb_private.h"
void
_setnethtent(int f, struct netent_data *ned)
{
if (ned->netf == NULL)
ned->netf = fopen(_PATH_NETWORKS, "re");
else
rewind(ned->netf);
ned->stayopen |= f;
}
void
_endnethtent(struct netent_data *ned)
{
if (ned->netf) {
fclose(ned->netf);
ned->netf = NULL;
}
ned->stayopen = 0;
}
static int
getnetent_p(struct netent *ne, struct netent_data *ned)
{
char *p, *bp, *ep;
char *cp, **q;
int len;
char line[BUFSIZ + 1];
if (ned->netf == NULL &&
(ned->netf = fopen(_PATH_NETWORKS, "re")) == NULL)
return (-1);
again:
p = fgets(line, sizeof line, ned->netf);
if (p == NULL)
return (-1);
if (*p == '#')
goto again;
cp = strpbrk(p, "#\n");
if (cp != NULL)
*cp = '\0';
bp = ned->netbuf;
ep = ned->netbuf + sizeof ned->netbuf;
ne->n_name = bp;
cp = strpbrk(p, " \t");
if (cp == NULL)
goto again;
*cp++ = '\0';
len = strlen(p) + 1;
if (ep - bp < len) {
RES_SET_H_ERRNO(__res_state(), NO_RECOVERY);
return (-1);
}
strlcpy(bp, p, ep - bp);
bp += len;
while (*cp == ' ' || *cp == '\t')
cp++;
p = strpbrk(cp, " \t");
if (p != NULL)
*p++ = '\0';
ne->n_net = inet_network(cp);
ne->n_addrtype = AF_INET;
q = ne->n_aliases = ned->net_aliases;
if (p != NULL) {
cp = p;
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q >= &ned->net_aliases[_MAXALIASES - 1])
break;
p = strpbrk(cp, " \t");
if (p != NULL)
*p++ = '\0';
len = strlen(cp) + 1;
if (ep - bp < len)
break;
strlcpy(bp, cp, ep - bp);
*q++ = bp;
bp += len;
cp = p;
}
}
*q = NULL;
return (0);
}
int
getnetent_r(struct netent *nptr, char *buffer, size_t buflen,
struct netent **result, int *h_errnop)
{
struct netent_data *ned;
struct netent ne;
res_state statp;
statp = __res_state();
if ((ned = __netent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (-1);
}
if (getnetent_p(&ne, ned) != 0)
return (-1);
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return ((errno != 0) ? errno : -1);
}
*result = nptr;
return (0);
}
struct netent *
getnetent(void)
{
struct netdata *nd;
struct netent *rval;
int ret_h_errno;
if ((nd = __netdata_init()) == NULL)
return (NULL);
if (getnetent_r(&nd->net, nd->data, sizeof(nd->data), &rval,
&ret_h_errno) != 0)
return (NULL);
return (rval);
}
int
_ht_getnetbyname(void *rval, void *cb_data, va_list ap)
{
const char *name;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct netent *nptr, ne;
struct netent_data *ned;
char **cp;
res_state statp;
int error;
name = va_arg(ap, const char *);
nptr = va_arg(ap, struct netent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
statp = __res_state();
if ((ned = __netent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
_setnethtent(ned->stayopen, ned);
while ((error = getnetent_p(&ne, ned)) == 0) {
if (strcasecmp(ne.n_name, name) == 0)
break;
for (cp = ne.n_aliases; *cp != 0; cp++)
if (strcasecmp(*cp, name) == 0)
goto found;
}
found:
if (!ned->stayopen)
_endnethtent(ned);
if (error != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct netent **)rval) = nptr;
return (NS_SUCCESS);
}
int
_ht_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
uint32_t net;
int type;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct netent *nptr, ne;
struct netent_data *ned;
res_state statp;
int error;
net = va_arg(ap, uint32_t);
type = va_arg(ap, int);
nptr = va_arg(ap, struct netent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
statp = __res_state();
if ((ned = __netent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
_setnethtent(ned->stayopen, ned);
while ((error = getnetent_p(&ne, ned)) == 0)
if (ne.n_addrtype == type && ne.n_net == net)
break;
if (!ned->stayopen)
_endnethtent(ned);
if (error != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct netent **)rval) = nptr;
return (NS_SUCCESS);
}
diff --git a/lib/libc/net/getnetbynis.c b/lib/libc/net/getnetbynis.c
index 266cce2bdac2..a56404a14fe7 100644
--- a/lib/libc/net/getnetbynis.c
+++ b/lib/libc/net/getnetbynis.c
@@ -1,260 +1,259 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994, Garrett Wollman
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <stdarg.h>
#include <nsswitch.h>
#include <arpa/nameser.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include "netdb_private.h"
#ifdef YP
static int
_getnetbynis(const char *name, char *map, int af, struct netent *ne,
struct netent_data *ned)
{
char *p, *bp, *ep;
char *cp, **q;
char *result;
int resultlen, len;
char *ypbuf;
switch(af) {
case AF_INET:
break;
default:
case AF_INET6:
errno = EAFNOSUPPORT;
return (-1);
}
if (ned->yp_domain == (char *)NULL)
if (yp_get_default_domain (&ned->yp_domain))
return (-1);
if (yp_match(ned->yp_domain, map, name, strlen(name), &result,
&resultlen))
return (-1);
ypbuf = alloca(resultlen + 2);
bcopy(result, ypbuf, resultlen);
ypbuf[resultlen] = '\0';
free(result);
result = ypbuf;
if ((cp = strchr(result, '\n')))
*cp = '\0';
cp = strpbrk(result, " \t");
*cp++ = '\0';
bp = ned->netbuf;
ep = ned->netbuf + sizeof ned->netbuf;
len = strlen(result) + 1;
if (ep - bp < len) {
RES_SET_H_ERRNO(__res_state(), NO_RECOVERY);
return (-1);
}
strlcpy(bp, result, ep - bp);
ne->n_name = bp;
bp += len;
while (*cp == ' ' || *cp == '\t')
cp++;
ne->n_net = inet_network(cp);
ne->n_addrtype = AF_INET;
q = ne->n_aliases = ned->net_aliases;
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q > &ned->net_aliases[_MAXALIASES - 1])
break;
p = strpbrk(cp, " \t");
if (p != NULL)
*p++ = '\0';
len = strlen(cp) + 1;
if (ep - bp < len)
break;
strlcpy(bp, cp, ep - bp);
*q++ = bp;
bp += len;
cp = p;
}
*q = NULL;
return (0);
}
#endif /* YP */
int
_nis_getnetbyname(void *rval, void *cb_data, va_list ap)
{
#ifdef YP
const char *name;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct netent *nptr, ne;
struct netent_data *ned;
res_state statp;
name = va_arg(ap, const char *);
nptr = va_arg(ap, struct netent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
statp = __res_state();
if ((ned = __netent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
if (_getnetbynis(name, "networks.byname", AF_INET, &ne, ned) != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct netent **)rval) = nptr;
return (NS_SUCCESS);
#else
return (NS_UNAVAIL);
#endif
}
int
_nis_getnetbyaddr(void *rval, void *cb_data, va_list ap)
{
#ifdef YP
uint32_t addr;
int af;
char *buffer;
size_t buflen;
int *errnop, *h_errnop;
struct netent *nptr, ne;
struct netent_data *ned;
char *str, *cp;
uint32_t net2;
int nn;
unsigned int netbr[4];
char buf[MAXDNAME];
res_state statp;
addr = va_arg(ap, uint32_t);
af = va_arg(ap, int);
nptr = va_arg(ap, struct netent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
h_errnop = va_arg(ap, int *);
statp = __res_state();
if ((ned = __netent_data_init()) == NULL) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_UNAVAIL);
}
if (af != AF_INET) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
errno = EAFNOSUPPORT;
return (NS_UNAVAIL);
}
for (nn = 4, net2 = addr; net2; net2 >>= 8) {
netbr[--nn] = net2 & 0xff;
}
switch (nn) {
case 3: /* Class A */
sprintf(buf, "%u", netbr[3]);
break;
case 2: /* Class B */
sprintf(buf, "%u.%u", netbr[2], netbr[3]);
break;
case 1: /* Class C */
sprintf(buf, "%u.%u.%u", netbr[1], netbr[2], netbr[3]);
break;
case 0: /* Class D - E */
sprintf(buf, "%u.%u.%u.%u", netbr[0], netbr[1],
netbr[2], netbr[3]);
break;
}
str = (char *)&buf;
cp = str + (strlen(str) - 2);
while(!strcmp(cp, ".0")) {
*cp = '\0';
cp = str + (strlen(str) - 2);
}
if (_getnetbynis(str, "networks.byaddr", af, &ne, ned) != 0) {
*h_errnop = statp->res_h_errno;
return (NS_NOTFOUND);
}
if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
return (NS_RETURN);
}
*((struct netent **)rval) = nptr;
return (NS_SUCCESS);
#else
return (NS_UNAVAIL);
#endif /* YP */
}
diff --git a/lib/libc/net/getnetnamadr.c b/lib/libc/net/getnetnamadr.c
index d3c44050a1ac..660de3302606 100644
--- a/lib/libc/net/getnetnamadr.c
+++ b/lib/libc/net/getnetnamadr.c
@@ -1,451 +1,450 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1994, Garrett Wollman
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <nsswitch.h>
#include "un-namespace.h"
#include "netdb_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
/* Network lookup order if nsswitch.conf is broken or nonexistent */
static const ns_src default_src[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NSSRC_DNS, NS_SUCCESS },
{ 0 }
};
NETDB_THREAD_ALLOC(netent_data)
NETDB_THREAD_ALLOC(netdata)
#ifdef NS_CACHING
static int
net_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
{
char *name;
uint32_t net;
int type;
size_t desired_size, size;
enum nss_lookup_type lookup_type;
int res = NS_UNAVAIL;
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
size = strlen(name);
desired_size = sizeof(enum nss_lookup_type) + size + 1;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
res = NS_SUCCESS;
break;
case nss_lt_id:
net = va_arg(ap, uint32_t);
type = va_arg(ap, int);
desired_size = sizeof(enum nss_lookup_type) +
sizeof(uint32_t) + sizeof(int);
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), &net,
sizeof(uint32_t));
memcpy(buffer + sizeof(enum nss_lookup_type) + sizeof(uint32_t),
&type, sizeof(int));
res = NS_SUCCESS;
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
fin:
*buffer_size = desired_size;
return (res);
}
static int
net_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
uint32_t net __unused;
int type __unused;
struct netent *ne;
char *orig_buf __unused;
size_t orig_buf_size __unused;
struct netent new_ne;
size_t desired_size, size, aliases_size;
char *p;
char **alias;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
net = va_arg(ap, uint32_t);
type = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
ne = va_arg(ap, struct netent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
desired_size = _ALIGNBYTES + sizeof(struct netent) + sizeof(char *);
if (ne->n_name != NULL)
desired_size += strlen(ne->n_name) + 1;
if (ne->n_aliases != NULL) {
aliases_size = 0;
for (alias = ne->n_aliases; *alias; ++alias) {
desired_size += strlen(*alias) + 1;
++aliases_size;
}
desired_size += _ALIGNBYTES +
(aliases_size + 1) * sizeof(char *);
}
if (*buffer_size < desired_size) {
/* this assignment is here for future use */
*buffer_size = desired_size;
return (NS_RETURN);
}
memcpy(&new_ne, ne, sizeof(struct netent));
*buffer_size = desired_size;
memset(buffer, 0, desired_size);
p = buffer + sizeof(struct netent) + sizeof(char *);
memcpy(buffer + sizeof(struct netent), &p, sizeof(char *));
p = (char *)_ALIGN(p);
if (new_ne.n_name != NULL) {
size = strlen(new_ne.n_name);
memcpy(p, new_ne.n_name, size);
new_ne.n_name = p;
p += size + 1;
}
if (new_ne.n_aliases != NULL) {
p = (char *)_ALIGN(p);
memcpy(p, new_ne.n_aliases, sizeof(char *) * aliases_size);
new_ne.n_aliases = (char **)p;
p += sizeof(char *) * (aliases_size + 1);
for (alias = new_ne.n_aliases; *alias; ++alias) {
size = strlen(*alias);
memcpy(p, *alias, size);
*alias = p;
p += size + 1;
}
}
memcpy(buffer, &new_ne, sizeof(struct netent));
return (NS_SUCCESS);
}
static int
net_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
uint32_t net __unused;
int type __unused;
struct netent *ne;
char *orig_buf;
size_t orig_buf_size;
int *ret_errno;
char *p;
char **alias;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
net = va_arg(ap, uint32_t);
type = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
ne = va_arg(ap, struct netent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
ret_errno = va_arg(ap, int *);
if (orig_buf_size <
buffer_size - sizeof(struct netent) - sizeof(char *)) {
*ret_errno = ERANGE;
return (NS_RETURN);
}
memcpy(ne, buffer, sizeof(struct netent));
memcpy(&p, buffer + sizeof(struct netent), sizeof(char *));
orig_buf = (char *)_ALIGN(orig_buf);
memcpy(orig_buf, buffer + sizeof(struct netent) + sizeof(char *) +
_ALIGN(p) - (size_t)p,
buffer_size - sizeof(struct netent) - sizeof(char *) -
_ALIGN(p) + (size_t)p);
p = (char *)_ALIGN(p);
NS_APPLY_OFFSET(ne->n_name, orig_buf, p, char *);
if (ne->n_aliases != NULL) {
NS_APPLY_OFFSET(ne->n_aliases, orig_buf, p, char **);
for (alias = ne->n_aliases; *alias; ++alias)
NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
}
if (retval != NULL)
*((struct netent **)retval) = ne;
return (NS_SUCCESS);
}
#endif /* NS_CACHING */
static void
netent_data_free(void *ptr)
{
struct netent_data *ned = ptr;
if (ned == NULL)
return;
ned->stayopen = 0;
_endnethtent(ned);
free(ned);
}
static void
netdata_free(void *ptr)
{
free(ptr);
}
int
__copy_netent(struct netent *ne, struct netent *nptr, char *buf, size_t buflen)
{
char *cp;
int i, n;
int numptr, len;
/* Find out the amount of space required to store the answer. */
numptr = 1; /* NULL ptr */
len = (char *)ALIGN(buf) - buf;
for (i = 0; ne->n_aliases[i]; i++, numptr++) {
len += strlen(ne->n_aliases[i]) + 1;
}
len += strlen(ne->n_name) + 1;
len += numptr * sizeof(char*);
if (len > (int)buflen) {
errno = ERANGE;
return (-1);
}
/* copy net value and type */
nptr->n_addrtype = ne->n_addrtype;
nptr->n_net = ne->n_net;
cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
/* copy official name */
n = strlen(ne->n_name) + 1;
strcpy(cp, ne->n_name);
nptr->n_name = cp;
cp += n;
/* copy aliases */
nptr->n_aliases = (char **)ALIGN(buf);
for (i = 0 ; ne->n_aliases[i]; i++) {
n = strlen(ne->n_aliases[i]) + 1;
strcpy(cp, ne->n_aliases[i]);
nptr->n_aliases[i] = cp;
cp += n;
}
nptr->n_aliases[i] = NULL;
return (0);
}
int
getnetbyname_r(const char *name, struct netent *ne, char *buffer,
size_t buflen, struct netent **result, int *h_errorp)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
networks, (void *)nss_lt_name,
net_id_func, net_marshal_func, net_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
NS_FILES_CB(_ht_getnetbyname, NULL)
{ NSSRC_DNS, _dns_getnetbyname, NULL },
NS_NIS_CB(_nis_getnetbyname, NULL) /* force -DHESIOD */
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ 0 }
};
int rval, ret_errno = 0;
rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS,
"getnetbyname_r", default_src, name, ne, buffer, buflen,
&ret_errno, h_errorp);
if (rval != NS_SUCCESS) {
errno = ret_errno;
return ((ret_errno != 0) ? ret_errno : -1);
}
return (0);
}
int
getnetbyaddr_r(uint32_t addr, int af, struct netent *ne, char *buffer,
size_t buflen, struct netent **result, int *h_errorp)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
networks, (void *)nss_lt_id,
net_id_func, net_marshal_func, net_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
NS_FILES_CB(_ht_getnetbyaddr, NULL)
{ NSSRC_DNS, _dns_getnetbyaddr, NULL },
NS_NIS_CB(_nis_getnetbyaddr, NULL) /* force -DHESIOD */
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ 0 }
};
int rval, ret_errno = 0;
rval = _nsdispatch((void *)result, dtab, NSDB_NETWORKS,
"getnetbyaddr_r", default_src, addr, af, ne, buffer, buflen,
&ret_errno, h_errorp);
if (rval != NS_SUCCESS) {
errno = ret_errno;
return ((ret_errno != 0) ? ret_errno : -1);
}
return (0);
}
struct netent *
getnetbyname(const char *name)
{
struct netdata *nd;
struct netent *rval;
int ret_h_errno;
if ((nd = __netdata_init()) == NULL)
return (NULL);
if (getnetbyname_r(name, &nd->net, nd->data, sizeof(nd->data), &rval,
&ret_h_errno) != 0)
return (NULL);
return (rval);
}
struct netent *
getnetbyaddr(uint32_t addr, int af)
{
struct netdata *nd;
struct netent *rval;
int ret_h_errno;
if ((nd = __netdata_init()) == NULL)
return (NULL);
if (getnetbyaddr_r(addr, af, &nd->net, nd->data, sizeof(nd->data),
&rval, &ret_h_errno) != 0)
return (NULL);
return (rval);
}
void
setnetent(int stayopen)
{
struct netent_data *ned;
if ((ned = __netent_data_init()) == NULL)
return;
_setnethtent(stayopen, ned);
_setnetdnsent(stayopen);
}
void
endnetent(void)
{
struct netent_data *ned;
if ((ned = __netent_data_init()) == NULL)
return;
_endnethtent(ned);
_endnetdnsent();
}
diff --git a/lib/libc/net/getproto.c b/lib/libc/net/getproto.c
index 407acf635c7e..c537ec03adab 100644
--- a/lib/libc/net/getproto.c
+++ b/lib/libc/net/getproto.c
@@ -1,137 +1,136 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getproto.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <netdb.h>
#include <nsswitch.h>
#include "netdb_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
#include "nss_tls.h"
static const ns_src defaultsrc[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NULL, 0 }
};
static int
files_getprotobynumber(void *retval, void *mdata, va_list ap)
{
struct protoent pe;
struct protoent_data *ped;
int error;
int number;
struct protoent *pptr;
char *buffer;
size_t buflen;
int *errnop;
number = va_arg(ap, int);
pptr = va_arg(ap, struct protoent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
if ((ped = __protoent_data_init()) == NULL) {
*errnop = errno;
return (NS_NOTFOUND);
}
__setprotoent_p(ped->stayopen, ped);
while ((error = __getprotoent_p(&pe, ped)) == 0)
if (pe.p_proto == number)
break;
if (!ped->stayopen)
__endprotoent_p(ped);
if (error != 0) {
*errnop = errno;
return (NS_NOTFOUND);
}
if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
*errnop = errno;
return (NS_RETURN);
}
*((struct protoent **)retval) = pptr;
return (NS_SUCCESS);
}
int
getprotobynumber_r(int proto, struct protoent *pptr, char *buffer,
size_t buflen, struct protoent **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
protocols, (void *)nss_lt_id,
__proto_id_func, __proto_marshal_func, __proto_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_getprotobynumber, NULL },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotobynumber_r",
defaultsrc, proto, pptr, buffer, buflen, &ret_errno);
if (rv != NS_SUCCESS) {
errno = ret_errno;
return (ret_errno);
}
return (0);
}
struct protoent *
getprotobynumber(int proto)
{
struct protodata *pd;
struct protoent *rval;
if ((pd = __protodata_init()) == NULL)
return (NULL);
if (getprotobynumber_r(proto, &pd->proto, pd->data, sizeof(pd->data),
&rval) != 0)
return (NULL);
return (rval);
}
diff --git a/lib/libc/net/getprotoent.c b/lib/libc/net/getprotoent.c
index 1fb719219c10..b8ea0b819979 100644
--- a/lib/libc/net/getprotoent.c
+++ b/lib/libc/net/getprotoent.c
@@ -1,553 +1,552 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getprotoent.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <nsswitch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "namespace.h"
#include "reentrant.h"
#include "un-namespace.h"
#include "netdb_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
#include "nss_tls.h"
static const ns_src defaultsrc[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NULL, 0 }
};
NETDB_THREAD_ALLOC(protoent_data)
NETDB_THREAD_ALLOC(protodata)
static void
protoent_data_clear(struct protoent_data *ped)
{
if (ped->fp) {
fclose(ped->fp);
ped->fp = NULL;
}
}
static void
protoent_data_free(void *ptr)
{
struct protoent_data *ped = ptr;
protoent_data_clear(ped);
free(ped);
}
static void
protodata_free(void *ptr)
{
free(ptr);
}
#ifdef NS_CACHING
int
__proto_id_func(char *buffer, size_t *buffer_size, va_list ap,
void *cache_mdata)
{
char *name;
int proto;
size_t desired_size, size;
enum nss_lookup_type lookup_type;
int res = NS_UNAVAIL;
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
size = strlen(name);
desired_size = sizeof(enum nss_lookup_type) + size + 1;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
res = NS_SUCCESS;
break;
case nss_lt_id:
proto = va_arg(ap, int);
desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), &proto,
sizeof(int));
res = NS_SUCCESS;
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
fin:
*buffer_size = desired_size;
return (res);
}
int
__proto_marshal_func(char *buffer, size_t *buffer_size, void *retval,
va_list ap, void *cache_mdata)
{
char *name __unused;
int num __unused;
struct protoent *proto;
char *orig_buf __unused;
size_t orig_buf_size __unused;
struct protoent new_proto;
size_t desired_size, size, aliases_size;
char *p;
char **alias;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
num = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
proto = va_arg(ap, struct protoent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
desired_size = _ALIGNBYTES + sizeof(struct protoent) + sizeof(char *);
if (proto->p_name != NULL)
desired_size += strlen(proto->p_name) + 1;
if (proto->p_aliases != NULL) {
aliases_size = 0;
for (alias = proto->p_aliases; *alias; ++alias) {
desired_size += strlen(*alias) + 1;
++aliases_size;
}
desired_size += _ALIGNBYTES + (aliases_size + 1) *
sizeof(char *);
}
if (*buffer_size < desired_size) {
/* this assignment is here for future use */
*buffer_size = desired_size;
return (NS_RETURN);
}
memcpy(&new_proto, proto, sizeof(struct protoent));
*buffer_size = desired_size;
memset(buffer, 0, desired_size);
p = buffer + sizeof(struct protoent) + sizeof(char *);
memcpy(buffer + sizeof(struct protoent), &p, sizeof(char *));
p = (char *)_ALIGN(p);
if (new_proto.p_name != NULL) {
size = strlen(new_proto.p_name);
memcpy(p, new_proto.p_name, size);
new_proto.p_name = p;
p += size + 1;
}
if (new_proto.p_aliases != NULL) {
p = (char *)_ALIGN(p);
memcpy(p, new_proto.p_aliases, sizeof(char *) * aliases_size);
new_proto.p_aliases = (char **)p;
p += sizeof(char *) * (aliases_size + 1);
for (alias = new_proto.p_aliases; *alias; ++alias) {
size = strlen(*alias);
memcpy(p, *alias, size);
*alias = p;
p += size + 1;
}
}
memcpy(buffer, &new_proto, sizeof(struct protoent));
return (NS_SUCCESS);
}
int
__proto_unmarshal_func(char *buffer, size_t buffer_size, void *retval,
va_list ap, void *cache_mdata)
{
char *name __unused;
int num __unused;
struct protoent *proto;
char *orig_buf;
size_t orig_buf_size;
int *ret_errno;
char *p;
char **alias;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
num = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
proto = va_arg(ap, struct protoent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
ret_errno = va_arg(ap, int *);
if (orig_buf_size <
buffer_size - sizeof(struct protoent) - sizeof(char *)) {
*ret_errno = ERANGE;
return (NS_RETURN);
}
memcpy(proto, buffer, sizeof(struct protoent));
memcpy(&p, buffer + sizeof(struct protoent), sizeof(char *));
orig_buf = (char *)_ALIGN(orig_buf);
memcpy(orig_buf, buffer + sizeof(struct protoent) + sizeof(char *) +
_ALIGN(p) - (size_t)p,
buffer_size - sizeof(struct protoent) - sizeof(char *) -
_ALIGN(p) + (size_t)p);
p = (char *)_ALIGN(p);
NS_APPLY_OFFSET(proto->p_name, orig_buf, p, char *);
if (proto->p_aliases != NULL) {
NS_APPLY_OFFSET(proto->p_aliases, orig_buf, p, char **);
for (alias = proto->p_aliases; *alias; ++alias)
NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
}
if (retval != NULL)
*((struct protoent **)retval) = proto;
return (NS_SUCCESS);
}
NSS_MP_CACHE_HANDLING(protocols);
#endif /* NS_CACHING */
int
__copy_protoent(struct protoent *pe, struct protoent *pptr, char *buf,
size_t buflen)
{
char *cp;
int i, n;
int numptr, len;
/* Find out the amount of space required to store the answer. */
numptr = 1; /* NULL ptr */
len = (char *)ALIGN(buf) - buf;
for (i = 0; pe->p_aliases[i]; i++, numptr++) {
len += strlen(pe->p_aliases[i]) + 1;
}
len += strlen(pe->p_name) + 1;
len += numptr * sizeof(char*);
if (len > (int)buflen) {
errno = ERANGE;
return (-1);
}
/* copy protocol value*/
pptr->p_proto = pe->p_proto;
cp = (char *)ALIGN(buf) + numptr * sizeof(char *);
/* copy official name */
n = strlen(pe->p_name) + 1;
strcpy(cp, pe->p_name);
pptr->p_name = cp;
cp += n;
/* copy aliases */
pptr->p_aliases = (char **)ALIGN(buf);
for (i = 0 ; pe->p_aliases[i]; i++) {
n = strlen(pe->p_aliases[i]) + 1;
strcpy(cp, pe->p_aliases[i]);
pptr->p_aliases[i] = cp;
cp += n;
}
pptr->p_aliases[i] = NULL;
return (0);
}
void
__setprotoent_p(int f, struct protoent_data *ped)
{
if (ped->fp == NULL)
ped->fp = fopen(_PATH_PROTOCOLS, "re");
else
rewind(ped->fp);
ped->stayopen |= f;
}
void
__endprotoent_p(struct protoent_data *ped)
{
if (ped->fp) {
fclose(ped->fp);
ped->fp = NULL;
}
ped->stayopen = 0;
}
int
__getprotoent_p(struct protoent *pe, struct protoent_data *ped)
{
char *p;
char *cp, **q, *endp;
long l;
if (ped->fp == NULL && (ped->fp = fopen(_PATH_PROTOCOLS, "re")) == NULL)
return (-1);
again:
if ((p = fgets(ped->line, sizeof ped->line, ped->fp)) == NULL)
return (-1);
if (*p == '#')
goto again;
cp = strpbrk(p, "#\n");
if (cp != NULL)
*cp = '\0';
pe->p_name = p;
cp = strpbrk(p, " \t");
if (cp == NULL)
goto again;
*cp++ = '\0';
while (*cp == ' ' || *cp == '\t')
cp++;
p = strpbrk(cp, " \t");
if (p != NULL)
*p++ = '\0';
l = strtol(cp, &endp, 10);
if (endp == cp || *endp != '\0' || l < 0 || l > USHRT_MAX)
goto again;
pe->p_proto = l;
q = pe->p_aliases = ped->aliases;
if (p != NULL) {
cp = p;
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q < &ped->aliases[_MAXALIASES - 1])
*q++ = cp;
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
}
}
*q = NULL;
return (0);
}
static int
files_getprotoent_r(void *retval, void *mdata, va_list ap)
{
struct protoent pe;
struct protoent_data *ped;
struct protoent *pptr;
char *buffer;
size_t buflen;
int *errnop;
pptr = va_arg(ap, struct protoent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
if ((ped = __protoent_data_init()) == NULL) {
*errnop = errno;
return (NS_NOTFOUND);
}
if (__getprotoent_p(&pe, ped) != 0) {
*errnop = errno;
return (NS_NOTFOUND);
}
if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
*errnop = errno;
return (NS_RETURN);
}
*((struct protoent **)retval) = pptr;
return (NS_SUCCESS);
}
static int
files_setprotoent(void *retval, void *mdata, va_list ap)
{
struct protoent_data *ped;
int f;
f = va_arg(ap, int);
if ((ped = __protoent_data_init()) == NULL)
return (NS_UNAVAIL);
__setprotoent_p(f, ped);
return (NS_UNAVAIL);
}
static int
files_endprotoent(void *retval, void *mdata, va_list ap)
{
struct protoent_data *ped;
if ((ped = __protoent_data_init()) == NULL)
return (NS_UNAVAIL);
__endprotoent_p(ped);
return (NS_UNAVAIL);
}
int
getprotoent_r(struct protoent *pptr, char *buffer, size_t buflen,
struct protoent **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
protocols, (void *)nss_lt_all,
__proto_marshal_func, __proto_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_getprotoent_r, (void *)nss_lt_all },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotoent_r",
defaultsrc, pptr, buffer, buflen, &ret_errno);
if (rv != NS_SUCCESS) {
errno = ret_errno;
return (ret_errno);
}
return (0);
}
void
setprotoent(int stayopen)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
protocols, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setprotoent, NULL },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "setprotoent", defaultsrc,
stayopen);
}
void
endprotoent(void)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
protocols, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_endprotoent, NULL },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)nsdispatch(NULL, dtab, NSDB_PROTOCOLS, "endprotoent", defaultsrc);
}
struct protoent *
getprotoent(void)
{
struct protodata *pd;
struct protoent *rval;
if ((pd = __protodata_init()) == NULL)
return (NULL);
if (getprotoent_r(&pd->proto, pd->data, sizeof(pd->data), &rval) != 0)
return (NULL);
return (rval);
}
diff --git a/lib/libc/net/getprotoname.c b/lib/libc/net/getprotoname.c
index 0ae48e96d3f3..7ce68e4d4a2f 100644
--- a/lib/libc/net/getprotoname.c
+++ b/lib/libc/net/getprotoname.c
@@ -1,151 +1,150 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getprotoname.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <netdb.h>
#include <nsswitch.h>
#include <string.h>
#include "netdb_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
#include "nss_tls.h"
static const ns_src defaultsrc[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ NULL, 0 }
};
#ifdef NS_CACHING
extern int __proto_id_func(char *, size_t *, va_list, void *);
extern int __proto_marshal_func(char *, size_t *, void *, va_list, void *);
extern int __proto_unmarshal_func(char *, size_t, void *, va_list, void *);
#endif
static int
files_getprotobyname(void *retval, void *mdata, va_list ap)
{
struct protoent pe;
struct protoent_data *ped;
char **cp;
int error;
char *name;
struct protoent *pptr;
char *buffer;
size_t buflen;
int *errnop;
name = va_arg(ap, char *);
pptr = va_arg(ap, struct protoent *);
buffer = va_arg(ap, char *);
buflen = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
if ((ped = __protoent_data_init()) == NULL) {
*errnop = errno;
return (NS_NOTFOUND);
}
__setprotoent_p(ped->stayopen, ped);
while ((error = __getprotoent_p(&pe, ped)) == 0) {
if (strcmp(pe.p_name, name) == 0)
break;
for (cp = pe.p_aliases; *cp != 0; cp++)
if (strcmp(*cp, name) == 0)
goto found;
}
found:
if (!ped->stayopen)
__endprotoent_p(ped);
if (error != 0) {
*errnop = errno;
return (NS_NOTFOUND);
}
if (__copy_protoent(&pe, pptr, buffer, buflen) != 0) {
*errnop = errno;
return (NS_RETURN);
}
*((struct protoent **)retval) = pptr;
return (NS_SUCCESS);
}
int
getprotobyname_r(const char *name, struct protoent *pptr, char *buffer,
size_t buflen, struct protoent **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
protocols, (void *)nss_lt_name,
__proto_id_func, __proto_marshal_func, __proto_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_getprotobyname, NULL },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_PROTOCOLS, "getprotobyname_r",
defaultsrc, name, pptr, buffer, buflen, &ret_errno);
if (rv != NS_SUCCESS) {
errno = ret_errno;
return (ret_errno);
}
return (0);
}
struct protoent *
getprotobyname(const char *name)
{
struct protodata *pd;
struct protoent *rval;
if ((pd = __protodata_init()) == NULL)
return (NULL);
if (getprotobyname_r(name, &pd->proto, pd->data, sizeof(pd->data),
&rval) != 0)
return (NULL);
return (rval);
}
diff --git a/lib/libc/net/getservent.c b/lib/libc/net/getservent.c
index d4241d49d05a..8b341b5a1833 100644
--- a/lib/libc/net/getservent.c
+++ b/lib/libc/net/getservent.c
@@ -1,1379 +1,1378 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getservent.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <db.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <netdb.h>
#include <nsswitch.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef YP
#include <rpc/rpc.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include "namespace.h"
#include "reentrant.h"
#include "un-namespace.h"
#include "netdb_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
#include "nss_tls.h"
enum constants
{
SETSERVENT = 1,
ENDSERVENT = 2,
SERVENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
SERVENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
};
struct servent_mdata
{
enum nss_lookup_type how;
int compat_mode;
};
static const ns_src defaultsrc[] = {
{ NSSRC_COMPAT, NS_SUCCESS },
{ NULL, 0 }
};
static int servent_unpack(char *, struct servent *, char **, size_t, int *);
/* files backend declarations */
struct files_state
{
FILE *fp;
int stayopen;
int compat_mode_active;
};
static void files_endstate(void *);
NSS_TLS_HANDLING(files);
static int files_servent(void *, void *, va_list);
static int files_setservent(void *, void *, va_list);
/* db backend declarations */
struct db_state
{
DB *db;
int stayopen;
int keynum;
};
static void db_endstate(void *);
NSS_TLS_HANDLING(db);
static int db_servent(void *, void *, va_list);
static int db_setservent(void *, void *, va_list);
#ifdef YP
/* nis backend declarations */
static int nis_servent(void *, void *, va_list);
static int nis_setservent(void *, void *, va_list);
struct nis_state
{
int yp_stepping;
char yp_domain[MAXHOSTNAMELEN];
char *yp_key;
int yp_keylen;
};
static void nis_endstate(void *);
NSS_TLS_HANDLING(nis);
static int nis_servent(void *, void *, va_list);
static int nis_setservent(void *, void *, va_list);
#endif
/* compat backend declarations */
static int compat_setservent(void *, void *, va_list);
/* get** wrappers for get**_r functions declarations */
struct servent_state {
struct servent serv;
char *buffer;
size_t bufsize;
};
static void servent_endstate(void *);
NSS_TLS_HANDLING(servent);
struct key {
const char *proto;
union {
const char *name;
int port;
};
};
static int wrap_getservbyname_r(struct key, struct servent *, char *, size_t,
struct servent **);
static int wrap_getservbyport_r(struct key, struct servent *, char *, size_t,
struct servent **);
static int wrap_getservent_r(struct key, struct servent *, char *, size_t,
struct servent **);
static struct servent *getserv(int (*fn)(struct key, struct servent *, char *,
size_t, struct servent **), struct key);
#ifdef NS_CACHING
static int serv_id_func(char *, size_t *, va_list, void *);
static int serv_marshal_func(char *, size_t *, void *, va_list, void *);
static int serv_unmarshal_func(char *, size_t, void *, va_list, void *);
#endif
static int
servent_unpack(char *p, struct servent *serv, char **aliases,
size_t aliases_size, int *errnop)
{
char *cp, **q, *endp;
long l;
if (*p == '#')
return -1;
memset(serv, 0, sizeof(struct servent));
cp = strpbrk(p, "#\n");
if (cp != NULL)
*cp = '\0';
serv->s_name = p;
p = strpbrk(p, " \t");
if (p == NULL)
return -1;
*p++ = '\0';
while (*p == ' ' || *p == '\t')
p++;
cp = strpbrk(p, ",/");
if (cp == NULL)
return -1;
*cp++ = '\0';
l = strtol(p, &endp, 10);
if (endp == p || *endp != '\0' || l < 0 || l > USHRT_MAX)
return -1;
serv->s_port = htons((in_port_t)l);
serv->s_proto = cp;
q = serv->s_aliases = aliases;
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q < &aliases[aliases_size - 1]) {
*q++ = cp;
} else {
*q = NULL;
*errnop = ERANGE;
return -1;
}
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
}
*q = NULL;
return 0;
}
static int
parse_result(struct servent *serv, char *buffer, size_t bufsize,
char *resultbuf, size_t resultbuflen, int *errnop)
{
char **aliases;
int aliases_size;
if (bufsize <= resultbuflen + _ALIGNBYTES + sizeof(char *)) {
*errnop = ERANGE;
return (NS_RETURN);
}
aliases = (char **)_ALIGN(&buffer[resultbuflen + 1]);
aliases_size = (buffer + bufsize - (char *)aliases) / sizeof(char *);
if (aliases_size < 1) {
*errnop = ERANGE;
return (NS_RETURN);
}
memcpy(buffer, resultbuf, resultbuflen);
buffer[resultbuflen] = '\0';
if (servent_unpack(buffer, serv, aliases, aliases_size, errnop) != 0)
return ((*errnop == 0) ? NS_NOTFOUND : NS_RETURN);
return (NS_SUCCESS);
}
/* files backend implementation */
static void
files_endstate(void *p)
{
FILE * f;
if (p == NULL)
return;
f = ((struct files_state *)p)->fp;
if (f != NULL)
fclose(f);
free(p);
}
/*
* compat structures. compat and files sources functionalities are almost
* equal, so they all are managed by files_servent function
*/
static int
files_servent(void *retval, void *mdata, va_list ap)
{
static const ns_src compat_src[] = {
#ifdef YP
{ NSSRC_NIS, NS_SUCCESS },
#endif
{ NULL, 0 }
};
ns_dtab compat_dtab[] = {
{ NSSRC_DB, db_servent,
(void *)((struct servent_mdata *)mdata)->how },
#ifdef YP
{ NSSRC_NIS, nis_servent,
(void *)((struct servent_mdata *)mdata)->how },
#endif
{ NULL, NULL, NULL }
};
struct files_state *st;
int rv;
int stayopen;
struct servent_mdata *serv_mdata;
char *name;
char *proto;
int port;
struct servent *serv;
char *buffer;
size_t bufsize;
int *errnop;
size_t linesize;
char *line;
char **cp;
name = NULL;
proto = NULL;
serv_mdata = (struct servent_mdata *)mdata;
switch (serv_mdata->how) {
case nss_lt_name:
name = va_arg(ap, char *);
proto = va_arg(ap, char *);
break;
case nss_lt_id:
port = va_arg(ap, int);
proto = va_arg(ap, char *);
break;
case nss_lt_all:
break;
default:
return NS_NOTFOUND;
}
serv = va_arg(ap, struct servent *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap,int *);
*errnop = files_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->fp == NULL)
st->compat_mode_active = 0;
if (st->fp == NULL && (st->fp = fopen(_PATH_SERVICES, "re")) == NULL) {
*errnop = errno;
return (NS_UNAVAIL);
}
if (serv_mdata->how == nss_lt_all)
stayopen = 1;
else {
rewind(st->fp);
stayopen = st->stayopen;
}
rv = NS_NOTFOUND;
do {
if (!st->compat_mode_active) {
if ((line = fgetln(st->fp, &linesize)) == NULL) {
*errnop = errno;
rv = NS_RETURN;
break;
}
if (*line=='+' && serv_mdata->compat_mode != 0)
st->compat_mode_active = 1;
}
if (st->compat_mode_active != 0) {
switch (serv_mdata->how) {
case nss_lt_name:
rv = nsdispatch(retval, compat_dtab,
NSDB_SERVICES_COMPAT, "getservbyname_r",
compat_src, name, proto, serv, buffer,
bufsize, errnop);
break;
case nss_lt_id:
rv = nsdispatch(retval, compat_dtab,
NSDB_SERVICES_COMPAT, "getservbyport_r",
compat_src, port, proto, serv, buffer,
bufsize, errnop);
break;
case nss_lt_all:
rv = nsdispatch(retval, compat_dtab,
NSDB_SERVICES_COMPAT, "getservent_r",
compat_src, serv, buffer, bufsize, errnop);
break;
}
if (!(rv & NS_TERMINATE) ||
serv_mdata->how != nss_lt_all)
st->compat_mode_active = 0;
continue;
}
rv = parse_result(serv, buffer, bufsize, line, linesize,
errnop);
if (rv == NS_NOTFOUND)
continue;
if (rv == NS_RETURN)
break;
rv = NS_NOTFOUND;
switch (serv_mdata->how) {
case nss_lt_name:
if (strcmp(name, serv->s_name) == 0)
goto gotname;
for (cp = serv->s_aliases; *cp; cp++)
if (strcmp(name, *cp) == 0)
goto gotname;
continue;
gotname:
if (proto == NULL || strcmp(serv->s_proto, proto) == 0)
rv = NS_SUCCESS;
break;
case nss_lt_id:
if (port != serv->s_port)
continue;
if (proto == NULL || strcmp(serv->s_proto, proto) == 0)
rv = NS_SUCCESS;
break;
case nss_lt_all:
rv = NS_SUCCESS;
break;
}
} while (!(rv & NS_TERMINATE));
if (!stayopen && st->fp != NULL) {
fclose(st->fp);
st->fp = NULL;
}
if ((rv == NS_SUCCESS) && (retval != NULL))
*(struct servent **)retval=serv;
return (rv);
}
static int
files_setservent(void *retval, void *mdata, va_list ap)
{
struct files_state *st;
int rv;
int f;
rv = files_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata) {
case SETSERVENT:
f = va_arg(ap,int);
if (st->fp == NULL)
st->fp = fopen(_PATH_SERVICES, "re");
else
rewind(st->fp);
st->stayopen |= f;
break;
case ENDSERVENT:
if (st->fp != NULL) {
fclose(st->fp);
st->fp = NULL;
}
st->stayopen = 0;
break;
default:
break;
}
st->compat_mode_active = 0;
return (NS_UNAVAIL);
}
/* db backend implementation */
static void
db_endstate(void *p)
{
DB *db;
if (p == NULL)
return;
db = ((struct db_state *)p)->db;
if (db != NULL)
db->close(db);
free(p);
}
static int
db_servent(void *retval, void *mdata, va_list ap)
{
char buf[BUFSIZ];
DBT key, data, *result;
DB *db;
struct db_state *st;
int rv;
int stayopen;
enum nss_lookup_type how;
char *name;
char *proto;
int port;
struct servent *serv;
char *buffer;
size_t bufsize;
int *errnop;
name = NULL;
proto = NULL;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, char *);
proto = va_arg(ap, char *);
break;
case nss_lt_id:
port = va_arg(ap, int);
proto = va_arg(ap, char *);
break;
case nss_lt_all:
break;
default:
return NS_NOTFOUND;
}
serv = va_arg(ap, struct servent *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap,int *);
*errnop = db_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (how == nss_lt_all && st->keynum < 0)
return (NS_NOTFOUND);
if (st->db == NULL) {
st->db = dbopen(_PATH_SERVICES_DB, O_RDONLY, 0, DB_HASH, NULL);
if (st->db == NULL) {
*errnop = errno;
return (NS_UNAVAIL);
}
}
stayopen = (how == nss_lt_all) ? 1 : st->stayopen;
db = st->db;
do {
switch (how) {
case nss_lt_name:
key.data = buf;
if (proto == NULL)
key.size = snprintf(buf, sizeof(buf),
"\376%s", name);
else
key.size = snprintf(buf, sizeof(buf),
"\376%s/%s", name, proto);
key.size++;
if (db->get(db, &key, &data, 0) != 0 ||
db->get(db, &data, &key, 0) != 0) {
rv = NS_NOTFOUND;
goto db_fin;
}
result = &key;
break;
case nss_lt_id:
key.data = buf;
port = htons(port);
if (proto == NULL)
key.size = snprintf(buf, sizeof(buf),
"\377%d", port);
else
key.size = snprintf(buf, sizeof(buf),
"\377%d/%s", port, proto);
key.size++;
if (db->get(db, &key, &data, 0) != 0 ||
db->get(db, &data, &key, 0) != 0) {
rv = NS_NOTFOUND;
goto db_fin;
}
result = &key;
break;
case nss_lt_all:
key.data = buf;
key.size = snprintf(buf, sizeof(buf), "%d",
st->keynum++);
key.size++;
if (db->get(db, &key, &data, 0) != 0) {
st->keynum = -1;
rv = NS_NOTFOUND;
goto db_fin;
}
result = &data;
break;
}
rv = parse_result(serv, buffer, bufsize, result->data,
result->size - 1, errnop);
} while (!(rv & NS_TERMINATE) && how == nss_lt_all);
db_fin:
if (!stayopen && st->db != NULL) {
db->close(db);
st->db = NULL;
}
if (rv == NS_SUCCESS && retval != NULL)
*(struct servent **)retval = serv;
return (rv);
}
static int
db_setservent(void *retval, void *mdata, va_list ap)
{
DB *db;
struct db_state *st;
int rv;
int f;
rv = db_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata) {
case SETSERVENT:
f = va_arg(ap, int);
st->stayopen |= f;
st->keynum = 0;
break;
case ENDSERVENT:
db = st->db;
if (db != NULL) {
db->close(db);
st->db = NULL;
}
st->stayopen = 0;
break;
default:
break;
}
return (NS_UNAVAIL);
}
/* nis backend implementation */
#ifdef YP
static void
nis_endstate(void *p)
{
if (p == NULL)
return;
free(((struct nis_state *)p)->yp_key);
free(p);
}
static int
nis_servent(void *retval, void *mdata, va_list ap)
{
char *resultbuf, *lastkey;
int resultbuflen;
char *buf;
struct nis_state *st;
int rv;
enum nss_lookup_type how;
char *name;
char *proto;
int port;
struct servent *serv;
char *buffer;
size_t bufsize;
int *errnop;
name = NULL;
proto = NULL;
buf = NULL;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how) {
case nss_lt_name:
name = va_arg(ap, char *);
proto = va_arg(ap, char *);
break;
case nss_lt_id:
port = va_arg(ap, int);
proto = va_arg(ap, char *);
break;
case nss_lt_all:
break;
default:
return NS_NOTFOUND;
}
serv = va_arg(ap, struct servent *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = nis_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->yp_domain[0] == '\0') {
if (getdomainname(st->yp_domain, sizeof st->yp_domain)) {
*errnop = errno;
return (NS_UNAVAIL);
}
}
do {
switch (how) {
case nss_lt_name:
free(buf);
asprintf(&buf, "%s/%s", name, proto);
if (buf == NULL)
return (NS_TRYAGAIN);
if (yp_match(st->yp_domain, "services.byname", buf,
strlen(buf), &resultbuf, &resultbuflen)) {
rv = NS_NOTFOUND;
goto fin;
}
break;
case nss_lt_id:
free(buf);
asprintf(&buf, "%d/%s", ntohs(port), proto);
if (buf == NULL)
return (NS_TRYAGAIN);
/*
* We have to be a little flexible
* here. Ideally you're supposed to have both
* a services.byname and a services.byport
* map, but some systems have only
* services.byname. FreeBSD cheats a little by
* putting the services.byport information in
* the same map as services.byname so that
* either case will work. We allow for both
* possibilities here: if there is no
* services.byport map, we try services.byname
* instead.
*/
rv = yp_match(st->yp_domain, "services.byport", buf,
strlen(buf), &resultbuf, &resultbuflen);
if (rv) {
if (rv == YPERR_MAP) {
if (yp_match(st->yp_domain,
"services.byname", buf,
strlen(buf), &resultbuf,
&resultbuflen)) {
rv = NS_NOTFOUND;
goto fin;
}
} else {
rv = NS_NOTFOUND;
goto fin;
}
}
break;
case nss_lt_all:
if (!st->yp_stepping) {
free(st->yp_key);
rv = yp_first(st->yp_domain, "services.byname",
&st->yp_key, &st->yp_keylen, &resultbuf,
&resultbuflen);
if (rv) {
rv = NS_NOTFOUND;
goto fin;
}
st->yp_stepping = 1;
} else {
lastkey = st->yp_key;
rv = yp_next(st->yp_domain, "services.byname",
st->yp_key, st->yp_keylen, &st->yp_key,
&st->yp_keylen, &resultbuf, &resultbuflen);
free(lastkey);
if (rv) {
st->yp_stepping = 0;
rv = NS_NOTFOUND;
goto fin;
}
}
break;
}
rv = parse_result(serv, buffer, bufsize, resultbuf,
resultbuflen, errnop);
free(resultbuf);
} while (!(rv & NS_TERMINATE) && how == nss_lt_all);
fin:
free(buf);
if (rv == NS_SUCCESS && retval != NULL)
*(struct servent **)retval = serv;
return (rv);
}
static int
nis_setservent(void *result, void *mdata, va_list ap)
{
struct nis_state *st;
int rv;
rv = nis_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata) {
case SETSERVENT:
case ENDSERVENT:
free(st->yp_key);
st->yp_key = NULL;
st->yp_stepping = 0;
break;
default:
break;
}
return (NS_UNAVAIL);
}
#endif
/* compat backend implementation */
static int
compat_setservent(void *retval, void *mdata, va_list ap)
{
static const ns_src compat_src[] = {
#ifdef YP
{ NSSRC_NIS, NS_SUCCESS },
#endif
{ NULL, 0 }
};
ns_dtab compat_dtab[] = {
{ NSSRC_DB, db_setservent, mdata },
#ifdef YP
{ NSSRC_NIS, nis_setservent, mdata },
#endif
{ NULL, NULL, NULL }
};
int f;
(void)files_setservent(retval, mdata, ap);
switch ((enum constants)(uintptr_t)mdata) {
case SETSERVENT:
f = va_arg(ap,int);
(void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
"setservent", compat_src, f);
break;
case ENDSERVENT:
(void)nsdispatch(retval, compat_dtab, NSDB_SERVICES_COMPAT,
"endservent", compat_src);
break;
default:
break;
}
return (NS_UNAVAIL);
}
#ifdef NS_CACHING
static int
serv_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
{
char *name;
char *proto;
int port;
size_t desired_size, size, size2;
enum nss_lookup_type lookup_type;
int res = NS_UNAVAIL;
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
proto = va_arg(ap, char *);
size = strlen(name);
desired_size = sizeof(enum nss_lookup_type) + size + 1;
if (proto != NULL) {
size2 = strlen(proto);
desired_size += size2 + 1;
} else
size2 = 0;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
if (proto != NULL)
memcpy(buffer + sizeof(enum nss_lookup_type) + size + 1,
proto, size2 + 1);
res = NS_SUCCESS;
break;
case nss_lt_id:
port = va_arg(ap, int);
proto = va_arg(ap, char *);
desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
if (proto != NULL) {
size = strlen(proto);
desired_size += size + 1;
} else
size = 0;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), &port,
sizeof(int));
if (proto != NULL)
memcpy(buffer + sizeof(enum nss_lookup_type) +
sizeof(int), proto, size + 1);
res = NS_SUCCESS;
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
fin:
*buffer_size = desired_size;
return (res);
}
int
serv_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
char *proto __unused;
int port __unused;
struct servent *serv;
char *orig_buf __unused;
size_t orig_buf_size __unused;
struct servent new_serv;
size_t desired_size;
char **alias;
char *p;
size_t size;
size_t aliases_size;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
proto = va_arg(ap, char *);
break;
case nss_lt_id:
port = va_arg(ap, int);
proto = va_arg(ap, char *);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
serv = va_arg(ap, struct servent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
desired_size = _ALIGNBYTES + sizeof(struct servent) + sizeof(char *);
if (serv->s_name != NULL)
desired_size += strlen(serv->s_name) + 1;
if (serv->s_proto != NULL)
desired_size += strlen(serv->s_proto) + 1;
aliases_size = 0;
if (serv->s_aliases != NULL) {
for (alias = serv->s_aliases; *alias; ++alias) {
desired_size += strlen(*alias) + 1;
++aliases_size;
}
desired_size += _ALIGNBYTES +
sizeof(char *) * (aliases_size + 1);
}
if (*buffer_size < desired_size) {
/* this assignment is here for future use */
*buffer_size = desired_size;
return (NS_RETURN);
}
memcpy(&new_serv, serv, sizeof(struct servent));
memset(buffer, 0, desired_size);
*buffer_size = desired_size;
p = buffer + sizeof(struct servent) + sizeof(char *);
memcpy(buffer + sizeof(struct servent), &p, sizeof(char *));
p = (char *)_ALIGN(p);
if (new_serv.s_name != NULL) {
size = strlen(new_serv.s_name);
memcpy(p, new_serv.s_name, size);
new_serv.s_name = p;
p += size + 1;
}
if (new_serv.s_proto != NULL) {
size = strlen(new_serv.s_proto);
memcpy(p, new_serv.s_proto, size);
new_serv.s_proto = p;
p += size + 1;
}
if (new_serv.s_aliases != NULL) {
p = (char *)_ALIGN(p);
memcpy(p, new_serv.s_aliases, sizeof(char *) * aliases_size);
new_serv.s_aliases = (char **)p;
p += sizeof(char *) * (aliases_size + 1);
for (alias = new_serv.s_aliases; *alias; ++alias) {
size = strlen(*alias);
memcpy(p, *alias, size);
*alias = p;
p += size + 1;
}
}
memcpy(buffer, &new_serv, sizeof(struct servent));
return (NS_SUCCESS);
}
int
serv_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
char *proto __unused;
int port __unused;
struct servent *serv;
char *orig_buf;
char *p;
char **alias;
size_t orig_buf_size;
int *ret_errno;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
proto = va_arg(ap, char *);
break;
case nss_lt_id:
port = va_arg(ap, int);
proto = va_arg(ap, char *);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
serv = va_arg(ap, struct servent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
ret_errno = va_arg(ap, int *);
if (orig_buf_size <
buffer_size - sizeof(struct servent) - sizeof(char *)) {
*ret_errno = ERANGE;
return (NS_RETURN);
}
memcpy(serv, buffer, sizeof(struct servent));
memcpy(&p, buffer + sizeof(struct servent), sizeof(char *));
orig_buf = (char *)_ALIGN(orig_buf);
memcpy(orig_buf, buffer + sizeof(struct servent) + sizeof(char *) +
(_ALIGN(p) - (size_t)p),
buffer_size - sizeof(struct servent) - sizeof(char *) -
(_ALIGN(p) - (size_t)p));
p = (char *)_ALIGN(p);
NS_APPLY_OFFSET(serv->s_name, orig_buf, p, char *);
NS_APPLY_OFFSET(serv->s_proto, orig_buf, p, char *);
if (serv->s_aliases != NULL) {
NS_APPLY_OFFSET(serv->s_aliases, orig_buf, p, char **);
for (alias = serv->s_aliases; *alias; ++alias)
NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
}
if (retval != NULL)
*((struct servent **)retval) = serv;
return (NS_SUCCESS);
}
NSS_MP_CACHE_HANDLING(services);
#endif /* NS_CACHING */
/* get**_r functions implementation */
int
getservbyname_r(const char *name, const char *proto, struct servent *serv,
char *buffer, size_t bufsize, struct servent **result)
{
static const struct servent_mdata mdata = { nss_lt_name, 0 };
static const struct servent_mdata compat_mdata = { nss_lt_name, 1 };
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
services, (void *)nss_lt_name,
serv_id_func, serv_marshal_func, serv_unmarshal_func);
#endif /* NS_CACHING */
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_servent, (void *)&mdata },
{ NSSRC_DB, db_servent, (void *)nss_lt_name },
#ifdef YP
{ NSSRC_NIS, nis_servent, (void *)nss_lt_name },
#endif
{ NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyname_r",
defaultsrc, name, proto, serv, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
int
getservbyport_r(int port, const char *proto, struct servent *serv,
char *buffer, size_t bufsize, struct servent **result)
{
static const struct servent_mdata mdata = { nss_lt_id, 0 };
static const struct servent_mdata compat_mdata = { nss_lt_id, 1 };
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
services, (void *)nss_lt_id,
serv_id_func, serv_marshal_func, serv_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_servent, (void *)&mdata },
{ NSSRC_DB, db_servent, (void *)nss_lt_id },
#ifdef YP
{ NSSRC_NIS, nis_servent, (void *)nss_lt_id },
#endif
{ NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservbyport_r",
defaultsrc, port, proto, serv, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
int
getservent_r(struct servent *serv, char *buffer, size_t bufsize,
struct servent **result)
{
static const struct servent_mdata mdata = { nss_lt_all, 0 };
static const struct servent_mdata compat_mdata = { nss_lt_all, 1 };
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
services, (void *)nss_lt_all,
serv_marshal_func, serv_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_servent, (void *)&mdata },
{ NSSRC_DB, db_servent, (void *)nss_lt_all },
#ifdef YP
{ NSSRC_NIS, nis_servent, (void *)nss_lt_all },
#endif
{ NSSRC_COMPAT, files_servent, (void *)&compat_mdata },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_SERVICES, "getservent_r",
defaultsrc, serv, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
void
setservent(int stayopen)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
services, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setservent, (void *)SETSERVENT },
{ NSSRC_DB, db_setservent, (void *)SETSERVENT },
#ifdef YP
{ NSSRC_NIS, nis_setservent, (void *)SETSERVENT },
#endif
{ NSSRC_COMPAT, compat_setservent, (void *)SETSERVENT },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)nsdispatch(NULL, dtab, NSDB_SERVICES, "setservent", defaultsrc,
stayopen);
}
void
endservent(void)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
services, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setservent, (void *)ENDSERVENT },
{ NSSRC_DB, db_setservent, (void *)ENDSERVENT },
#ifdef YP
{ NSSRC_NIS, nis_setservent, (void *)ENDSERVENT },
#endif
{ NSSRC_COMPAT, compat_setservent, (void *)ENDSERVENT },
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)nsdispatch(NULL, dtab, NSDB_SERVICES, "endservent", defaultsrc);
}
/* get** wrappers for get**_r functions implementation */
static void
servent_endstate(void *p)
{
if (p == NULL)
return;
free(((struct servent_state *)p)->buffer);
free(p);
}
static int
wrap_getservbyname_r(struct key key, struct servent *serv, char *buffer,
size_t bufsize, struct servent **res)
{
return (getservbyname_r(key.name, key.proto, serv, buffer, bufsize,
res));
}
static int
wrap_getservbyport_r(struct key key, struct servent *serv, char *buffer,
size_t bufsize, struct servent **res)
{
return (getservbyport_r(key.port, key.proto, serv, buffer, bufsize,
res));
}
static int
wrap_getservent_r(struct key key, struct servent *serv, char *buffer,
size_t bufsize, struct servent **res)
{
return (getservent_r(serv, buffer, bufsize, res));
}
static struct servent *
getserv(int (*fn)(struct key, struct servent *, char *, size_t,
struct servent **), struct key key)
{
int rv;
struct servent *res;
struct servent_state * st;
rv = servent_getstate(&st);
if (rv != 0) {
errno = rv;
return NULL;
}
if (st->buffer == NULL) {
st->buffer = malloc(SERVENT_STORAGE_INITIAL);
if (st->buffer == NULL)
return (NULL);
st->bufsize = SERVENT_STORAGE_INITIAL;
}
do {
rv = fn(key, &st->serv, st->buffer, st->bufsize, &res);
if (res == NULL && rv == ERANGE) {
free(st->buffer);
if ((st->bufsize << 1) > SERVENT_STORAGE_MAX) {
st->buffer = NULL;
errno = ERANGE;
return (NULL);
}
st->bufsize <<= 1;
st->buffer = malloc(st->bufsize);
if (st->buffer == NULL)
return (NULL);
}
} while (res == NULL && rv == ERANGE);
if (rv != 0)
errno = rv;
return (res);
}
struct servent *
getservbyname(const char *name, const char *proto)
{
struct key key;
key.name = name;
key.proto = proto;
return (getserv(wrap_getservbyname_r, key));
}
struct servent *
getservbyport(int port, const char *proto)
{
struct key key;
key.port = port;
key.proto = proto;
return (getserv(wrap_getservbyport_r, key));
}
struct servent *
getservent(void)
{
struct key key;
key.proto = NULL;
key.port = 0;
return (getserv(wrap_getservent_r, key));
}
diff --git a/lib/libc/net/hesiod.c b/lib/libc/net/hesiod.c
index 421c3a4586d1..edced0707fe0 100644
--- a/lib/libc/net/hesiod.c
+++ b/lib/libc/net/hesiod.c
@@ -1,559 +1,557 @@
/* $NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $ */
/* Copyright (c) 1996 by Internet Software Consortium.
*
* 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
* CONSORTIUM 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.
*/
/* Copyright 1996 by the Massachusetts Institute of Technology.
*
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright
* notice and this permission notice appear in supporting
* documentation, and that the name of M.I.T. not be used in
* advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is"
* without express or implied warranty.
*/
/* This file is part of the hesiod library. It implements the core
* portion of the hesiod resolver.
*
* This file is loosely based on an interim version of hesiod.c from
* the BIND IRS library, which was in turn based on an earlier version
* of this file. Extensive changes have been made on each step of the
* path.
*
* This implementation is not truly thread-safe at the moment because
* it uses res_send() and accesses _res.
*/
-#include <sys/cdefs.h>
#if 0
static char *orig_rcsid = "$NetBSD: hesiod.c,v 1.9 1999/02/11 06:16:38 simonb Exp $";
#endif
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <errno.h>
#include <hesiod.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
struct hesiod_p {
char *lhs; /* normally ".ns" */
char *rhs; /* AKA the default hesiod domain */
int classes[2]; /* The class search order. */
};
#define MAX_HESRESP 1024
static int read_config_file(struct hesiod_p *, const char *);
static char **get_txt_records(int, const char *);
static int init_context(void);
static void translate_errors(void);
/*
* hesiod_init --
* initialize a hesiod_p.
*/
int
hesiod_init(void **context)
{
struct hesiod_p *ctx;
const char *p, *configname;
ctx = malloc(sizeof(struct hesiod_p));
if (ctx) {
*context = ctx;
configname = secure_getenv("HESIOD_CONFIG");
if (!configname)
configname = _PATH_HESIOD_CONF;
if (read_config_file(ctx, configname) >= 0) {
/*
* The default rhs can be overridden by an
* environment variable.
*/
p = secure_getenv("HES_DOMAIN");
if (p) {
if (ctx->rhs)
free(ctx->rhs);
ctx->rhs = malloc(strlen(p) + 2);
if (ctx->rhs) {
*ctx->rhs = '.';
strcpy(ctx->rhs + 1,
(*p == '.') ? p + 1 : p);
return 0;
} else
errno = ENOMEM;
} else
return 0;
}
} else
errno = ENOMEM;
if (ctx->lhs)
free(ctx->lhs);
if (ctx->rhs)
free(ctx->rhs);
if (ctx)
free(ctx);
return -1;
}
/*
* hesiod_end --
* Deallocates the hesiod_p.
*/
void
hesiod_end(void *context)
{
struct hesiod_p *ctx = (struct hesiod_p *) context;
free(ctx->rhs);
if (ctx->lhs)
free(ctx->lhs);
free(ctx);
}
/*
* hesiod_to_bind --
* takes a hesiod (name, type) and returns a DNS
* name which is to be resolved.
*/
char *
hesiod_to_bind(void *context, const char *name, const char *type)
{
struct hesiod_p *ctx = (struct hesiod_p *) context;
char bindname[MAXDNAME], *p, *ret, **rhs_list = NULL;
const char *rhs;
int len;
if (strlcpy(bindname, name, sizeof(bindname)) >= sizeof(bindname)) {
errno = EMSGSIZE;
return NULL;
}
/*
* Find the right right hand side to use, possibly
* truncating bindname.
*/
p = strchr(bindname, '@');
if (p) {
*p++ = 0;
if (strchr(p, '.'))
rhs = name + (p - bindname);
else {
rhs_list = hesiod_resolve(context, p, "rhs-extension");
if (rhs_list)
rhs = *rhs_list;
else {
errno = ENOENT;
return NULL;
}
}
} else
rhs = ctx->rhs;
/* See if we have enough room. */
len = strlen(bindname) + 1 + strlen(type);
if (ctx->lhs)
len += strlen(ctx->lhs) + ((ctx->lhs[0] != '.') ? 1 : 0);
len += strlen(rhs) + ((rhs[0] != '.') ? 1 : 0);
if (len > sizeof(bindname) - 1) {
if (rhs_list)
hesiod_free_list(context, rhs_list);
errno = EMSGSIZE;
return NULL;
}
/* Put together the rest of the domain. */
strcat(bindname, ".");
strcat(bindname, type);
/* Only append lhs if it isn't empty. */
if (ctx->lhs && ctx->lhs[0] != '\0' ) {
if (ctx->lhs[0] != '.')
strcat(bindname, ".");
strcat(bindname, ctx->lhs);
}
if (rhs[0] != '.')
strcat(bindname, ".");
strcat(bindname, rhs);
/* rhs_list is no longer needed, since we're done with rhs. */
if (rhs_list)
hesiod_free_list(context, rhs_list);
/* Make a copy of the result and return it to the caller. */
ret = strdup(bindname);
if (!ret)
errno = ENOMEM;
return ret;
}
/*
* hesiod_resolve --
* Given a hesiod name and type, return an array of strings returned
* by the resolver.
*/
char **
hesiod_resolve(void *context, const char *name, const char *type)
{
struct hesiod_p *ctx = (struct hesiod_p *) context;
char *bindname, **retvec;
bindname = hesiod_to_bind(context, name, type);
if (!bindname)
return NULL;
retvec = get_txt_records(ctx->classes[0], bindname);
if (retvec == NULL && errno == ENOENT && ctx->classes[1])
retvec = get_txt_records(ctx->classes[1], bindname);
free(bindname);
return retvec;
}
/*ARGSUSED*/
void
hesiod_free_list(void *context, char **list)
{
char **p;
if (list == NULL)
return;
for (p = list; *p; p++)
free(*p);
free(list);
}
/* read_config_file --
* Parse the /etc/hesiod.conf file. Returns 0 on success,
* -1 on failure. On failure, it might leave values in ctx->lhs
* or ctx->rhs which need to be freed by the caller.
*/
static int
read_config_file(struct hesiod_p *ctx, const char *filename)
{
char *key, *data, *p, **which;
char buf[MAXDNAME + 7];
int n;
FILE *fp;
/* Set default query classes. */
ctx->classes[0] = C_IN;
ctx->classes[1] = C_HS;
/* Try to open the configuration file. */
fp = fopen(filename, "re");
if (!fp) {
/* Use compiled in default domain names. */
ctx->lhs = strdup(DEF_LHS);
ctx->rhs = strdup(DEF_RHS);
if (ctx->lhs && ctx->rhs)
return 0;
else {
errno = ENOMEM;
return -1;
}
}
ctx->lhs = NULL;
ctx->rhs = NULL;
while (fgets(buf, sizeof(buf), fp) != NULL) {
p = buf;
if (*p == '#' || *p == '\n' || *p == '\r')
continue;
while (*p == ' ' || *p == '\t')
p++;
key = p;
while (*p != ' ' && *p != '\t' && *p != '=')
p++;
*p++ = 0;
while (isspace(*p) || *p == '=')
p++;
data = p;
while (!isspace(*p))
p++;
*p = 0;
if (strcasecmp(key, "lhs") == 0 ||
strcasecmp(key, "rhs") == 0) {
which = (strcasecmp(key, "lhs") == 0)
? &ctx->lhs : &ctx->rhs;
*which = strdup(data);
if (!*which) {
fclose(fp);
errno = ENOMEM;
return -1;
}
} else {
if (strcasecmp(key, "classes") == 0) {
n = 0;
while (*data && n < 2) {
p = data;
while (*p && *p != ',')
p++;
if (*p)
*p++ = 0;
if (strcasecmp(data, "IN") == 0)
ctx->classes[n++] = C_IN;
else
if (strcasecmp(data, "HS") == 0)
ctx->classes[n++] =
C_HS;
data = p;
}
while (n < 2)
ctx->classes[n++] = 0;
}
}
}
fclose(fp);
if (!ctx->rhs || ctx->classes[0] == 0 ||
ctx->classes[0] == ctx->classes[1]) {
errno = ENOEXEC;
return -1;
}
return 0;
}
/*
* get_txt_records --
* Given a DNS class and a DNS name, do a lookup for TXT records, and
* return a list of them.
*/
static char **
get_txt_records(int qclass, const char *name)
{
HEADER *hp;
unsigned char qbuf[PACKETSZ], abuf[MAX_HESRESP], *p, *eom, *eor;
char *dst, **list;
int ancount, qdcount, i, j, n, skip, type, class, len;
/* Make sure the resolver is initialized. */
if ((_res.options & RES_INIT) == 0 && res_init() == -1)
return NULL;
/* Construct the query. */
n = res_mkquery(QUERY, name, qclass, T_TXT, NULL, 0,
NULL, qbuf, PACKETSZ);
if (n < 0)
return NULL;
/* Send the query. */
n = res_send(qbuf, n, abuf, MAX_HESRESP);
if (n < 0 || n > MAX_HESRESP) {
errno = ECONNREFUSED; /* XXX */
return NULL;
}
/* Parse the header of the result. */
hp = (HEADER *) (void *) abuf;
ancount = ntohs(hp->ancount);
qdcount = ntohs(hp->qdcount);
p = abuf + sizeof(HEADER);
eom = abuf + n;
/*
* Skip questions, trying to get to the answer section
* which follows.
*/
for (i = 0; i < qdcount; i++) {
skip = dn_skipname(p, eom);
if (skip < 0 || p + skip + QFIXEDSZ > eom) {
errno = EMSGSIZE;
return NULL;
}
p += skip + QFIXEDSZ;
}
/* Allocate space for the text record answers. */
list = malloc((ancount + 1) * sizeof(char *));
if (!list) {
errno = ENOMEM;
return NULL;
}
/* Parse the answers. */
j = 0;
for (i = 0; i < ancount; i++) {
/* Parse the header of this answer. */
skip = dn_skipname(p, eom);
if (skip < 0 || p + skip + 10 > eom)
break;
type = p[skip + 0] << 8 | p[skip + 1];
class = p[skip + 2] << 8 | p[skip + 3];
len = p[skip + 8] << 8 | p[skip + 9];
p += skip + 10;
if (p + len > eom) {
errno = EMSGSIZE;
break;
}
/* Skip entries of the wrong class and type. */
if (class != qclass || type != T_TXT) {
p += len;
continue;
}
/* Allocate space for this answer. */
list[j] = malloc((size_t)len);
if (!list[j]) {
errno = ENOMEM;
break;
}
dst = list[j++];
/* Copy answer data into the allocated area. */
eor = p + len;
while (p < eor) {
n = (unsigned char) *p++;
if (p + n > eor) {
errno = EMSGSIZE;
break;
}
memcpy(dst, p, (size_t)n);
p += n;
dst += n;
}
if (p < eor) {
errno = EMSGSIZE;
break;
}
*dst = 0;
}
/*
* If we didn't terminate the loop normally, something
* went wrong.
*/
if (i < ancount) {
for (i = 0; i < j; i++)
free(list[i]);
free(list);
return NULL;
}
if (j == 0) {
errno = ENOENT;
free(list);
return NULL;
}
list[j] = NULL;
return list;
}
/*
* COMPATIBILITY FUNCTIONS
*/
static int inited = 0;
static void *context;
static int errval = HES_ER_UNINIT;
int
hes_init(void)
{
init_context();
return errval;
}
char *
hes_to_bind(const char *name, const char *type)
{
static char *bindname;
if (init_context() < 0)
return NULL;
if (bindname)
free(bindname);
bindname = hesiod_to_bind(context, name, type);
if (!bindname)
translate_errors();
return bindname;
}
char **
hes_resolve(const char *name, const char *type)
{
static char **list;
if (init_context() < 0)
return NULL;
/*
* In the old Hesiod interface, the caller was responsible for
* freeing the returned strings but not the vector of strings itself.
*/
if (list)
free(list);
list = hesiod_resolve(context, name, type);
if (!list)
translate_errors();
return list;
}
int
hes_error(void)
{
return errval;
}
void
hes_free(char **hp)
{
hesiod_free_list(context, hp);
}
static int
init_context(void)
{
if (!inited) {
inited = 1;
if (hesiod_init(&context) < 0) {
errval = HES_ER_CONFIG;
return -1;
}
errval = HES_ER_OK;
}
return 0;
}
static void
translate_errors(void)
{
switch (errno) {
case ENOENT:
errval = HES_ER_NOTFOUND;
break;
case ECONNREFUSED:
case EMSGSIZE:
errval = HES_ER_NET;
break;
case ENOMEM:
default:
/* Not a good match, but the best we can do. */
errval = HES_ER_CONFIG;
break;
}
}
diff --git a/lib/libc/net/if_indextoname.c b/lib/libc/net/if_indextoname.c
index ba4bd7ab3794..99620c9cac0d 100644
--- a/lib/libc/net/if_indextoname.c
+++ b/lib/libc/net/if_indextoname.c
@@ -1,93 +1,92 @@
/* $KAME: if_indextoname.c,v 1.7 2000/11/08 03:09:30 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-1-Clause
*
* Copyright (c) 1997, 2000
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI Id: if_indextoname.c,v 2.3 2000/04/17 22:38:05 dab Exp
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
/*
* From RFC 2553:
*
* The second function maps an interface index into its corresponding
* name.
*
* #include <net/if.h>
*
* char *if_indextoname(unsigned int ifindex, char *ifname);
*
* The ifname argument must point to a buffer of at least IF_NAMESIZE
* bytes into which the interface name corresponding to the specified
* index is returned. (IF_NAMESIZE is also defined in <net/if.h> and
* its value includes a terminating null byte at the end of the
* interface name.) This pointer is also the return value of the
* function. If there is no interface corresponding to the specified
* index, NULL is returned, and errno is set to ENXIO, if there was a
* system error (such as running out of memory), if_indextoname returns
* NULL and errno would be set to the proper value (e.g., ENOMEM).
*/
char *
if_indextoname(unsigned int ifindex, char *ifname)
{
struct ifaddrs *ifaddrs, *ifa;
int error = 0;
if (ifindex == 0) {
errno = ENXIO;
return(NULL);
}
if (getifaddrs(&ifaddrs) < 0)
return(NULL); /* getifaddrs properly set errno */
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK &&
ifindex == LLINDEX((struct sockaddr_dl*)ifa->ifa_addr))
break;
}
if (ifa == NULL) {
error = ENXIO;
ifname = NULL;
}
else
strncpy(ifname, ifa->ifa_name, IFNAMSIZ);
freeifaddrs(ifaddrs);
errno = error;
return(ifname);
}
diff --git a/lib/libc/net/if_nameindex.c b/lib/libc/net/if_nameindex.c
index ca052e91f7a5..a7c2c92bd8d1 100644
--- a/lib/libc/net/if_nameindex.c
+++ b/lib/libc/net/if_nameindex.c
@@ -1,147 +1,146 @@
/* $KAME: if_nameindex.c,v 1.8 2000/11/24 08:20:01 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-1-Clause
*
* Copyright (c) 1997, 2000
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI Id: if_nameindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <net/if.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
/*
* From RFC 2553:
*
* 4.3 Return All Interface Names and Indexes
*
* The if_nameindex structure holds the information about a single
* interface and is defined as a result of including the <net/if.h>
* header.
*
* struct if_nameindex {
* unsigned int if_index;
* char *if_name;
* };
*
* The final function returns an array of if_nameindex structures, one
* structure per interface.
*
* struct if_nameindex *if_nameindex(void);
*
* The end of the array of structures is indicated by a structure with
* an if_index of 0 and an if_name of NULL. The function returns a NULL
* pointer upon an error, and would set errno to the appropriate value.
*
* The memory used for this array of structures along with the interface
* names pointed to by the if_name members is obtained dynamically.
* This memory is freed by the next function.
*
* 4.4. Free Memory
*
* The following function frees the dynamic memory that was allocated by
* if_nameindex().
*
* #include <net/if.h>
*
* void if_freenameindex(struct if_nameindex *ptr);
*
* The argument to this function must be a pointer that was returned by
* if_nameindex().
*/
struct if_nameindex *
if_nameindex(void)
{
struct ifaddrs *ifaddrs, *ifa;
unsigned int ni;
int nbytes;
struct if_nameindex *ifni, *ifni2;
char *cp;
if (getifaddrs(&ifaddrs) < 0)
return(NULL);
/*
* First, find out how many interfaces there are, and how
* much space we need for the string names.
*/
ni = 0;
nbytes = 0;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK) {
nbytes += strlen(ifa->ifa_name) + 1;
ni++;
}
}
/*
* Next, allocate a chunk of memory, use the first part
* for the array of structures, and the last part for
* the strings.
*/
cp = malloc((ni + 1) * sizeof(struct if_nameindex) + nbytes);
ifni = (struct if_nameindex *)cp;
if (ifni == NULL)
goto out;
cp += (ni + 1) * sizeof(struct if_nameindex);
/*
* Now just loop through the list of interfaces again,
* filling in the if_nameindex array and making copies
* of all the strings.
*/
ifni2 = ifni;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK) {
ifni2->if_index =
LLINDEX((struct sockaddr_dl*)ifa->ifa_addr);
ifni2->if_name = cp;
strcpy(cp, ifa->ifa_name);
ifni2++;
cp += strlen(cp) + 1;
}
}
/*
* Finally, don't forget to terminate the array.
*/
ifni2->if_index = 0;
ifni2->if_name = NULL;
out:
freeifaddrs(ifaddrs);
return(ifni);
}
void
if_freenameindex(struct if_nameindex *ptr)
{
free(ptr);
}
diff --git a/lib/libc/net/if_nametoindex.c b/lib/libc/net/if_nametoindex.c
index 0042bc8c0f4f..febf33b86667 100644
--- a/lib/libc/net/if_nametoindex.c
+++ b/lib/libc/net/if_nametoindex.c
@@ -1,100 +1,99 @@
/* $KAME: if_nametoindex.c,v 1.6 2000/11/24 08:18:54 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-1-Clause
*
* Copyright (c) 1997, 2000
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI Id: if_nametoindex.c,v 2.3 2000/04/17 22:38:05 dab Exp
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "un-namespace.h"
/*
* From RFC 2553:
*
* 4.1 Name-to-Index
*
*
* The first function maps an interface name into its corresponding
* index.
*
* #include <net/if.h>
*
* unsigned int if_nametoindex(const char *ifname);
*
* If the specified interface name does not exist, the return value is
* 0, and errno is set to ENXIO. If there was a system error (such as
* running out of memory), the return value is 0 and errno is set to the
* proper value (e.g., ENOMEM).
*/
unsigned int
if_nametoindex(const char *ifname)
{
int s;
struct ifreq ifr;
struct ifaddrs *ifaddrs, *ifa;
unsigned int ni;
s = _socket(AF_INET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
if (s != -1) {
memset(&ifr, 0, sizeof(ifr));
strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
if (_ioctl(s, SIOCGIFINDEX, &ifr) != -1) {
_close(s);
return (ifr.ifr_index);
}
_close(s);
}
if (getifaddrs(&ifaddrs) < 0)
return(0);
ni = 0;
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
if (ifa->ifa_addr &&
ifa->ifa_addr->sa_family == AF_LINK &&
strcmp(ifa->ifa_name, ifname) == 0) {
ni = LLINDEX((struct sockaddr_dl*)ifa->ifa_addr);
break;
}
}
freeifaddrs(ifaddrs);
if (!ni)
errno = ENXIO;
return(ni);
}
diff --git a/lib/libc/net/ip6opt.c b/lib/libc/net/ip6opt.c
index 54bd24939d3c..4f53840299ea 100644
--- a/lib/libc/net/ip6opt.c
+++ b/lib/libc/net/ip6opt.c
@@ -1,599 +1,598 @@
/* $KAME: ip6opt.c,v 1.13 2003/06/06 10:08:20 suz Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <string.h>
#include <stdio.h>
static int ip6optlen(u_int8_t *opt, u_int8_t *lim);
static void inet6_insert_padopt(u_char *p, int len);
#ifndef IPV6_2292HOPOPTS
#define IPV6_2292HOPOPTS 22
#endif
#ifndef IPV6_2292DSTOPTS
#define IPV6_2292DSTOPTS 23
#endif
#define is_ipv6_hopopts(x) \
((x) == IPV6_HOPOPTS || (x) == IPV6_2292HOPOPTS)
#define is_ipv6_dstopts(x) \
((x) == IPV6_DSTOPTS || (x) == IPV6_2292DSTOPTS)
/*
* This function returns the number of bytes required to hold an option
* when it is stored as ancillary data, including the cmsghdr structure
* at the beginning, and any padding at the end (to make its size a
* multiple of 8 bytes). The argument is the size of the structure
* defining the option, which must include any pad bytes at the
* beginning (the value y in the alignment term "xn + y"), the type
* byte, the length byte, and the option data.
*/
int
inet6_option_space(int nbytes)
{
nbytes += 2; /* we need space for nxt-hdr and length fields */
return(CMSG_SPACE((nbytes + 7) & ~7));
}
/*
* This function is called once per ancillary data object that will
* contain either Hop-by-Hop or Destination options. It returns 0 on
* success or -1 on an error.
*/
int
inet6_option_init(void *bp, struct cmsghdr **cmsgp, int type)
{
struct cmsghdr *ch = (struct cmsghdr *)bp;
/* argument validation */
if (!is_ipv6_hopopts(type) && !is_ipv6_dstopts(type))
return(-1);
ch->cmsg_level = IPPROTO_IPV6;
ch->cmsg_type = type;
ch->cmsg_len = CMSG_LEN(0);
*cmsgp = ch;
return(0);
}
/*
* This function appends a Hop-by-Hop option or a Destination option
* into an ancillary data object that has been initialized by
* inet6_option_init(). This function returns 0 if it succeeds or -1 on
* an error.
* multx is the value x in the alignment term "xn + y" described
* earlier. It must have a value of 1, 2, 4, or 8.
* plusy is the value y in the alignment term "xn + y" described
* earlier. It must have a value between 0 and 7, inclusive.
*/
int
inet6_option_append(struct cmsghdr *cmsg, const u_int8_t *typep, int multx,
int plusy)
{
int padlen, optlen, off;
u_char *bp = (u_char *)cmsg + cmsg->cmsg_len;
struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
/* argument validation */
if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
return(-1);
if (plusy < 0 || plusy > 7)
return(-1);
/*
* If this is the first option, allocate space for the
* first 2 bytes(for next header and length fields) of
* the option header.
*/
if (bp == (u_char *)eh) {
bp += 2;
cmsg->cmsg_len += 2;
}
/* calculate pad length before the option. */
off = bp - (u_char *)eh;
padlen = roundup2(off % multx, multx) - (off % multx);
padlen += plusy;
padlen %= multx; /* keep the pad as short as possible */
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
bp += padlen;
/* copy the option */
if (typep[0] == IP6OPT_PAD1)
optlen = 1;
else
optlen = typep[1] + 2;
memcpy(bp, typep, optlen);
bp += optlen;
cmsg->cmsg_len += optlen;
/* calculate pad length after the option and insert the padding */
off = bp - (u_char *)eh;
padlen = ((off + 7) & ~7) - off;
inet6_insert_padopt(bp, padlen);
bp += padlen;
cmsg->cmsg_len += padlen;
/* update the length field of the ip6 option header */
eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
return(0);
}
/*
* This function appends a Hop-by-Hop option or a Destination option
* into an ancillary data object that has been initialized by
* inet6_option_init(). This function returns a pointer to the 8-bit
* option type field that starts the option on success, or NULL on an
* error.
* The difference between this function and inet6_option_append() is
* that the latter copies the contents of a previously built option into
* the ancillary data object while the current function returns a
* pointer to the space in the data object where the option's TLV must
* then be built by the caller.
*
*/
u_int8_t *
inet6_option_alloc(struct cmsghdr *cmsg, int datalen, int multx, int plusy)
{
int padlen, off;
u_int8_t *bp = (u_char *)cmsg + cmsg->cmsg_len;
u_int8_t *retval;
struct ip6_ext *eh = (struct ip6_ext *)CMSG_DATA(cmsg);
/* argument validation */
if (multx != 1 && multx != 2 && multx != 4 && multx != 8)
return(NULL);
if (plusy < 0 || plusy > 7)
return(NULL);
/*
* If this is the first option, allocate space for the
* first 2 bytes(for next header and length fields) of
* the option header.
*/
if (bp == (u_char *)eh) {
bp += 2;
cmsg->cmsg_len += 2;
}
/* calculate pad length before the option. */
off = bp - (u_char *)eh;
padlen = roundup2(off % multx, multx) - (off % multx);
padlen += plusy;
padlen %= multx; /* keep the pad as short as possible */
/* insert padding */
inet6_insert_padopt(bp, padlen);
cmsg->cmsg_len += padlen;
bp += padlen;
/* keep space to store specified length of data */
retval = bp;
bp += datalen;
cmsg->cmsg_len += datalen;
/* calculate pad length after the option and insert the padding */
off = bp - (u_char *)eh;
padlen = ((off + 7) & ~7) - off;
inet6_insert_padopt(bp, padlen);
bp += padlen;
cmsg->cmsg_len += padlen;
/* update the length field of the ip6 option header */
eh->ip6e_len = ((bp - (u_char *)eh) >> 3) - 1;
return(retval);
}
/*
* This function processes the next Hop-by-Hop option or Destination
* option in an ancillary data object. If another option remains to be
* processed, the return value of the function is 0 and *tptrp points to
* the 8-bit option type field (which is followed by the 8-bit option
* data length, followed by the option data). If no more options remain
* to be processed, the return value is -1 and *tptrp is NULL. If an
* error occurs, the return value is -1 and *tptrp is not NULL.
* (RFC 2292, 6.3.5)
*/
int
inet6_option_next(const struct cmsghdr *cmsg, u_int8_t **tptrp)
{
struct ip6_ext *ip6e;
int hdrlen, optlen;
u_int8_t *lim;
if (cmsg->cmsg_level != IPPROTO_IPV6 ||
(!is_ipv6_hopopts(cmsg->cmsg_type) &&
!is_ipv6_dstopts(cmsg->cmsg_type)))
return(-1);
/* message length validation */
if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
return(-1);
ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
hdrlen = (ip6e->ip6e_len + 1) << 3;
if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
return(-1);
/*
* If the caller does not specify the starting point,
* simply return the 1st option.
* Otherwise, search the option list for the next option.
*/
lim = (u_int8_t *)ip6e + hdrlen;
if (*tptrp == NULL)
*tptrp = (u_int8_t *)(ip6e + 1);
else {
if ((optlen = ip6optlen(*tptrp, lim)) == 0)
return(-1);
*tptrp = *tptrp + optlen;
}
if (*tptrp >= lim) { /* there is no option */
*tptrp = NULL;
return(-1);
}
/*
* Finally, checks if the next option is safely stored in the
* cmsg data.
*/
if (ip6optlen(*tptrp, lim) == 0)
return(-1);
else
return(0);
}
/*
* This function is similar to the inet6_option_next() function,
* except this function lets the caller specify the option type to be
* searched for, instead of always returning the next option in the
* ancillary data object.
* Note: RFC 2292 says the type of tptrp is u_int8_t *, but we think
* it's a typo. The variable should be type of u_int8_t **.
*/
int
inet6_option_find(const struct cmsghdr *cmsg, u_int8_t **tptrp, int type)
{
struct ip6_ext *ip6e;
int hdrlen, optlen;
u_int8_t *optp, *lim;
if (cmsg->cmsg_level != IPPROTO_IPV6 ||
(!is_ipv6_hopopts(cmsg->cmsg_type) &&
!is_ipv6_dstopts(cmsg->cmsg_type)))
return(-1);
/* message length validation */
if (cmsg->cmsg_len < CMSG_SPACE(sizeof(struct ip6_ext)))
return(-1);
ip6e = (struct ip6_ext *)CMSG_DATA(cmsg);
hdrlen = (ip6e->ip6e_len + 1) << 3;
if (cmsg->cmsg_len < CMSG_SPACE(hdrlen))
return(-1);
/*
* If the caller does not specify the starting point,
* search from the beginning of the option list.
* Otherwise, search from *the next option* of the specified point.
*/
lim = (u_int8_t *)ip6e + hdrlen;
if (*tptrp == NULL)
*tptrp = (u_int8_t *)(ip6e + 1);
else {
if ((optlen = ip6optlen(*tptrp, lim)) == 0)
return(-1);
*tptrp = *tptrp + optlen;
}
for (optp = *tptrp; optp < lim; optp += optlen) {
if (*optp == type) {
*tptrp = optp;
return(0);
}
if ((optlen = ip6optlen(optp, lim)) == 0)
return(-1);
}
/* search failed */
*tptrp = NULL;
return(-1);
}
/*
* Calculate the length of a given IPv6 option. Also checks
* if the option is safely stored in user's buffer according to the
* calculated length and the limitation of the buffer.
*/
static int
ip6optlen(u_int8_t *opt, u_int8_t *lim)
{
int optlen;
if (*opt == IP6OPT_PAD1)
optlen = 1;
else {
/* is there enough space to store type and len? */
if (opt + 2 > lim)
return(0);
optlen = *(opt + 1) + 2;
}
if (opt + optlen <= lim)
return(optlen);
return(0);
}
static void
inet6_insert_padopt(u_char *p, int len)
{
switch(len) {
case 0:
return;
case 1:
p[0] = IP6OPT_PAD1;
return;
default:
p[0] = IP6OPT_PADN;
p[1] = len - 2;
memset(&p[2], 0, len - 2);
return;
}
}
/*
* The following functions are defined in RFC3542, which is a successor
* of RFC2292.
*/
int
inet6_opt_init(void *extbuf, socklen_t extlen)
{
struct ip6_ext *ext = (struct ip6_ext *)extbuf;
if (ext) {
if (extlen <= 0 || (extlen % 8))
return(-1);
ext->ip6e_len = (extlen >> 3) - 1;
}
return(2); /* sizeof the next and the length fields */
}
int
inet6_opt_append(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
socklen_t len, u_int8_t align, void **databufp)
{
int currentlen = offset, padlen = 0;
/*
* The option type must have a value from 2 to 255, inclusive.
* (0 and 1 are reserved for the Pad1 and PadN options, respectively.)
*/
if (type < 2)
return(-1);
/*
* The option data length must have a value between 0 and 255,
* inclusive, and is the length of the option data that follows.
*/
if (len > 255 || len < 0 )
return(-1);
/*
* The align parameter must have a value of 1, 2, 4, or 8.
* The align value can not exceed the value of len.
*/
if (align != 1 && align != 2 && align != 4 && align != 8)
return(-1);
if (align > len)
return(-1);
/* Calculate the padding length. */
currentlen += 2 + len; /* 2 means "type + len" */
if (currentlen % align)
padlen = align - (currentlen % align);
/* The option must fit in the extension header buffer. */
currentlen += padlen;
if (extlen && /* XXX: right? */
currentlen > extlen)
return(-1);
if (extbuf) {
u_int8_t *optp = (u_int8_t *)extbuf + offset;
if (padlen == 1) {
/* insert a Pad1 option */
*optp = IP6OPT_PAD1;
optp++;
}
else if (padlen > 0) {
/* insert a PadN option for alignment */
*optp++ = IP6OPT_PADN;
*optp++ = padlen - 2;
memset(optp, 0, padlen - 2);
optp += (padlen - 2);
}
*optp++ = type;
*optp++ = len;
*databufp = optp;
}
return(currentlen);
}
int
inet6_opt_finish(void *extbuf, socklen_t extlen, int offset)
{
int updatelen = offset > 0 ? (1 + ((offset - 1) | 7)) : 0;
if (extbuf) {
u_int8_t *padp;
int padlen = updatelen - offset;
if (updatelen > extlen)
return(-1);
padp = (u_int8_t *)extbuf + offset;
if (padlen == 1)
*padp = IP6OPT_PAD1;
else if (padlen > 0) {
*padp++ = IP6OPT_PADN;
*padp++ = (padlen - 2);
memset(padp, 0, padlen - 2);
}
}
return(updatelen);
}
int
inet6_opt_set_val(void *databuf, int offset, void *val, socklen_t vallen)
{
memcpy((u_int8_t *)databuf + offset, val, vallen);
return(offset + vallen);
}
int
inet6_opt_next(void *extbuf, socklen_t extlen, int offset, u_int8_t *typep,
socklen_t *lenp, void **databufp)
{
u_int8_t *optp, *lim;
int optlen;
/* Validate extlen. XXX: is the variable really necessary?? */
if (extlen == 0 || (extlen % 8))
return(-1);
lim = (u_int8_t *)extbuf + extlen;
/*
* If this is the first time this function called for this options
* header, simply return the 1st option.
* Otherwise, search the option list for the next option.
*/
if (offset == 0) {
optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
}
else
optp = (u_int8_t *)extbuf + offset;
/* Find the next option skipping any padding options. */
while(optp < lim) {
switch(*optp) {
case IP6OPT_PAD1:
optp++;
break;
case IP6OPT_PADN:
if ((optlen = ip6optlen(optp, lim)) == 0)
goto optend;
optp += optlen;
break;
default: /* found */
if ((optlen = ip6optlen(optp, lim)) == 0)
goto optend;
*typep = *optp;
*lenp = optlen - 2;
*databufp = optp + 2;
return(optp + optlen - (u_int8_t *)extbuf);
}
}
optend:
*databufp = NULL; /* for safety */
return(-1);
}
int
inet6_opt_find(void *extbuf, socklen_t extlen, int offset, u_int8_t type,
socklen_t *lenp, void **databufp)
{
u_int8_t *optp, *lim;
int optlen;
/* Validate extlen. XXX: is the variable really necessary?? */
if (extlen == 0 || (extlen % 8))
return(-1);
lim = (u_int8_t *)extbuf + extlen;
/*
* If this is the first time this function called for this options
* header, simply return the 1st option.
* Otherwise, search the option list for the next option.
*/
if (offset == 0) {
optp = (u_int8_t *)((struct ip6_hbh *)extbuf + 1);
}
else
optp = (u_int8_t *)extbuf + offset;
/* Find the specified option */
while(optp < lim) {
if ((optlen = ip6optlen(optp, lim)) == 0)
goto optend;
if (*optp == type) { /* found */
*lenp = optlen - 2;
*databufp = optp + 2;
return(optp + optlen - (u_int8_t *)extbuf);
}
optp += optlen;
}
optend:
*databufp = NULL; /* for safety */
return(-1);
}
int
inet6_opt_get_val(void *databuf, int offset, void *val, socklen_t vallen)
{
/* we can't assume alignment here */
memcpy(val, (u_int8_t *)databuf + offset, vallen);
return(offset + vallen);
}
diff --git a/lib/libc/net/linkaddr.c b/lib/libc/net/linkaddr.c
index df1b7b94276e..5cff503331db 100644
--- a/lib/libc/net/linkaddr.c
+++ b/lib/libc/net/linkaddr.c
@@ -1,169 +1,168 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)linkaddr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <net/if.h>
#include <net/if_dl.h>
#include <string.h>
/* States*/
#define NAMING 0
#define GOTONE 1
#define GOTTWO 2
#define RESET 3
/* Inputs */
#define DIGIT (4*0)
#define END (4*1)
#define DELIM (4*2)
#define LETTER (4*3)
void
link_addr(const char *addr, struct sockaddr_dl *sdl)
{
char *cp = sdl->sdl_data;
char *cplim = sdl->sdl_len + (char *)sdl;
int byte = 0, state = NAMING, new;
bzero((char *)&sdl->sdl_family, sdl->sdl_len - 1);
sdl->sdl_family = AF_LINK;
do {
state &= ~LETTER;
if ((*addr >= '0') && (*addr <= '9')) {
new = *addr - '0';
} else if ((*addr >= 'a') && (*addr <= 'f')) {
new = *addr - 'a' + 10;
} else if ((*addr >= 'A') && (*addr <= 'F')) {
new = *addr - 'A' + 10;
} else if (*addr == 0) {
state |= END;
} else if (state == NAMING &&
(((*addr >= 'A') && (*addr <= 'Z')) ||
((*addr >= 'a') && (*addr <= 'z'))))
state |= LETTER;
else
state |= DELIM;
addr++;
switch (state /* | INPUT */) {
case NAMING | DIGIT:
case NAMING | LETTER:
*cp++ = addr[-1];
continue;
case NAMING | DELIM:
state = RESET;
sdl->sdl_nlen = cp - sdl->sdl_data;
continue;
case GOTTWO | DIGIT:
*cp++ = byte;
/* FALLTHROUGH */
case RESET | DIGIT:
state = GOTONE;
byte = new;
continue;
case GOTONE | DIGIT:
state = GOTTWO;
byte = new + (byte << 4);
continue;
default: /* | DELIM */
state = RESET;
*cp++ = byte;
byte = 0;
continue;
case GOTONE | END:
case GOTTWO | END:
*cp++ = byte;
/* FALLTHROUGH */
case RESET | END:
break;
}
break;
} while (cp < cplim);
sdl->sdl_alen = cp - LLADDR(sdl);
new = cp - (char *)sdl;
if (new > sizeof(*sdl))
sdl->sdl_len = new;
return;
}
static const char hexlist[] = "0123456789abcdef";
char *
link_ntoa(const struct sockaddr_dl *sdl)
{
static char obuf[64];
_Static_assert(sizeof(obuf) >= IFNAMSIZ + 20, "obuf is too small");
char *out;
const u_char *in, *inlim;
int namelen, i, rem;
namelen = (sdl->sdl_nlen <= IFNAMSIZ) ? sdl->sdl_nlen : IFNAMSIZ;
out = obuf;
rem = sizeof(obuf);
if (namelen > 0) {
bcopy(sdl->sdl_data, out, namelen);
out += namelen;
rem -= namelen;
if (sdl->sdl_alen > 0) {
*out++ = ':';
rem--;
}
}
in = (const u_char *)sdl->sdl_data + sdl->sdl_nlen;
inlim = in + sdl->sdl_alen;
while (in < inlim && rem > 1) {
if (in != (const u_char *)sdl->sdl_data + sdl->sdl_nlen) {
*out++ = '.';
rem--;
}
i = *in++;
if (i > 0xf) {
if (rem < 3)
break;
*out++ = hexlist[i >> 4];
*out++ = hexlist[i & 0xf];
rem -= 2;
} else {
if (rem < 2)
break;
*out++ = hexlist[i];
rem--;
}
}
*out = 0;
return (obuf);
}
diff --git a/lib/libc/net/map_v4v6.c b/lib/libc/net/map_v4v6.c
index 7a624df5d552..d4713705a48d 100644
--- a/lib/libc/net/map_v4v6.c
+++ b/lib/libc/net/map_v4v6.c
@@ -1,111 +1,110 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* ++Copyright++ 1985, 1988, 1993
* -
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* -
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
* -
* --Copyright--
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <resolv.h>
#include <ctype.h>
#include <syslog.h>
#include "netdb_private.h"
typedef union {
int32_t al;
char ac;
} align;
void
_map_v4v6_address(const char *src, char *dst)
{
/* Our caller may update in place. */
memmove(&dst[12], src, NS_INADDRSZ);
/* Mark this ipv6 addr as a mapped ipv4. */
memset(&dst[10], 0xff, 2);
memset(&dst[0], 0, 10);
}
void
_map_v4v6_hostent(struct hostent *hp, char **bpp, char *ep) {
char **ap;
if (hp->h_addrtype != AF_INET || hp->h_length != INADDRSZ)
return;
hp->h_addrtype = AF_INET6;
hp->h_length = IN6ADDRSZ;
for (ap = hp->h_addr_list; *ap; ap++) {
int i = (u_long)*bpp % sizeof(align);
if (i != 0)
i = sizeof(align) - i;
if ((ep - *bpp) < (i + IN6ADDRSZ)) {
/* Out of memory. Truncate address list here. */
*ap = NULL;
return;
}
*bpp += i;
_map_v4v6_address(*ap, *bpp);
*ap = *bpp;
*bpp += IN6ADDRSZ;
}
}
diff --git a/lib/libc/net/name6.c b/lib/libc/net/name6.c
index 75a663ab1ca7..ae1a117665cb 100644
--- a/lib/libc/net/name6.c
+++ b/lib/libc/net/name6.c
@@ -1,1131 +1,1130 @@
/* $KAME: name6.c,v 1.25 2000/06/26 16:44:40 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 1995, 1996, 1997, 1998, and 1999 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* ++Copyright++ 1985, 1988, 1993
* -
* Copyright (c) 1985, 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* -
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
* -
* --Copyright--
*/
/*
* Atsushi Onoe <onoe@sm.sony.co.jp>
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/queue.h>
#include <netinet/in.h>
#ifdef INET6
#include <net/if.h>
#include <sys/sysctl.h>
#include <sys/ioctl.h>
#include <netinet6/in6_var.h> /* XXX */
#endif
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <nsswitch.h>
#include <unistd.h>
#include "un-namespace.h"
#include "netdb_private.h"
#include "res_private.h"
#ifndef MAXALIASES
#define MAXALIASES 10
#endif
#ifndef MAXADDRS
#define MAXADDRS 20
#endif
#ifndef MAXDNAME
#define MAXDNAME 1025
#endif
#ifdef INET6
#define ADDRLEN(af) ((af) == AF_INET6 ? sizeof(struct in6_addr) : \
sizeof(struct in_addr))
#else
#define ADDRLEN(af) sizeof(struct in_addr)
#endif
#define MAPADDR(ab, ina) \
do { \
memcpy(&(ab)->map_inaddr, ina, sizeof(struct in_addr)); \
memset((ab)->map_zero, 0, sizeof((ab)->map_zero)); \
memset((ab)->map_one, 0xff, sizeof((ab)->map_one)); \
} while (0)
#define MAPADDRENABLED(flags) \
(((flags) & AI_V4MAPPED) || \
(((flags) & AI_V4MAPPED_CFG)))
union inx_addr {
struct in_addr in_addr;
#ifdef INET6
struct in6_addr in6_addr;
#endif
struct {
u_char mau_zero[10];
u_char mau_one[2];
struct in_addr mau_inaddr;
} map_addr_un;
#define map_zero map_addr_un.mau_zero
#define map_one map_addr_un.mau_one
#define map_inaddr map_addr_un.mau_inaddr
};
struct policyqueue {
TAILQ_ENTRY(policyqueue) pc_entry;
#ifdef INET6
struct in6_addrpolicy pc_policy;
#endif
};
TAILQ_HEAD(policyhead, policyqueue);
#define AIO_SRCFLAG_DEPRECATED 0x1
struct hp_order {
union {
struct sockaddr_storage aiou_ss;
struct sockaddr aiou_sa;
} aio_src_un;
#define aio_srcsa aio_src_un.aiou_sa
u_int32_t aio_srcflag;
int aio_srcscope;
int aio_dstscope;
struct policyqueue *aio_srcpolicy;
struct policyqueue *aio_dstpolicy;
union {
struct sockaddr_storage aiou_ss;
struct sockaddr aiou_sa;
} aio_un;
#define aio_sa aio_un.aiou_sa
int aio_matchlen;
char *aio_h_addr;
int aio_initial_sequence;
};
static struct hostent *_hpcopy(struct hostent *, int *);
static struct hostent *_hpaddr(int, const char *, void *, int *);
#ifdef INET6
static struct hostent *_hpmerge(struct hostent *, struct hostent *, int *);
static struct hostent *_hpmapv6(struct hostent *, int *);
#endif
static struct hostent *_hpsort(struct hostent *, res_state);
#ifdef INET6
static struct hostent *_hpreorder(struct hostent *);
static int get_addrselectpolicy(struct policyhead *);
static void free_addrselectpolicy(struct policyhead *);
static struct policyqueue *match_addrselectpolicy(struct sockaddr *,
struct policyhead *);
static void set_source(struct hp_order *, struct policyhead *);
static int matchlen(struct sockaddr *, struct sockaddr *);
static int comp_dst(const void *, const void *);
static int gai_addr2scopetype(struct sockaddr *);
#endif
/*
* Functions defined in RFC2553
* getipnodebyname, getipnodebyaddr, freehostent
*/
struct hostent *
getipnodebyname(const char *name, int af, int flags, int *errp)
{
struct hostent *hp;
union inx_addr addrbuf;
res_state statp;
u_long options;
switch (af) {
case AF_INET:
#ifdef INET6
case AF_INET6:
#endif
break;
default:
*errp = NO_RECOVERY;
return NULL;
}
if (flags & AI_ADDRCONFIG) {
int s;
if ((s = _socket(af, SOCK_DGRAM | SOCK_CLOEXEC, 0)) < 0)
return NULL;
/*
* TODO:
* Note that implementation dependent test for address
* configuration should be done every time called
* (or appropriate interval),
* because addresses will be dynamically assigned or deleted.
*/
_close(s);
}
#ifdef INET6
/* special case for literal address */
if (inet_pton(AF_INET6, name, &addrbuf) == 1) {
if (af != AF_INET6) {
*errp = HOST_NOT_FOUND;
return NULL;
}
return _hpaddr(af, name, &addrbuf, errp);
}
#endif
if (inet_aton(name, (struct in_addr *)&addrbuf) == 1) {
if (af != AF_INET) {
if (MAPADDRENABLED(flags)) {
MAPADDR(&addrbuf, &addrbuf.in_addr);
} else {
*errp = HOST_NOT_FOUND;
return NULL;
}
}
return _hpaddr(af, name, &addrbuf, errp);
}
statp = __res_state();
if ((statp->options & RES_INIT) == 0) {
if (res_ninit(statp) < 0) {
*errp = NETDB_INTERNAL;
return NULL;
}
}
options = statp->options;
statp->options &= ~RES_USE_INET6;
hp = gethostbyname2(name, af);
hp = _hpcopy(hp, errp);
#ifdef INET6
if (af == AF_INET6)
hp = _hpreorder(hp);
if (af == AF_INET6 && ((flags & AI_ALL) || hp == NULL) &&
MAPADDRENABLED(flags)) {
struct hostent *hp2 = gethostbyname2(name, AF_INET);
if (hp == NULL)
if (hp2 == NULL)
*errp = statp->res_h_errno;
else
hp = _hpmapv6(hp2, errp);
else {
if (hp2 && strcmp(hp->h_name, hp2->h_name) == 0) {
struct hostent *hpb = hp;
hp = _hpmerge(hpb, hp2, errp);
freehostent(hpb);
}
}
}
#endif
if (hp == NULL)
*errp = statp->res_h_errno;
statp->options = options;
return _hpsort(hp, statp);
}
struct hostent *
getipnodebyaddr(const void *src, size_t len, int af, int *errp)
{
struct hostent *hp;
res_state statp;
u_long options;
#ifdef INET6
struct in6_addr addrbuf;
#else
struct in_addr addrbuf;
#endif
switch (af) {
case AF_INET:
if (len != sizeof(struct in_addr)) {
*errp = NO_RECOVERY;
return NULL;
}
if (rounddown2((long)src, sizeof(struct in_addr))) {
memcpy(&addrbuf, src, len);
src = &addrbuf;
}
if (((struct in_addr *)src)->s_addr == 0)
return NULL;
break;
#ifdef INET6
case AF_INET6:
if (len != sizeof(struct in6_addr)) {
*errp = NO_RECOVERY;
return NULL;
}
if (rounddown2((long)src, sizeof(struct in6_addr) / 2)) {
/* XXX */
memcpy(&addrbuf, src, len);
src = &addrbuf;
}
if (IN6_IS_ADDR_UNSPECIFIED((struct in6_addr *)src))
return NULL;
if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)src)
|| IN6_IS_ADDR_V4COMPAT((struct in6_addr *)src)) {
src = (char *)src +
(sizeof(struct in6_addr) - sizeof(struct in_addr));
af = AF_INET;
len = sizeof(struct in_addr);
}
break;
#endif
default:
*errp = NO_RECOVERY;
return NULL;
}
statp = __res_state();
if ((statp->options & RES_INIT) == 0) {
if (res_ninit(statp) < 0) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return NULL;
}
}
options = statp->options;
statp->options &= ~RES_USE_INET6;
hp = gethostbyaddr(src, len, af);
if (hp == NULL)
*errp = statp->res_h_errno;
statp->options = options;
return (_hpcopy(hp, errp));
}
void
freehostent(struct hostent *ptr)
{
free(ptr);
}
/*
* Private utility functions
*/
/*
* _hpcopy: allocate and copy hostent structure
*/
static struct hostent *
_hpcopy(struct hostent *hp, int *errp)
{
struct hostent *nhp;
char *cp, **pp;
int size, addrsize;
int nalias = 0, naddr = 0;
int al_off;
int i;
if (hp == NULL)
return hp;
/* count size to be allocated */
size = sizeof(struct hostent);
if (hp->h_name != NULL)
size += strlen(hp->h_name) + 1;
if ((pp = hp->h_aliases) != NULL) {
for (i = 0; *pp != NULL; i++, pp++) {
if (**pp != '\0') {
size += strlen(*pp) + 1;
nalias++;
}
}
}
/* adjust alignment */
size = ALIGN(size);
al_off = size;
size += sizeof(char *) * (nalias + 1);
addrsize = ALIGN(hp->h_length);
if ((pp = hp->h_addr_list) != NULL) {
while (*pp++ != NULL)
naddr++;
}
size += addrsize * naddr;
size += sizeof(char *) * (naddr + 1);
/* copy */
if ((nhp = (struct hostent *)malloc(size)) == NULL) {
*errp = TRY_AGAIN;
return NULL;
}
cp = (char *)&nhp[1];
if (hp->h_name != NULL) {
nhp->h_name = cp;
strcpy(cp, hp->h_name);
cp += strlen(cp) + 1;
} else
nhp->h_name = NULL;
nhp->h_aliases = (char **)((char *)nhp + al_off);
if ((pp = hp->h_aliases) != NULL) {
for (i = 0; *pp != NULL; pp++) {
if (**pp != '\0') {
nhp->h_aliases[i++] = cp;
strcpy(cp, *pp);
cp += strlen(cp) + 1;
}
}
}
nhp->h_aliases[nalias] = NULL;
cp = (char *)&nhp->h_aliases[nalias + 1];
nhp->h_addrtype = hp->h_addrtype;
nhp->h_length = hp->h_length;
nhp->h_addr_list = (char **)cp;
if ((pp = hp->h_addr_list) != NULL) {
cp = (char *)&nhp->h_addr_list[naddr + 1];
for (i = 0; *pp != NULL; pp++) {
nhp->h_addr_list[i++] = cp;
memcpy(cp, *pp, hp->h_length);
cp += addrsize;
}
}
nhp->h_addr_list[naddr] = NULL;
return nhp;
}
/*
* _hpaddr: construct hostent structure with one address
*/
static struct hostent *
_hpaddr(int af, const char *name, void *addr, int *errp)
{
struct hostent *hp, hpbuf;
char *addrs[2];
hp = &hpbuf;
hp->h_name = (char *)name;
hp->h_aliases = NULL;
hp->h_addrtype = af;
hp->h_length = ADDRLEN(af);
hp->h_addr_list = addrs;
addrs[0] = (char *)addr;
addrs[1] = NULL;
return (_hpcopy(hp, errp));
}
#ifdef INET6
/*
* _hpmerge: merge 2 hostent structure, arguments will be freed
*/
static struct hostent *
_hpmerge(struct hostent *hp1, struct hostent *hp2, int *errp)
{
int i, j;
int naddr, nalias;
char **pp;
struct hostent *hp, hpbuf;
char *aliases[MAXALIASES + 1], *addrs[MAXADDRS + 1];
union inx_addr addrbuf[MAXADDRS];
if (hp1 == NULL)
return _hpcopy(hp2, errp);
if (hp2 == NULL)
return _hpcopy(hp1, errp);
#define HP(i) (i == 1 ? hp1 : hp2)
hp = &hpbuf;
hp->h_name = (hp1->h_name != NULL ? hp1->h_name : hp2->h_name);
hp->h_aliases = aliases;
nalias = 0;
for (i = 1; i <= 2; i++) {
if ((pp = HP(i)->h_aliases) == NULL)
continue;
for (; nalias < MAXALIASES && *pp != NULL; pp++) {
/* check duplicates */
for (j = 0; j < nalias; j++)
if (strcasecmp(*pp, aliases[j]) == 0)
break;
if (j == nalias)
aliases[nalias++] = *pp;
}
}
aliases[nalias] = NULL;
if (hp1->h_length != hp2->h_length) {
hp->h_addrtype = AF_INET6;
hp->h_length = sizeof(struct in6_addr);
} else {
hp->h_addrtype = hp1->h_addrtype;
hp->h_length = hp1->h_length;
}
hp->h_addr_list = addrs;
naddr = 0;
for (i = 1; i <= 2; i++) {
if ((pp = HP(i)->h_addr_list) == NULL)
continue;
if (HP(i)->h_length == hp->h_length) {
while (naddr < MAXADDRS && *pp != NULL)
addrs[naddr++] = *pp++;
} else {
/* copy IPv4 addr as mapped IPv6 addr */
while (naddr < MAXADDRS && *pp != NULL) {
MAPADDR(&addrbuf[naddr], *pp++);
addrs[naddr] = (char *)&addrbuf[naddr];
naddr++;
}
}
}
addrs[naddr] = NULL;
return (_hpcopy(hp, errp));
}
#endif
/*
* _hpmapv6: convert IPv4 hostent into IPv4-mapped IPv6 addresses
*/
#ifdef INET6
static struct hostent *
_hpmapv6(struct hostent *hp, int *errp)
{
struct hostent hp6;
if (hp == NULL)
return NULL;
if (hp->h_addrtype == AF_INET6)
return _hpcopy(hp, errp);
memset(&hp6, 0, sizeof(struct hostent));
hp6.h_addrtype = AF_INET6;
hp6.h_length = sizeof(struct in6_addr);
return _hpmerge(&hp6, hp, errp);
}
#endif
/*
* _hpsort: sort address by sortlist
*/
static struct hostent *
_hpsort(struct hostent *hp, res_state statp)
{
int i, j, n;
u_char *ap, *sp, *mp, **pp;
char t;
char order[MAXADDRS];
int nsort = statp->nsort;
if (hp == NULL || hp->h_addr_list[1] == NULL || nsort == 0)
return hp;
for (i = 0; (ap = (u_char *)hp->h_addr_list[i]); i++) {
for (j = 0; j < nsort; j++) {
#ifdef INET6
if (statp->_u._ext.ext->sort_list[j].af !=
hp->h_addrtype)
continue;
sp = (u_char *)&statp->_u._ext.ext->sort_list[j].addr;
mp = (u_char *)&statp->_u._ext.ext->sort_list[j].mask;
#else
sp = (u_char *)&statp->sort_list[j].addr;
mp = (u_char *)&statp->sort_list[j].mask;
#endif
for (n = 0; n < hp->h_length; n++) {
if ((ap[n] & mp[n]) != sp[n])
break;
}
if (n == hp->h_length)
break;
}
order[i] = j;
}
n = i;
pp = (u_char **)hp->h_addr_list;
for (i = 0; i < n - 1; i++) {
for (j = i + 1; j < n; j++) {
if (order[i] > order[j]) {
ap = pp[i];
pp[i] = pp[j];
pp[j] = ap;
t = order[i];
order[i] = order[j];
order[j] = t;
}
}
}
return hp;
}
#ifdef INET6
/*
* _hpreorder: sort address by default address selection
*/
static struct hostent *
_hpreorder(struct hostent *hp)
{
struct hp_order *aio;
int i, n;
char *ap;
struct sockaddr *sa;
struct policyhead policyhead;
if (hp == NULL)
return hp;
switch (hp->h_addrtype) {
case AF_INET:
#ifdef INET6
case AF_INET6:
#endif
break;
default:
return hp;
}
/* count the number of addrinfo elements for sorting. */
for (n = 0; hp->h_addr_list[n] != NULL; n++)
;
/*
* If the number is small enough, we can skip the reordering process.
*/
if (n <= 1)
return hp;
/* allocate a temporary array for sort and initialization of it. */
if ((aio = malloc(sizeof(*aio) * n)) == NULL)
return hp; /* give up reordering */
memset(aio, 0, sizeof(*aio) * n);
/* retrieve address selection policy from the kernel */
TAILQ_INIT(&policyhead);
if (!get_addrselectpolicy(&policyhead)) {
/* no policy is installed into kernel, we don't sort. */
free(aio);
return hp;
}
for (i = 0; i < n; i++) {
ap = hp->h_addr_list[i];
aio[i].aio_h_addr = ap;
sa = &aio[i].aio_sa;
switch (hp->h_addrtype) {
case AF_INET:
sa->sa_family = AF_INET;
sa->sa_len = sizeof(struct sockaddr_in);
memcpy(&((struct sockaddr_in *)sa)->sin_addr, ap,
sizeof(struct in_addr));
break;
#ifdef INET6
case AF_INET6:
if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
sa->sa_family = AF_INET;
sa->sa_len = sizeof(struct sockaddr_in);
memcpy(&((struct sockaddr_in *)sa)->sin_addr,
&ap[12], sizeof(struct in_addr));
} else {
sa->sa_family = AF_INET6;
sa->sa_len = sizeof(struct sockaddr_in6);
memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr,
ap, sizeof(struct in6_addr));
}
break;
#endif
}
aio[i].aio_dstscope = gai_addr2scopetype(sa);
aio[i].aio_dstpolicy = match_addrselectpolicy(sa, &policyhead);
set_source(&aio[i], &policyhead);
aio[i].aio_initial_sequence = i;
}
/* perform sorting. */
qsort(aio, n, sizeof(*aio), comp_dst);
/* reorder the h_addr_list. */
for (i = 0; i < n; i++)
hp->h_addr_list[i] = aio[i].aio_h_addr;
/* cleanup and return */
free(aio);
free_addrselectpolicy(&policyhead);
return hp;
}
static int
get_addrselectpolicy(struct policyhead *head)
{
#ifdef INET6
int mib[] = { CTL_NET, PF_INET6, IPPROTO_IPV6, IPV6CTL_ADDRCTLPOLICY };
size_t l;
char *buf;
struct in6_addrpolicy *pol, *ep;
if (sysctl(mib, nitems(mib), NULL, &l, NULL, 0) < 0)
return (0);
if ((buf = malloc(l)) == NULL)
return (0);
if (sysctl(mib, nitems(mib), buf, &l, NULL, 0) < 0) {
free(buf);
return (0);
}
ep = (struct in6_addrpolicy *)(buf + l);
for (pol = (struct in6_addrpolicy *)buf; pol + 1 <= ep; pol++) {
struct policyqueue *new;
if ((new = malloc(sizeof(*new))) == NULL) {
free_addrselectpolicy(head); /* make the list empty */
break;
}
new->pc_policy = *pol;
TAILQ_INSERT_TAIL(head, new, pc_entry);
}
free(buf);
return (1);
#else
return (0);
#endif
}
static void
free_addrselectpolicy(struct policyhead *head)
{
struct policyqueue *ent, *nent;
for (ent = TAILQ_FIRST(head); ent; ent = nent) {
nent = TAILQ_NEXT(ent, pc_entry);
TAILQ_REMOVE(head, ent, pc_entry);
free(ent);
}
}
static struct policyqueue *
match_addrselectpolicy(struct sockaddr *addr, struct policyhead *head)
{
#ifdef INET6
struct policyqueue *ent, *bestent = NULL;
struct in6_addrpolicy *pol;
int matchlen, bestmatchlen = -1;
u_char *mp, *ep, *k, *p, m;
struct sockaddr_in6 key;
switch(addr->sa_family) {
case AF_INET6:
key = *(struct sockaddr_in6 *)addr;
break;
case AF_INET:
/* convert the address into IPv4-mapped IPv6 address. */
memset(&key, 0, sizeof(key));
key.sin6_family = AF_INET6;
key.sin6_len = sizeof(key);
_map_v4v6_address(
(char *)&((struct sockaddr_in *)addr)->sin_addr,
(char *)&key.sin6_addr);
break;
default:
return(NULL);
}
for (ent = TAILQ_FIRST(head); ent; ent = TAILQ_NEXT(ent, pc_entry)) {
pol = &ent->pc_policy;
matchlen = 0;
mp = (u_char *)&pol->addrmask.sin6_addr;
ep = mp + 16; /* XXX: scope field? */
k = (u_char *)&key.sin6_addr;
p = (u_char *)&pol->addr.sin6_addr;
for (; mp < ep && *mp; mp++, k++, p++) {
m = *mp;
if ((*k & m) != *p)
goto next; /* not match */
if (m == 0xff) /* short cut for a typical case */
matchlen += 8;
else {
while (m >= 0x80) {
matchlen++;
m <<= 1;
}
}
}
/* matched. check if this is better than the current best. */
if (matchlen > bestmatchlen) {
bestent = ent;
bestmatchlen = matchlen;
}
next:
continue;
}
return(bestent);
#else
return(NULL);
#endif
}
static void
set_source(struct hp_order *aio, struct policyhead *ph)
{
struct sockaddr_storage ss = aio->aio_un.aiou_ss;
socklen_t srclen;
int s;
/* set unspec ("no source is available"), just in case */
aio->aio_srcsa.sa_family = AF_UNSPEC;
aio->aio_srcscope = -1;
switch(ss.ss_family) {
case AF_INET:
((struct sockaddr_in *)&ss)->sin_port = htons(1);
break;
#ifdef INET6
case AF_INET6:
((struct sockaddr_in6 *)&ss)->sin6_port = htons(1);
break;
#endif
default: /* ignore unsupported AFs explicitly */
return;
}
/* open a socket to get the source address for the given dst */
if ((s = _socket(ss.ss_family, SOCK_DGRAM | SOCK_CLOEXEC,
IPPROTO_UDP)) < 0)
return; /* give up */
if (_connect(s, (struct sockaddr *)&ss, ss.ss_len) < 0)
goto cleanup;
srclen = ss.ss_len;
if (_getsockname(s, &aio->aio_srcsa, &srclen) < 0) {
aio->aio_srcsa.sa_family = AF_UNSPEC;
goto cleanup;
}
aio->aio_srcscope = gai_addr2scopetype(&aio->aio_srcsa);
aio->aio_srcpolicy = match_addrselectpolicy(&aio->aio_srcsa, ph);
aio->aio_matchlen = matchlen(&aio->aio_srcsa, (struct sockaddr *)&ss);
#ifdef INET6
if (ss.ss_family == AF_INET6) {
struct in6_ifreq ifr6;
u_int32_t flags6;
memset(&ifr6, 0, sizeof(ifr6));
memcpy(&ifr6.ifr_addr, &ss, ss.ss_len);
if (_ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == 0) {
flags6 = ifr6.ifr_ifru.ifru_flags6;
if ((flags6 & IN6_IFF_DEPRECATED))
aio->aio_srcflag |= AIO_SRCFLAG_DEPRECATED;
}
}
#endif
cleanup:
_close(s);
return;
}
static int
matchlen(struct sockaddr *src, struct sockaddr *dst)
{
int match = 0;
u_char *s, *d;
u_char *lim, r;
int addrlen;
switch (src->sa_family) {
#ifdef INET6
case AF_INET6:
s = (u_char *)&((struct sockaddr_in6 *)src)->sin6_addr;
d = (u_char *)&((struct sockaddr_in6 *)dst)->sin6_addr;
addrlen = sizeof(struct in6_addr);
lim = s + addrlen;
break;
#endif
case AF_INET:
s = (u_char *)&((struct sockaddr_in *)src)->sin_addr;
d = (u_char *)&((struct sockaddr_in *)dst)->sin_addr;
addrlen = sizeof(struct in_addr);
lim = s + addrlen;
break;
default:
return(0);
}
while (s < lim)
if ((r = (*d++ ^ *s++)) != 0) {
while ((r & 0x80) == 0) {
match++;
r <<= 1;
}
break;
} else
match += 8;
return(match);
}
static int
comp_dst(const void *arg1, const void *arg2)
{
const struct hp_order *dst1 = arg1, *dst2 = arg2;
/*
* Rule 1: Avoid unusable destinations.
* XXX: we currently do not consider if an appropriate route exists.
*/
if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
dst2->aio_srcsa.sa_family == AF_UNSPEC) {
return(-1);
}
if (dst1->aio_srcsa.sa_family == AF_UNSPEC &&
dst2->aio_srcsa.sa_family != AF_UNSPEC) {
return(1);
}
/* Rule 2: Prefer matching scope. */
if (dst1->aio_dstscope == dst1->aio_srcscope &&
dst2->aio_dstscope != dst2->aio_srcscope) {
return(-1);
}
if (dst1->aio_dstscope != dst1->aio_srcscope &&
dst2->aio_dstscope == dst2->aio_srcscope) {
return(1);
}
/* Rule 3: Avoid deprecated addresses. */
if (dst1->aio_srcsa.sa_family != AF_UNSPEC &&
dst2->aio_srcsa.sa_family != AF_UNSPEC) {
if (!(dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
return(-1);
}
if ((dst1->aio_srcflag & AIO_SRCFLAG_DEPRECATED) &&
!(dst2->aio_srcflag & AIO_SRCFLAG_DEPRECATED)) {
return(1);
}
}
/* Rule 4: Prefer home addresses. */
/* XXX: not implemented yet */
/* Rule 5: Prefer matching label. */
#ifdef INET6
if (dst1->aio_srcpolicy && dst1->aio_dstpolicy &&
dst1->aio_srcpolicy->pc_policy.label ==
dst1->aio_dstpolicy->pc_policy.label &&
(dst2->aio_srcpolicy == NULL || dst2->aio_dstpolicy == NULL ||
dst2->aio_srcpolicy->pc_policy.label !=
dst2->aio_dstpolicy->pc_policy.label)) {
return(-1);
}
if (dst2->aio_srcpolicy && dst2->aio_dstpolicy &&
dst2->aio_srcpolicy->pc_policy.label ==
dst2->aio_dstpolicy->pc_policy.label &&
(dst1->aio_srcpolicy == NULL || dst1->aio_dstpolicy == NULL ||
dst1->aio_srcpolicy->pc_policy.label !=
dst1->aio_dstpolicy->pc_policy.label)) {
return(1);
}
#endif
/* Rule 6: Prefer higher precedence. */
#ifdef INET6
if (dst1->aio_dstpolicy &&
(dst2->aio_dstpolicy == NULL ||
dst1->aio_dstpolicy->pc_policy.preced >
dst2->aio_dstpolicy->pc_policy.preced)) {
return(-1);
}
if (dst2->aio_dstpolicy &&
(dst1->aio_dstpolicy == NULL ||
dst2->aio_dstpolicy->pc_policy.preced >
dst1->aio_dstpolicy->pc_policy.preced)) {
return(1);
}
#endif
/* Rule 7: Prefer native transport. */
/* XXX: not implemented yet */
/* Rule 8: Prefer smaller scope. */
if (dst1->aio_dstscope >= 0 &&
dst1->aio_dstscope < dst2->aio_dstscope) {
return(-1);
}
if (dst2->aio_dstscope >= 0 &&
dst2->aio_dstscope < dst1->aio_dstscope) {
return(1);
}
/*
* Rule 9: Use longest matching prefix.
* We compare the match length in a same AF only.
*/
if (dst1->aio_sa.sa_family == dst2->aio_sa.sa_family) {
if (dst1->aio_matchlen > dst2->aio_matchlen) {
return(-1);
}
if (dst1->aio_matchlen < dst2->aio_matchlen) {
return(1);
}
}
/* Rule 10: Otherwise, leave the order unchanged. */
/*
* Note that qsort is unstable; so, we can't return zero and
* expect the order to be unchanged.
* That also means we can't depend on the current position of
* dst2 being after dst1. We must enforce the initial order
* with an explicit compare on the original position.
* The qsort specification requires that "When the same objects
* (consisting of width bytes, irrespective of their current
* positions in the array) are passed more than once to the
* comparison function, the results shall be consistent with one
* another."
* In other words, If A < B, then we must also return B > A.
*/
if (dst2->aio_initial_sequence < dst1->aio_initial_sequence)
return(1);
return(-1);
}
/*
* Copy from scope.c.
* XXX: we should standardize the functions and link them as standard
* library.
*/
static int
gai_addr2scopetype(struct sockaddr *sa)
{
#ifdef INET6
struct sockaddr_in6 *sa6;
#endif
struct sockaddr_in *sa4;
switch(sa->sa_family) {
#ifdef INET6
case AF_INET6:
sa6 = (struct sockaddr_in6 *)sa;
if (IN6_IS_ADDR_MULTICAST(&sa6->sin6_addr)) {
/* just use the scope field of the multicast address */
return(sa6->sin6_addr.s6_addr[2] & 0x0f);
}
/*
* Unicast addresses: map scope type to corresponding scope
* value defined for multcast addresses.
* XXX: hardcoded scope type values are bad...
*/
if (IN6_IS_ADDR_LOOPBACK(&sa6->sin6_addr))
return(1); /* node local scope */
if (IN6_IS_ADDR_LINKLOCAL(&sa6->sin6_addr))
return(2); /* link-local scope */
if (IN6_IS_ADDR_SITELOCAL(&sa6->sin6_addr))
return(5); /* site-local scope */
return(14); /* global scope */
break;
#endif
case AF_INET:
/*
* IPv4 pseudo scoping according to RFC 3484.
*/
sa4 = (struct sockaddr_in *)sa;
/* IPv4 autoconfiguration addresses have link-local scope. */
if (((u_char *)&sa4->sin_addr)[0] == 169 &&
((u_char *)&sa4->sin_addr)[1] == 254)
return(2);
/* Private addresses have site-local scope. */
if (((u_char *)&sa4->sin_addr)[0] == 10 ||
(((u_char *)&sa4->sin_addr)[0] == 172 &&
(((u_char *)&sa4->sin_addr)[1] & 0xf0) == 16) ||
(((u_char *)&sa4->sin_addr)[0] == 192 &&
((u_char *)&sa4->sin_addr)[1] == 168))
return(14); /* XXX: It should be 5 unless NAT */
/* Loopback addresses have link-local scope. */
if (((u_char *)&sa4->sin_addr)[0] == 127)
return(2);
return(14);
break;
default:
errno = EAFNOSUPPORT; /* is this a good error? */
return(-1);
}
}
#endif
diff --git a/lib/libc/net/nscache.c b/lib/libc/net/nscache.c
index 0814818aa210..3537d77edbbe 100644
--- a/lib/libc/net/nscache.c
+++ b/lib/libc/net/nscache.c
@@ -1,439 +1,438 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#define _NS_PRIVATE
#include <nsswitch.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#include "nscachedcli.h"
#include "nscache.h"
#define NSS_CACHE_KEY_INITIAL_SIZE (256)
#define NSS_CACHE_KEY_SIZE_LIMIT (NSS_CACHE_KEY_INITIAL_SIZE << 4)
#define NSS_CACHE_BUFFER_INITIAL_SIZE (1024)
#define NSS_CACHE_BUFFER_SIZE_LIMIT (NSS_CACHE_BUFFER_INITIAL_SIZE << 8)
#define CACHED_SOCKET_PATH "/var/run/nscd"
int
__nss_cache_handler(void *retval, void *mdata, va_list ap)
{
return (NS_UNAVAIL);
}
int
__nss_common_cache_read(void *retval, void *mdata, va_list ap)
{
struct cached_connection_params params;
cached_connection connection;
char *buffer;
size_t buffer_size, size;
nss_cache_info const *cache_info;
nss_cache_data *cache_data;
va_list ap_new;
int res;
cache_data = (nss_cache_data *)mdata;
cache_info = cache_data->info;
memset(&params, 0, sizeof(struct cached_connection_params));
params.socket_path = CACHED_SOCKET_PATH;
cache_data->key = (char *)malloc(NSS_CACHE_KEY_INITIAL_SIZE);
memset(cache_data->key, 0, NSS_CACHE_KEY_INITIAL_SIZE);
cache_data->key_size = NSS_CACHE_KEY_INITIAL_SIZE;
va_copy(ap_new, ap);
do {
size = cache_data->key_size;
res = cache_info->id_func(cache_data->key, &size, ap_new,
cache_info->mdata);
va_end(ap_new);
if (res == NS_RETURN) {
if (cache_data->key_size > NSS_CACHE_KEY_SIZE_LIMIT)
break;
cache_data->key_size <<= 1;
cache_data->key = realloc(cache_data->key,
cache_data->key_size);
memset(cache_data->key, 0, cache_data->key_size);
va_copy(ap_new, ap);
}
} while (res == NS_RETURN);
if (res != NS_SUCCESS) {
free(cache_data->key);
cache_data->key = NULL;
cache_data->key_size = 0;
return (res);
} else
cache_data->key_size = size;
buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
do {
connection = __open_cached_connection(&params);
if (connection == NULL) {
res = -1;
break;
}
res = __cached_read(connection, cache_info->entry_name,
cache_data->key, cache_data->key_size, buffer,
&buffer_size);
__close_cached_connection(connection);
if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
buffer = (char *)realloc(buffer, buffer_size);
memset(buffer, 0, buffer_size);
}
} while (res == -2);
if (res == 0) {
if (buffer_size == 0) {
free(buffer);
free(cache_data->key);
cache_data->key = NULL;
cache_data->key_size = 0;
return (NS_RETURN);
}
va_copy(ap_new, ap);
res = cache_info->unmarshal_func(buffer, buffer_size, retval,
ap_new, cache_info->mdata);
va_end(ap_new);
if (res != NS_SUCCESS) {
free(buffer);
free(cache_data->key);
cache_data->key = NULL;
cache_data->key_size = 0;
return (res);
} else
res = 0;
}
if (res == 0) {
free(cache_data->key);
cache_data->key = NULL;
cache_data->key_size = 0;
}
free(buffer);
return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
}
int
__nss_common_cache_write(void *retval, void *mdata, va_list ap)
{
struct cached_connection_params params;
cached_connection connection;
char *buffer;
size_t buffer_size;
nss_cache_info const *cache_info;
nss_cache_data *cache_data;
va_list ap_new;
int res;
cache_data = (nss_cache_data *)mdata;
cache_info = cache_data->info;
if (cache_data->key == NULL)
return (NS_UNAVAIL);
memset(&params, 0, sizeof(struct cached_connection_params));
params.socket_path = CACHED_SOCKET_PATH;
connection = __open_cached_connection(&params);
if (connection == NULL) {
free(cache_data->key);
return (NS_UNAVAIL);
}
buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
do {
size_t size;
size = buffer_size;
va_copy(ap_new, ap);
res = cache_info->marshal_func(buffer, &size, retval, ap_new,
cache_info->mdata);
va_end(ap_new);
if (res == NS_RETURN) {
if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
break;
buffer_size <<= 1;
buffer = (char *)realloc(buffer, buffer_size);
memset(buffer, 0, buffer_size);
}
} while (res == NS_RETURN);
if (res != NS_SUCCESS) {
__close_cached_connection(connection);
free(cache_data->key);
free(buffer);
return (res);
}
res = __cached_write(connection, cache_info->entry_name,
cache_data->key, cache_data->key_size, buffer, buffer_size);
__close_cached_connection(connection);
free(cache_data->key);
free(buffer);
return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
}
int
__nss_common_cache_write_negative(void *mdata)
{
struct cached_connection_params params;
cached_connection connection;
int res;
nss_cache_info const *cache_info;
nss_cache_data *cache_data;
cache_data = (nss_cache_data *)mdata;
cache_info = cache_data->info;
if (cache_data->key == NULL)
return (NS_UNAVAIL);
memset(&params, 0, sizeof(struct cached_connection_params));
params.socket_path = CACHED_SOCKET_PATH;
connection = __open_cached_connection(&params);
if (connection == NULL) {
free(cache_data->key);
return (NS_UNAVAIL);
}
res = __cached_write(connection, cache_info->entry_name,
cache_data->key, cache_data->key_size, NULL, 0);
__close_cached_connection(connection);
free(cache_data->key);
return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
}
int
__nss_mp_cache_read(void *retval, void *mdata, va_list ap)
{
struct cached_connection_params params;
cached_mp_read_session rs;
char *buffer;
size_t buffer_size;
nss_cache_info const *cache_info;
nss_cache_data *cache_data;
va_list ap_new;
int res;
cache_data = (nss_cache_data *)mdata;
cache_info = cache_data->info;
if (cache_info->get_mp_ws_func() != INVALID_CACHED_MP_WRITE_SESSION)
return (NS_UNAVAIL);
rs = cache_info->get_mp_rs_func();
if (rs == INVALID_CACHED_MP_READ_SESSION) {
memset(&params, 0, sizeof(struct cached_connection_params));
params.socket_path = CACHED_SOCKET_PATH;
rs = __open_cached_mp_read_session(&params,
cache_info->entry_name);
if (rs == INVALID_CACHED_MP_READ_SESSION)
return (NS_UNAVAIL);
cache_info->set_mp_rs_func(rs);
}
buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
do {
res = __cached_mp_read(rs, buffer, &buffer_size);
if (res == -2 && buffer_size < NSS_CACHE_BUFFER_SIZE_LIMIT) {
buffer = (char *)realloc(buffer, buffer_size);
memset(buffer, 0, buffer_size);
}
} while (res == -2);
if (res == 0) {
va_copy(ap_new, ap);
res = cache_info->unmarshal_func(buffer, buffer_size, retval,
ap_new, cache_info->mdata);
va_end(ap_new);
if (res != NS_SUCCESS) {
free(buffer);
return (res);
} else
res = 0;
} else {
free(buffer);
__close_cached_mp_read_session(rs);
rs = INVALID_CACHED_MP_READ_SESSION;
cache_info->set_mp_rs_func(rs);
return (res == -1 ? NS_RETURN : NS_UNAVAIL);
}
free(buffer);
return (res == 0 ? NS_SUCCESS : NS_NOTFOUND);
}
int
__nss_mp_cache_write(void *retval, void *mdata, va_list ap)
{
struct cached_connection_params params;
cached_mp_write_session ws;
char *buffer;
size_t buffer_size;
nss_cache_info const *cache_info;
nss_cache_data *cache_data;
va_list ap_new;
int res;
cache_data = (nss_cache_data *)mdata;
cache_info = cache_data->info;
ws = cache_info->get_mp_ws_func();
if (ws == INVALID_CACHED_MP_WRITE_SESSION) {
memset(&params, 0, sizeof(struct cached_connection_params));
params.socket_path = CACHED_SOCKET_PATH;
ws = __open_cached_mp_write_session(&params,
cache_info->entry_name);
if (ws == INVALID_CACHED_MP_WRITE_SESSION)
return (NS_UNAVAIL);
cache_info->set_mp_ws_func(ws);
}
buffer_size = NSS_CACHE_BUFFER_INITIAL_SIZE;
buffer = (char *)malloc(NSS_CACHE_BUFFER_INITIAL_SIZE);
memset(buffer, 0, NSS_CACHE_BUFFER_INITIAL_SIZE);
do {
size_t size;
size = buffer_size;
va_copy(ap_new, ap);
res = cache_info->marshal_func(buffer, &size, retval, ap_new,
cache_info->mdata);
va_end(ap_new);
if (res == NS_RETURN) {
if (buffer_size > NSS_CACHE_BUFFER_SIZE_LIMIT)
break;
buffer_size <<= 1;
buffer = (char *)realloc(buffer, buffer_size);
memset(buffer, 0, buffer_size);
}
} while (res == NS_RETURN);
if (res != NS_SUCCESS) {
free(buffer);
return (res);
}
res = __cached_mp_write(ws, buffer, buffer_size);
free(buffer);
return (res == 0 ? NS_SUCCESS : NS_UNAVAIL);
}
int
__nss_mp_cache_write_submit(void *retval, void *mdata, va_list ap)
{
cached_mp_write_session ws;
nss_cache_info const *cache_info;
nss_cache_data *cache_data;
cache_data = (nss_cache_data *)mdata;
cache_info = cache_data->info;
ws = cache_info->get_mp_ws_func();
if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
__close_cached_mp_write_session(ws);
ws = INVALID_CACHED_MP_WRITE_SESSION;
cache_info->set_mp_ws_func(ws);
}
return (NS_UNAVAIL);
}
int
__nss_mp_cache_end(void *retval, void *mdata, va_list ap)
{
cached_mp_write_session ws;
cached_mp_read_session rs;
nss_cache_info const *cache_info;
nss_cache_data *cache_data;
cache_data = (nss_cache_data *)mdata;
cache_info = cache_data->info;
ws = cache_info->get_mp_ws_func();
if (ws != INVALID_CACHED_MP_WRITE_SESSION) {
__abandon_cached_mp_write_session(ws);
ws = INVALID_CACHED_MP_WRITE_SESSION;
cache_info->set_mp_ws_func(ws);
}
rs = cache_info->get_mp_rs_func();
if (rs != INVALID_CACHED_MP_READ_SESSION) {
__close_cached_mp_read_session(rs);
rs = INVALID_CACHED_MP_READ_SESSION;
cache_info->set_mp_rs_func(rs);
}
return (NS_UNAVAIL);
}
diff --git a/lib/libc/net/nscachedcli.c b/lib/libc/net/nscachedcli.c
index 55b0b97129f5..f57e69bdceb2 100644
--- a/lib/libc/net/nscachedcli.c
+++ b/lib/libc/net/nscachedcli.c
@@ -1,573 +1,572 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Michael Bushkov <bushman@rsu.ru>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/event.h>
#include <sys/uio.h>
#include <sys/un.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "nscachedcli.h"
#define NS_DEFAULT_CACHED_IO_TIMEOUT 4
static int safe_write(struct cached_connection_ *, const void *, size_t);
static int safe_read(struct cached_connection_ *, void *, size_t);
static int send_credentials(struct cached_connection_ *, int);
/*
* safe_write writes data to the specified connection and tries to do it in
* the very safe manner. We ensure, that we can write to the socket with
* kevent. If the data_size can't be sent in one piece, then it would be
* splitted.
*/
static int
safe_write(struct cached_connection_ *connection, const void *data,
size_t data_size)
{
struct kevent eventlist;
int nevents;
size_t result;
ssize_t s_result;
struct timespec timeout;
if (data_size == 0)
return (0);
timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
timeout.tv_nsec = 0;
result = 0;
do {
nevents = _kevent(connection->write_queue, NULL, 0, &eventlist,
1, &timeout);
if ((nevents == 1) && (eventlist.filter == EVFILT_WRITE)) {
s_result = _sendto(connection->sockfd, data + result,
eventlist.data < data_size - result ?
eventlist.data : data_size - result, MSG_NOSIGNAL,
NULL, 0);
if (s_result == -1)
return (-1);
else
result += s_result;
if (eventlist.flags & EV_EOF)
return (result < data_size ? -1 : 0);
} else
return (-1);
} while (result < data_size);
return (0);
}
/*
* safe_read reads data from connection and tries to do it in the very safe
* and stable way. It uses kevent to ensure, that the data are available for
* reading. If the amount of data to be read is too large, then they would
* be splitted.
*/
static int
safe_read(struct cached_connection_ *connection, void *data, size_t data_size)
{
struct kevent eventlist;
size_t result;
ssize_t s_result;
struct timespec timeout;
int nevents;
if (data_size == 0)
return (0);
timeout.tv_sec = NS_DEFAULT_CACHED_IO_TIMEOUT;
timeout.tv_nsec = 0;
result = 0;
do {
nevents = _kevent(connection->read_queue, NULL, 0, &eventlist,
1, &timeout);
if (nevents == 1 && eventlist.filter == EVFILT_READ) {
s_result = _read(connection->sockfd, data + result,
eventlist.data <= data_size - result ?
eventlist.data : data_size - result);
if (s_result == -1)
return (-1);
else
result += s_result;
if (eventlist.flags & EV_EOF)
return (result < data_size ? -1 : 0);
} else
return (-1);
} while (result < data_size);
return (0);
}
/*
* Sends the credentials information to the connection along with the
* communication element type.
*/
static int
send_credentials(struct cached_connection_ *connection, int type)
{
union {
struct cmsghdr hdr;
char pad[CMSG_SPACE(sizeof(struct cmsgcred))];
} cmsg;
struct msghdr mhdr;
struct iovec iov;
struct kevent eventlist;
int nevents;
ssize_t result;
memset(&cmsg, 0, sizeof(cmsg));
cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
cmsg.hdr.cmsg_level = SOL_SOCKET;
cmsg.hdr.cmsg_type = SCM_CREDS;
memset(&mhdr, 0, sizeof(mhdr));
mhdr.msg_iov = &iov;
mhdr.msg_iovlen = 1;
mhdr.msg_control = &cmsg;
mhdr.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
iov.iov_base = &type;
iov.iov_len = sizeof(int);
EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
NOTE_LOWAT, sizeof(int), NULL);
(void)_kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
nevents = _kevent(connection->write_queue, NULL, 0, &eventlist, 1,
NULL);
if (nevents == 1 && eventlist.filter == EVFILT_WRITE) {
result = _sendmsg(connection->sockfd, &mhdr,
MSG_NOSIGNAL) == -1 ? -1 : 0;
EV_SET(&eventlist, connection->sockfd, EVFILT_WRITE, EV_ADD,
0, 0, NULL);
_kevent(connection->write_queue, &eventlist, 1, NULL, 0, NULL);
return (result);
} else
return (-1);
}
/*
* Opens the connection with the specified params. Initializes all kqueues.
*/
struct cached_connection_ *
__open_cached_connection(struct cached_connection_params const *params)
{
struct cached_connection_ *retval;
struct kevent eventlist;
struct sockaddr_un client_address;
int client_address_len, client_socket;
int res;
assert(params != NULL);
client_socket = _socket(PF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
client_address.sun_family = PF_LOCAL;
strncpy(client_address.sun_path, params->socket_path,
sizeof(client_address.sun_path));
client_address_len = sizeof(client_address.sun_family) +
strlen(client_address.sun_path) + 1;
res = _connect(client_socket, (struct sockaddr *)&client_address,
client_address_len);
if (res == -1) {
_close(client_socket);
return (NULL);
}
_fcntl(client_socket, F_SETFL, O_NONBLOCK);
retval = malloc(sizeof(struct cached_connection_));
assert(retval != NULL);
memset(retval, 0, sizeof(struct cached_connection_));
retval->sockfd = client_socket;
retval->write_queue = kqueue();
assert(retval->write_queue != -1);
EV_SET(&eventlist, retval->sockfd, EVFILT_WRITE, EV_ADD, 0, 0, NULL);
res = _kevent(retval->write_queue, &eventlist, 1, NULL, 0, NULL);
retval->read_queue = kqueue();
assert(retval->read_queue != -1);
EV_SET(&eventlist, retval->sockfd, EVFILT_READ, EV_ADD, 0, 0, NULL);
res = _kevent(retval->read_queue, &eventlist, 1, NULL, 0, NULL);
return (retval);
}
void
__close_cached_connection(struct cached_connection_ *connection)
{
assert(connection != NULL);
_close(connection->sockfd);
_close(connection->read_queue);
_close(connection->write_queue);
free(connection);
}
/*
* This function is very close to the cache_write function of the caching
* library, which is used in the caching daemon. It caches the data with the
* specified key in the cache entry with entry_name.
*/
int
__cached_write(struct cached_connection_ *connection, const char *entry_name,
const char *key, size_t key_size, const char *data, size_t data_size)
{
size_t name_size;
int error_code;
int result;
error_code = -1;
result = 0;
result = send_credentials(connection, CET_WRITE_REQUEST);
if (result != 0)
goto fin;
name_size = strlen(entry_name);
result = safe_write(connection, &name_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(connection, &key_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(connection, &data_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(connection, entry_name, name_size);
if (result != 0)
goto fin;
result = safe_write(connection, key, key_size);
if (result != 0)
goto fin;
result = safe_write(connection, data, data_size);
if (result != 0)
goto fin;
result = safe_read(connection, &error_code, sizeof(int));
if (result != 0)
error_code = -1;
fin:
return (error_code);
}
/*
* This function is very close to the cache_read function of the caching
* library, which is used in the caching daemon. It reads cached data with the
* specified key from the cache entry with entry_name.
*/
int
__cached_read(struct cached_connection_ *connection, const char *entry_name,
const char *key, size_t key_size, char *data, size_t *data_size)
{
size_t name_size, result_size;
int error_code, rec_error_code;
int result;
assert(connection != NULL);
result = 0;
error_code = -1;
result = send_credentials(connection, CET_READ_REQUEST);
if (result != 0)
goto fin;
name_size = strlen(entry_name);
result = safe_write(connection, &name_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(connection, &key_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(connection, entry_name, name_size);
if (result != 0)
goto fin;
result = safe_write(connection, key, key_size);
if (result != 0)
goto fin;
result = safe_read(connection, &rec_error_code, sizeof(int));
if (result != 0)
goto fin;
if (rec_error_code != 0) {
error_code = rec_error_code;
goto fin;
}
result = safe_read(connection, &result_size, sizeof(size_t));
if (result != 0)
goto fin;
if (result_size > *data_size) {
*data_size = result_size;
error_code = -2;
goto fin;
}
result = safe_read(connection, data, result_size);
if (result != 0)
goto fin;
*data_size = result_size;
error_code = 0;
fin:
return (error_code);
}
/*
* Initializes the mp_write_session. For such a session the new connection
* would be opened. The data should be written to the session with
* __cached_mp_write function. The __close_cached_mp_write_session function
* should be used to submit session and __abandon_cached_mp_write_session - to
* abandon it. When the session is submitted, the whole se
*/
struct cached_connection_ *
__open_cached_mp_write_session(struct cached_connection_params const *params,
const char *entry_name)
{
struct cached_connection_ *connection, *retval;
size_t name_size;
int error_code;
int result;
retval = NULL;
connection = __open_cached_connection(params);
if (connection == NULL)
return (NULL);
connection->mp_flag = 1;
result = send_credentials(connection, CET_MP_WRITE_SESSION_REQUEST);
if (result != 0)
goto fin;
name_size = strlen(entry_name);
result = safe_write(connection, &name_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(connection, entry_name, name_size);
if (result != 0)
goto fin;
result = safe_read(connection, &error_code, sizeof(int));
if (result != 0)
goto fin;
if (error_code != 0)
result = error_code;
fin:
if (result != 0)
__close_cached_connection(connection);
else
retval = connection;
return (retval);
}
/*
* Adds new portion of data to the opened write session
*/
int
__cached_mp_write(struct cached_connection_ *ws, const char *data,
size_t data_size)
{
int request, result;
int error_code;
error_code = -1;
request = CET_MP_WRITE_SESSION_WRITE_REQUEST;
result = safe_write(ws, &request, sizeof(int));
if (result != 0)
goto fin;
result = safe_write(ws, &data_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(ws, data, data_size);
if (result != 0)
goto fin;
result = safe_read(ws, &error_code, sizeof(int));
if (result != 0)
error_code = -1;
fin:
return (error_code);
}
/*
* Abandons all operations with the write session. All data, that were written
* to the session before, are discarded.
*/
int
__abandon_cached_mp_write_session(struct cached_connection_ *ws)
{
int notification;
int result;
notification = CET_MP_WRITE_SESSION_ABANDON_NOTIFICATION;
result = safe_write(ws, &notification, sizeof(int));
__close_cached_connection(ws);
return (result);
}
/*
* Gracefully closes the write session. The data, that were previously written
* to the session, are committed.
*/
int
__close_cached_mp_write_session(struct cached_connection_ *ws)
{
int notification;
notification = CET_MP_WRITE_SESSION_CLOSE_NOTIFICATION;
(void)safe_write(ws, &notification, sizeof(int));
__close_cached_connection(ws);
return (0);
}
struct cached_connection_ *
__open_cached_mp_read_session(struct cached_connection_params const *params,
const char *entry_name)
{
struct cached_connection_ *connection, *retval;
size_t name_size;
int error_code;
int result;
retval = NULL;
connection = __open_cached_connection(params);
if (connection == NULL)
return (NULL);
connection->mp_flag = 1;
result = send_credentials(connection, CET_MP_READ_SESSION_REQUEST);
if (result != 0)
goto fin;
name_size = strlen(entry_name);
result = safe_write(connection, &name_size, sizeof(size_t));
if (result != 0)
goto fin;
result = safe_write(connection, entry_name, name_size);
if (result != 0)
goto fin;
result = safe_read(connection, &error_code, sizeof(int));
if (result != 0)
goto fin;
if (error_code != 0)
result = error_code;
fin:
if (result != 0)
__close_cached_connection(connection);
else
retval = connection;
return (retval);
}
int
__cached_mp_read(struct cached_connection_ *rs, char *data, size_t *data_size)
{
size_t result_size;
int error_code, rec_error_code;
int request, result;
error_code = -1;
request = CET_MP_READ_SESSION_READ_REQUEST;
result = safe_write(rs, &request, sizeof(int));
if (result != 0)
goto fin;
result = safe_read(rs, &rec_error_code, sizeof(int));
if (result != 0)
goto fin;
if (rec_error_code != 0) {
error_code = rec_error_code;
goto fin;
}
result = safe_read(rs, &result_size, sizeof(size_t));
if (result != 0)
goto fin;
if (result_size > *data_size) {
*data_size = result_size;
error_code = -2;
goto fin;
}
result = safe_read(rs, data, result_size);
if (result != 0)
goto fin;
*data_size = result_size;
error_code = 0;
fin:
return (error_code);
}
int
__close_cached_mp_read_session(struct cached_connection_ *rs)
{
__close_cached_connection(rs);
return (0);
}
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
index 958bd2ed69b0..60baa0014904 100644
--- a/lib/libc/net/nsdispatch.c
+++ b/lib/libc/net/nsdispatch.c
@@ -1,783 +1,782 @@
/* $NetBSD: nsdispatch.c,v 1.9 1999/01/25 00:16:17 lukem Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*-
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* Portions of this software were developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#define _NS_PRIVATE
#include <nsswitch.h>
#include <pthread.h>
#include <pthread_np.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "un-namespace.h"
#include "nss_tls.h"
#include "libc_private.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
enum _nss_constants {
/* Number of elements allocated when we grow a vector */
ELEMSPERCHUNK = 8
};
/*
* Global NSS data structures are mostly read-only, but we update
* them when we read or re-read the nsswitch.conf.
*/
static pthread_rwlock_t nss_lock = PTHREAD_RWLOCK_INITIALIZER;
/*
* Runtime determination of whether we are dynamically linked or not.
*/
extern int _DYNAMIC __attribute__ ((weak));
#define is_dynamic() (&_DYNAMIC != NULL)
/*
* default sourcelist: `files'
*/
const ns_src __nsdefaultsrc[] = {
{ NSSRC_FILES, NS_SUCCESS },
{ 0 },
};
/* Database, source mappings. */
static unsigned int _nsmapsize;
static ns_dbt *_nsmap = NULL;
/* NSS modules. */
static unsigned int _nsmodsize;
static ns_mod *_nsmod;
/* Placeholder for builtin modules' dlopen `handle'. */
static int __nss_builtin_handle;
static void *nss_builtin_handle = &__nss_builtin_handle;
#ifdef NS_CACHING
/*
* Cache lookup cycle prevention function - if !NULL then no cache lookups
* will be made
*/
static void *nss_cache_cycle_prevention_func = NULL;
#endif
/*
* We keep track of nsdispatch() nesting depth in dispatch_depth. When a
* fallback method is invoked from nsdispatch(), we temporarily set
* fallback_depth to the current dispatch depth plus one. Subsequent
* calls at that exact depth will run in fallback mode (restricted to the
* same source as the call that was handled by the fallback method), while
* calls below that depth will be handled normally, allowing fallback
* methods to perform arbitrary lookups.
*/
struct fb_state {
int dispatch_depth;
int fallback_depth;
};
static void fb_endstate(void *);
NSS_TLS_HANDLING(fb);
/*
* Attempt to spew relatively uniform messages to syslog.
*/
#define nss_log(level, fmt, ...) \
syslog((level), "NSSWITCH(%s): " fmt, __func__, __VA_ARGS__)
#define nss_log_simple(level, s) \
syslog((level), "NSSWITCH(%s): " s, __func__)
/*
* Dynamically growable arrays are used for lists of databases, sources,
* and modules. The following `vector' interface is used to isolate the
* common operations.
*/
typedef int (*vector_comparison)(const void *, const void *);
typedef void (*vector_free_elem)(void *);
static void vector_sort(void *, unsigned int, size_t,
vector_comparison);
static void vector_free(void *, unsigned int *, size_t,
vector_free_elem);
static void *vector_ref(unsigned int, void *, unsigned int, size_t);
static void *vector_search(const void *, void *, unsigned int, size_t,
vector_comparison);
static void *vector_append(const void *, void *, unsigned int *, size_t);
/*
* Internal interfaces.
*/
static int string_compare(const void *, const void *);
static int mtab_compare(const void *, const void *);
static int nss_configure(void);
static void ns_dbt_free(ns_dbt *);
static void ns_mod_free(ns_mod *);
static void ns_src_free(ns_src **, int);
static void nss_load_builtin_modules(void);
static void nss_load_module(const char *, nss_module_register_fn);
static void nss_atexit(void);
/* nsparser */
extern FILE *_nsyyin;
/*
* The vector operations
*/
static void
vector_sort(void *vec, unsigned int count, size_t esize,
vector_comparison comparison)
{
qsort(vec, count, esize, comparison);
}
static void *
vector_search(const void *key, void *vec, unsigned int count, size_t esize,
vector_comparison comparison)
{
return (bsearch(key, vec, count, esize, comparison));
}
static void *
vector_append(const void *elem, void *vec, unsigned int *count, size_t esize)
{
void *p;
if ((*count % ELEMSPERCHUNK) == 0) {
p = reallocarray(vec, *count + ELEMSPERCHUNK, esize);
if (p == NULL) {
nss_log_simple(LOG_ERR, "memory allocation failure");
return (vec);
}
vec = p;
}
memmove((void *)(((uintptr_t)vec) + (*count * esize)), elem, esize);
(*count)++;
return (vec);
}
static void *
vector_ref(unsigned int i, void *vec, unsigned int count, size_t esize)
{
if (i < count)
return (void *)((uintptr_t)vec + (i * esize));
else
return (NULL);
}
#define VECTOR_FREE(v, c, s, f) \
do { vector_free(v, c, s, f); v = NULL; } while (0)
static void
vector_free(void *vec, unsigned int *count, size_t esize,
vector_free_elem free_elem)
{
unsigned int i;
void *elem;
for (i = 0; i < *count; i++) {
elem = vector_ref(i, vec, *count, esize);
if (elem != NULL)
free_elem(elem);
}
free(vec);
*count = 0;
}
/*
* Comparison functions for vector_search.
*/
static int
string_compare(const void *a, const void *b)
{
return (strcasecmp(*(const char * const *)a, *(const char * const *)b));
}
static int
mtab_compare(const void *a, const void *b)
{
int cmp;
cmp = strcmp(((const ns_mtab *)a)->name, ((const ns_mtab *)b)->name);
if (cmp != 0)
return (cmp);
else
return (strcmp(((const ns_mtab *)a)->database,
((const ns_mtab *)b)->database));
}
/*
* NSS nsmap management.
*/
void
_nsdbtaddsrc(ns_dbt *dbt, const ns_src *src)
{
const ns_mod *modp;
dbt->srclist = vector_append(src, dbt->srclist, &dbt->srclistsize,
sizeof(*src));
modp = vector_search(&src->name, _nsmod, _nsmodsize, sizeof(*_nsmod),
string_compare);
if (modp == NULL)
nss_load_module(src->name, NULL);
}
#ifdef _NSS_DEBUG
void
_nsdbtdump(const ns_dbt *dbt)
{
int i;
printf("%s (%d source%s):", dbt->name, dbt->srclistsize,
dbt->srclistsize == 1 ? "" : "s");
for (i = 0; i < (int)dbt->srclistsize; i++) {
printf(" %s", dbt->srclist[i].name);
if (!(dbt->srclist[i].flags &
(NS_UNAVAIL|NS_NOTFOUND|NS_TRYAGAIN)) &&
(dbt->srclist[i].flags & NS_SUCCESS))
continue;
printf(" [");
if (!(dbt->srclist[i].flags & NS_SUCCESS))
printf(" SUCCESS=continue");
if (dbt->srclist[i].flags & NS_UNAVAIL)
printf(" UNAVAIL=return");
if (dbt->srclist[i].flags & NS_NOTFOUND)
printf(" NOTFOUND=return");
if (dbt->srclist[i].flags & NS_TRYAGAIN)
printf(" TRYAGAIN=return");
printf(" ]");
}
printf("\n");
}
#endif
/*
* The first time nsdispatch is called (during a process's lifetime,
* or after nsswitch.conf has been updated), nss_configure will
* prepare global data needed by NSS.
*/
static int
nss_configure(void)
{
static time_t confmod;
#ifndef NS_REREAD_CONF
static int already_initialized = 0;
#endif
struct stat statbuf;
int result, isthreaded;
const char *path;
#ifdef NS_CACHING
void *handle;
#endif
result = 0;
isthreaded = __isthreaded;
#if defined(_NSS_DEBUG) && defined(_NSS_SHOOT_FOOT)
/* NOTE WELL: THIS IS A SECURITY HOLE. This must only be built
* for debugging purposes and MUST NEVER be used in production.
*/
path = getenv("NSSWITCH_CONF");
if (path == NULL)
#endif
path = _PATH_NS_CONF;
#ifndef NS_REREAD_CONF
/*
* Define NS_REREAD_CONF to have nsswitch notice changes
* to nsswitch.conf(5) during runtime. This involves calling
* stat(2) every time, which can result in performance hit.
*/
if (already_initialized)
return (0);
already_initialized = 1;
#endif /* NS_REREAD_CONF */
if (stat(path, &statbuf) != 0)
return (0);
if (statbuf.st_mtime <= confmod)
return (0);
if (isthreaded) {
(void)_pthread_rwlock_unlock(&nss_lock);
result = _pthread_rwlock_wrlock(&nss_lock);
if (result != 0)
return (result);
if (stat(path, &statbuf) != 0)
goto fin;
if (statbuf.st_mtime <= confmod)
goto fin;
}
_nsyyin = fopen(path, "re");
if (_nsyyin == NULL)
goto fin;
VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
(vector_free_elem)ns_dbt_free);
VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
(vector_free_elem)ns_mod_free);
if (confmod == 0)
(void)atexit(nss_atexit);
nss_load_builtin_modules();
_nsyyparse();
(void)fclose(_nsyyin);
vector_sort(_nsmap, _nsmapsize, sizeof(*_nsmap), string_compare);
confmod = statbuf.st_mtime;
#ifdef NS_CACHING
handle = libc_dlopen(NULL, RTLD_LAZY | RTLD_GLOBAL);
if (handle != NULL) {
nss_cache_cycle_prevention_func = dlsym(handle,
"_nss_cache_cycle_prevention_function");
dlclose(handle);
}
#endif
fin:
if (isthreaded) {
(void)_pthread_rwlock_unlock(&nss_lock);
if (result == 0)
result = _pthread_rwlock_rdlock(&nss_lock);
}
return (result);
}
void
_nsdbtput(const ns_dbt *dbt)
{
unsigned int i;
ns_dbt *p;
for (i = 0; i < _nsmapsize; i++) {
p = vector_ref(i, _nsmap, _nsmapsize, sizeof(*_nsmap));
if (string_compare(&dbt->name, &p->name) == 0) {
/* overwrite existing entry */
if (p->srclist != NULL)
ns_src_free(&p->srclist, p->srclistsize);
memmove(p, dbt, sizeof(*dbt));
return;
}
}
_nsmap = vector_append(dbt, _nsmap, &_nsmapsize, sizeof(*_nsmap));
}
static void
ns_dbt_free(ns_dbt *dbt)
{
ns_src_free(&dbt->srclist, dbt->srclistsize);
if (dbt->name)
free((void *)dbt->name);
}
static void
ns_src_free(ns_src **src, int srclistsize)
{
int i;
for (i = 0; i < srclistsize; i++)
if ((*src)[i].name != NULL)
/* This one was allocated by nslexer. You'll just
* have to trust me.
*/
free((void *)((*src)[i].name));
free(*src);
*src = NULL;
}
/*
* NSS module management.
*/
/* The built-in NSS modules are all loaded at once. */
#define NSS_BACKEND(name, reg) \
ns_mtab *reg(unsigned int *, nss_module_unregister_fn *);
#include "nss_backends.h"
#undef NSS_BACKEND
static void
nss_load_builtin_modules(void)
{
#define NSS_BACKEND(name, reg) nss_load_module(#name, reg);
#include "nss_backends.h"
#undef NSS_BACKEND
}
/* Load a built-in or dynamically linked module. If the `reg_fn'
* argument is non-NULL, assume a built-in module and use reg_fn to
* register it. Otherwise, search for a dynamic NSS module.
*/
static void
nss_load_module(const char *source, nss_module_register_fn reg_fn)
{
char buf[PATH_MAX];
ns_mod mod;
nss_module_register_fn fn;
memset(&mod, 0, sizeof(mod));
mod.name = strdup(source);
if (mod.name == NULL) {
nss_log_simple(LOG_ERR, "memory allocation failure");
return;
}
if (reg_fn != NULL) {
/* The placeholder is required, as a NULL handle
* represents an invalid module.
*/
mod.handle = nss_builtin_handle;
fn = reg_fn;
} else if (!is_dynamic()) {
goto fin;
} else if (strcmp(source, NSSRC_CACHE) == 0 ||
strcmp(source, NSSRC_COMPAT) == 0 ||
strcmp(source, NSSRC_DB) == 0 ||
strcmp(source, NSSRC_DNS) == 0 ||
strcmp(source, NSSRC_FILES) == 0 ||
strcmp(source, NSSRC_NIS) == 0) {
/*
* Avoid calling dlopen(3) for built-in modules.
*/
goto fin;
} else {
if (snprintf(buf, sizeof(buf), "nss_%s.so.%d", mod.name,
NSS_MODULE_INTERFACE_VERSION) >= (int)sizeof(buf))
goto fin;
mod.handle = libc_dlopen(buf, RTLD_LOCAL|RTLD_LAZY);
if (mod.handle == NULL) {
#ifdef _NSS_DEBUG
/* This gets pretty annoying since the built-in
* sources aren't modules yet.
*/
nss_log(LOG_DEBUG, "%s, %s", mod.name, dlerror());
#endif
goto fin;
}
fn = (nss_module_register_fn)dlfunc(mod.handle,
"nss_module_register");
if (fn == NULL) {
(void)dlclose(mod.handle);
mod.handle = NULL;
nss_log(LOG_ERR, "%s, %s", mod.name, dlerror());
goto fin;
}
}
mod.mtab = fn(mod.name, &mod.mtabsize, &mod.unregister);
if (mod.mtab == NULL || mod.mtabsize == 0) {
if (mod.handle != nss_builtin_handle)
(void)dlclose(mod.handle);
mod.handle = NULL;
nss_log(LOG_ERR, "%s, registration failed", mod.name);
goto fin;
}
if (mod.mtabsize > 1)
qsort(mod.mtab, mod.mtabsize, sizeof(mod.mtab[0]),
mtab_compare);
fin:
_nsmod = vector_append(&mod, _nsmod, &_nsmodsize, sizeof(*_nsmod));
vector_sort(_nsmod, _nsmodsize, sizeof(*_nsmod), string_compare);
}
static int exiting = 0;
static void
ns_mod_free(ns_mod *mod)
{
free(mod->name);
if (mod->handle == NULL)
return;
if (mod->unregister != NULL)
mod->unregister(mod->mtab, mod->mtabsize);
if (mod->handle != nss_builtin_handle && !exiting)
(void)dlclose(mod->handle);
}
/*
* Cleanup
*/
static void
nss_atexit(void)
{
int isthreaded;
exiting = 1;
isthreaded = __isthreaded;
if (isthreaded)
(void)_pthread_rwlock_wrlock(&nss_lock);
VECTOR_FREE(_nsmap, &_nsmapsize, sizeof(*_nsmap),
(vector_free_elem)ns_dbt_free);
VECTOR_FREE(_nsmod, &_nsmodsize, sizeof(*_nsmod),
(vector_free_elem)ns_mod_free);
if (isthreaded)
(void)_pthread_rwlock_unlock(&nss_lock);
}
/*
* Finally, the actual implementation.
*/
static nss_method
nss_method_lookup(const char *source, const char *database,
const char *method, const ns_dtab disp_tab[], void **mdata)
{
ns_mod *mod;
ns_mtab *match, key;
int i;
if (disp_tab != NULL)
for (i = 0; disp_tab[i].src != NULL; i++)
if (strcasecmp(source, disp_tab[i].src) == 0) {
*mdata = disp_tab[i].mdata;
return (disp_tab[i].method);
}
mod = vector_search(&source, _nsmod, _nsmodsize, sizeof(*_nsmod),
string_compare);
if (mod != NULL && mod->handle != NULL) {
key.database = database;
key.name = method;
match = bsearch(&key, mod->mtab, mod->mtabsize,
sizeof(mod->mtab[0]), mtab_compare);
if (match != NULL) {
*mdata = match->mdata;
return (match->method);
}
}
*mdata = NULL;
return (NULL);
}
static void
fb_endstate(void *p)
{
free(p);
}
__weak_reference(_nsdispatch, nsdispatch);
int
_nsdispatch(void *retval, const ns_dtab disp_tab[], const char *database,
const char *method_name, const ns_src defaults[], ...)
{
va_list ap;
const ns_dbt *dbt;
const ns_src *srclist;
nss_method method, fb_method;
void *mdata;
int isthreaded, serrno, i, result, srclistsize;
struct fb_state *st;
int saved_depth;
#ifdef NS_CACHING
nss_cache_data cache_data;
nss_cache_data *cache_data_p;
int cache_flag;
#endif
dbt = NULL;
fb_method = NULL;
isthreaded = __isthreaded;
serrno = errno;
if (isthreaded) {
result = _pthread_rwlock_rdlock(&nss_lock);
if (result != 0) {
result = NS_UNAVAIL;
goto fin;
}
}
result = fb_getstate(&st);
if (result != 0) {
result = NS_UNAVAIL;
goto fin;
}
result = nss_configure();
if (result != 0) {
result = NS_UNAVAIL;
goto fin;
}
++st->dispatch_depth;
if (st->dispatch_depth > st->fallback_depth) {
dbt = vector_search(&database, _nsmap, _nsmapsize, sizeof(*_nsmap),
string_compare);
fb_method = nss_method_lookup(NSSRC_FALLBACK, database,
method_name, disp_tab, &mdata);
}
if (dbt != NULL) {
srclist = dbt->srclist;
srclistsize = dbt->srclistsize;
} else {
srclist = defaults;
srclistsize = 0;
while (srclist[srclistsize].name != NULL)
srclistsize++;
}
#ifdef NS_CACHING
cache_data_p = NULL;
cache_flag = 0;
#endif
for (i = 0; i < srclistsize; i++) {
result = NS_NOTFOUND;
method = nss_method_lookup(srclist[i].name, database,
method_name, disp_tab, &mdata);
if (method != NULL) {
#ifdef NS_CACHING
if (strcmp(srclist[i].name, NSSRC_CACHE) == 0 &&
nss_cache_cycle_prevention_func == NULL) {
#ifdef NS_STRICT_LIBC_EID_CHECKING
if (issetugid() != 0)
continue;
#endif
cache_flag = 1;
memset(&cache_data, 0, sizeof(nss_cache_data));
cache_data.info = (nss_cache_info const *)mdata;
cache_data_p = &cache_data;
va_start(ap, defaults);
if (cache_data.info->id_func != NULL)
result = __nss_common_cache_read(retval,
cache_data_p, ap);
else if (cache_data.info->marshal_func != NULL)
result = __nss_mp_cache_read(retval,
cache_data_p, ap);
else
result = __nss_mp_cache_end(retval,
cache_data_p, ap);
va_end(ap);
} else {
cache_flag = 0;
errno = 0;
va_start(ap, defaults);
result = method(retval, mdata, ap);
va_end(ap);
}
#else /* NS_CACHING */
errno = 0;
va_start(ap, defaults);
result = method(retval, mdata, ap);
va_end(ap);
#endif /* NS_CACHING */
if (result & (srclist[i].flags))
break;
} else {
if (fb_method != NULL) {
saved_depth = st->fallback_depth;
st->fallback_depth = st->dispatch_depth + 1;
va_start(ap, defaults);
result = fb_method(retval,
(void *)srclist[i].name, ap);
va_end(ap);
st->fallback_depth = saved_depth;
} else
nss_log(LOG_DEBUG, "%s, %s, %s, not found, "
"and no fallback provided",
srclist[i].name, database, method_name);
}
}
#ifdef NS_CACHING
if (cache_data_p != NULL &&
(result & (NS_NOTFOUND | NS_SUCCESS)) && cache_flag == 0) {
va_start(ap, defaults);
if (result == NS_SUCCESS) {
if (cache_data.info->id_func != NULL)
__nss_common_cache_write(retval, cache_data_p,
ap);
else if (cache_data.info->marshal_func != NULL)
__nss_mp_cache_write(retval, cache_data_p, ap);
} else if (result == NS_NOTFOUND) {
if (cache_data.info->id_func == NULL) {
if (cache_data.info->marshal_func != NULL)
__nss_mp_cache_write_submit(retval,
cache_data_p, ap);
} else
__nss_common_cache_write_negative(cache_data_p);
}
va_end(ap);
}
#endif /* NS_CACHING */
if (isthreaded)
(void)_pthread_rwlock_unlock(&nss_lock);
--st->dispatch_depth;
fin:
errno = serrno;
return (result);
}
diff --git a/lib/libc/net/nsparser.y b/lib/libc/net/nsparser.y
index 636ac19ffbc0..ec840d996f90 100644
--- a/lib/libc/net/nsparser.y
+++ b/lib/libc/net/nsparser.y
@@ -1,177 +1,176 @@
%{
/* $NetBSD: nsparser.y,v 1.3 1999/01/25 00:16:18 lukem Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997, 1998, 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#define _NS_PRIVATE
#include <nsswitch.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "un-namespace.h"
static void _nsaddsrctomap(const char *);
static ns_dbt curdbt;
static ns_src cursrc;
%}
%union {
char *str;
int mapval;
}
%token NL
%token SUCCESS UNAVAIL NOTFOUND TRYAGAIN
%token RETURN CONTINUE
%token ERRORTOKEN
%token <str> STRING
%type <mapval> Status Action
%%
File
: /* empty */
| Lines
;
Lines
: Entry
| Lines Entry
;
Entry
: NL
| Database ':' NL
{
free((char*)curdbt.name);
}
| Database ':' Srclist NL
{
_nsdbtput(&curdbt);
}
| error NL
{
yyerrok;
}
;
Database
: STRING
{
curdbt.name = yylval.str;
curdbt.srclist = NULL;
curdbt.srclistsize = 0;
}
;
Srclist
: Item
| Srclist Item
;
Item
: STRING
{
cursrc.flags = NS_TERMINATE;
_nsaddsrctomap($1);
}
| STRING '[' { cursrc.flags = NS_SUCCESS; } Criteria ']'
{
_nsaddsrctomap($1);
}
;
Criteria
: Criterion
| Criteria Criterion
;
Criterion
: Status '=' Action
{
if ($3) /* if action == RETURN set RETURN bit */
cursrc.flags |= $1;
else /* else unset it */
cursrc.flags &= ~$1;
}
;
Status
: SUCCESS { $$ = NS_SUCCESS; }
| UNAVAIL { $$ = NS_UNAVAIL; }
| NOTFOUND { $$ = NS_NOTFOUND; }
| TRYAGAIN { $$ = NS_TRYAGAIN; }
;
Action
: RETURN { $$ = NS_ACTION_RETURN; }
| CONTINUE { $$ = NS_ACTION_CONTINUE; }
;
%%
static void
_nsaddsrctomap(const char *elem)
{
int i, lineno;
extern int _nsyylineno;
extern char * _nsyytext;
lineno = _nsyylineno - (*_nsyytext == '\n' ? 1 : 0);
if (curdbt.srclistsize > 0) {
if (((strcasecmp(elem, NSSRC_COMPAT) == 0) &&
(strcasecmp(curdbt.srclist[0].name, NSSRC_CACHE) != 0)) ||
(strcasecmp(curdbt.srclist[0].name, NSSRC_COMPAT) == 0)) {
syslog(LOG_ERR,
"NSSWITCH(nsparser): %s line %d: 'compat' used with sources, other than 'cache'",
_PATH_NS_CONF, lineno);
free((void*)elem);
return;
}
}
for (i = 0; i < curdbt.srclistsize; i++) {
if (strcasecmp(curdbt.srclist[i].name, elem) == 0) {
syslog(LOG_ERR,
"NSSWITCH(nsparser): %s line %d: duplicate source '%s'",
_PATH_NS_CONF, lineno, elem);
free((void*)elem);
return;
}
}
cursrc.name = elem;
_nsdbtaddsrc(&curdbt, &cursrc);
}
diff --git a/lib/libc/net/nss_compat.c b/lib/libc/net/nss_compat.c
index 131e7c398589..fb1956b1e71a 100644
--- a/lib/libc/net/nss_compat.c
+++ b/lib/libc/net/nss_compat.c
@@ -1,288 +1,287 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project by
* Jacques A. Vidrine, Safeport Network Services, and Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035
* ("CBOSS"), as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Compatibility shims for the GNU C Library-style nsswitch interface.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <errno.h>
#include <nss.h>
#include <pthread.h>
#include <pthread_np.h>
#include "un-namespace.h"
#include "libc_private.h"
struct group;
struct passwd;
static int terminator;
#define DECLARE_TERMINATOR(x) \
static pthread_key_t _term_key_##x; \
static void \
_term_create_##x(void) \
{ \
(void)_pthread_key_create(&_term_key_##x, NULL); \
} \
static void *_term_main_##x; \
static pthread_once_t _term_once_##x = PTHREAD_ONCE_INIT
#define SET_TERMINATOR(x, y) \
do { \
if (!__isthreaded || _pthread_main_np()) \
_term_main_##x = (y); \
else { \
(void)_pthread_once(&_term_once_##x, _term_create_##x); \
(void)_pthread_setspecific(_term_key_##x, y); \
} \
} while (0)
#define CHECK_TERMINATOR(x) \
(!__isthreaded || _pthread_main_np() ? \
(_term_main_##x) : \
((void)_pthread_once(&_term_once_##x, _term_create_##x), \
_pthread_getspecific(_term_key_##x)))
DECLARE_TERMINATOR(group);
int __nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap);
int __nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap);
int __nss_compat_getgrent_r(void *retval, void *mdata, va_list ap);
int __nss_compat_setgrent(void *retval, void *mdata, va_list ap);
int __nss_compat_endgrent(void *retval, void *mdata, va_list ap);
int __nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap);
int __nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap);
int __nss_compat_getpwent_r(void *retval, void *mdata, va_list ap);
int __nss_compat_setpwent(void *retval, void *mdata, va_list ap);
int __nss_compat_endpwent(void *retval, void *mdata, va_list ap);
int
__nss_compat_getgrnam_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(const char *, struct group *, char *, size_t, int *);
const char *name;
struct group *grp;
char *buffer;
int *errnop, ns_status;
size_t bufsize;
enum nss_status nss_status;
fn = mdata;
name = va_arg(ap, const char *);
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
nss_status = fn(name, grp, buffer, bufsize, errnop);
ns_status = __nss_compat_result(nss_status, *errnop);
if (ns_status == NS_SUCCESS)
*(struct group **)retval = grp;
return (ns_status);
}
int
__nss_compat_getgrgid_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(gid_t, struct group *, char *, size_t, int *);
gid_t gid;
struct group *grp;
char *buffer;
int *errnop, ns_status;
size_t bufsize;
enum nss_status nss_status;
fn = mdata;
gid = va_arg(ap, gid_t);
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
nss_status = fn(gid, grp, buffer, bufsize, errnop);
ns_status = __nss_compat_result(nss_status, *errnop);
if (ns_status == NS_SUCCESS)
*(struct group **)retval = grp;
return (ns_status);
}
int
__nss_compat_getgrent_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(struct group *, char *, size_t, int *);
struct group *grp;
char *buffer;
int *errnop, ns_status;
size_t bufsize;
enum nss_status nss_status;
if (CHECK_TERMINATOR(group))
return (NS_NOTFOUND);
fn = mdata;
grp = va_arg(ap, struct group *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
nss_status = fn(grp, buffer, bufsize, errnop);
ns_status = __nss_compat_result(nss_status, *errnop);
if (ns_status == NS_SUCCESS)
*(struct group **)retval = grp;
else if (ns_status != NS_RETURN)
SET_TERMINATOR(group, &terminator);
return (ns_status);
}
int
__nss_compat_setgrent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(group, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}
int
__nss_compat_endgrent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(group, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}
DECLARE_TERMINATOR(passwd);
int
__nss_compat_getpwnam_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(const char *, struct passwd *, char *, size_t, int *);
const char *name;
struct passwd *pwd;
char *buffer;
int *errnop, ns_status;
size_t bufsize;
enum nss_status nss_status;
fn = mdata;
name = va_arg(ap, const char *);
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
nss_status = fn(name, pwd, buffer, bufsize, errnop);
ns_status = __nss_compat_result(nss_status, *errnop);
if (ns_status == NS_SUCCESS)
*(struct passwd **)retval = pwd;
return (ns_status);
}
int
__nss_compat_getpwuid_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(uid_t, struct passwd *, char *, size_t, int *);
uid_t uid;
struct passwd *pwd;
char *buffer;
int *errnop, ns_status;
size_t bufsize;
enum nss_status nss_status;
fn = mdata;
uid = va_arg(ap, uid_t);
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
nss_status = fn(uid, pwd, buffer, bufsize, errnop);
ns_status = __nss_compat_result(nss_status, *errnop);
if (ns_status == NS_SUCCESS)
*(struct passwd **)retval = pwd;
return (ns_status);
}
int
__nss_compat_getpwent_r(void *retval, void *mdata, va_list ap)
{
int (*fn)(struct passwd *, char *, size_t, int *);
struct passwd *pwd;
char *buffer;
int *errnop, ns_status;
size_t bufsize;
enum nss_status nss_status;
if (CHECK_TERMINATOR(passwd))
return (NS_NOTFOUND);
fn = mdata;
pwd = va_arg(ap, struct passwd *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
nss_status = fn(pwd, buffer, bufsize, errnop);
ns_status = __nss_compat_result(nss_status, *errnop);
if (ns_status == NS_SUCCESS)
*(struct passwd **)retval = pwd;
else if (ns_status != NS_RETURN)
SET_TERMINATOR(passwd, &terminator);
return (ns_status);
}
int
__nss_compat_setpwent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(passwd, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}
int
__nss_compat_endpwent(void *retval, void *mdata, va_list ap)
{
SET_TERMINATOR(passwd, NULL);
((int (*)(void))mdata)();
return (NS_UNAVAIL);
}
diff --git a/lib/libc/net/ntoh.c b/lib/libc/net/ntoh.c
index 1c309ded5cb8..508a2c81d466 100644
--- a/lib/libc/net/ntoh.c
+++ b/lib/libc/net/ntoh.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2006 Olivier Houchard
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/endian.h>
#define _BYTEORDER_FUNC_DEFINED
#include <arpa/inet.h>
uint32_t
htonl(uint32_t hl)
{
return (__htonl(hl));
}
uint16_t
htons(uint16_t hs)
{
return (__htons(hs));
}
uint32_t
ntohl(uint32_t nl)
{
return (__ntohl(nl));
}
uint16_t
ntohs(uint16_t ns)
{
return (__ntohs(ns));
}
diff --git a/lib/libc/net/rcmd.c b/lib/libc/net/rcmd.c
index 1a0dd5c48d01..edc3e07b1dc6 100644
--- a/lib/libc/net/rcmd.c
+++ b/lib/libc/net/rcmd.c
@@ -1,733 +1,732 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rcmd.c 8.3 (Berkeley) 3/26/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdlib.h>
#include <unistd.h>
#include <pwd.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <rpc/rpc.h>
#ifdef YP
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include <arpa/nameser.h>
#include "un-namespace.h"
#include "libc_private.h"
extern int innetgr( const char *, const char *, const char *, const char * );
#define max(a, b) ((a > b) ? a : b)
int __ivaliduser(FILE *, u_int32_t, const char *, const char *);
int __ivaliduser_af(FILE *,const void *, const char *, const char *, int, int);
int __ivaliduser_sa(FILE *, const struct sockaddr *, socklen_t, const char *,
const char *);
static int __icheckhost(const struct sockaddr *, socklen_t, const char *);
char paddr[NI_MAXHOST];
int
rcmd(char **ahost, int rport, const char *locuser, const char *remuser,
const char *cmd, int *fd2p)
{
return rcmd_af(ahost, rport, locuser, remuser, cmd, fd2p, AF_INET);
}
int
rcmd_af(char **ahost, int rport, const char *locuser, const char *remuser,
const char *cmd, int *fd2p, int af)
{
struct addrinfo hints, *res, *ai;
struct sockaddr_storage from;
fd_set reads;
sigset_t oldmask, newmask;
pid_t pid;
int s, aport, lport, timo, error;
char c, *p;
int refused, nres;
char num[8];
static char canonnamebuf[MAXDNAME]; /* is it proper here? */
/* call rcmdsh() with specified remote shell if appropriate. */
if ((p = secure_getenv("RSH")) != NULL) {
struct servent *sp = getservbyname("shell", "tcp");
if (sp && sp->s_port == rport)
return (rcmdsh(ahost, rport, locuser, remuser,
cmd, p));
}
/* use rsh(1) if non-root and remote port is shell. */
if (geteuid()) {
struct servent *sp = getservbyname("shell", "tcp");
if (sp && sp->s_port == rport)
return (rcmdsh(ahost, rport, locuser, remuser,
cmd, NULL));
}
pid = getpid();
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
(void)snprintf(num, sizeof(num), "%d", ntohs(rport));
error = getaddrinfo(*ahost, num, &hints, &res);
if (error) {
fprintf(stderr, "rcmd: getaddrinfo: %s\n",
gai_strerror(error));
if (error == EAI_SYSTEM)
fprintf(stderr, "rcmd: getaddrinfo: %s\n",
strerror(errno));
return (-1);
}
if (res->ai_canonname
&& strlen(res->ai_canonname) + 1 < sizeof(canonnamebuf)) {
strncpy(canonnamebuf, res->ai_canonname, sizeof(canonnamebuf));
*ahost = canonnamebuf;
}
nres = 0;
for (ai = res; ai; ai = ai->ai_next)
nres++;
ai = res;
refused = 0;
sigemptyset(&newmask);
sigaddset(&newmask, SIGURG);
__libc_sigprocmask(SIG_BLOCK, (const sigset_t *)&newmask, &oldmask);
for (timo = 1, lport = IPPORT_RESERVED - 1;;) {
s = rresvport_af(&lport, ai->ai_family);
if (s < 0) {
if (errno != EAGAIN && ai->ai_next) {
ai = ai->ai_next;
continue;
}
if (errno == EAGAIN)
(void)fprintf(stderr,
"rcmd: socket: All ports in use\n");
else
(void)fprintf(stderr, "rcmd: socket: %s\n",
strerror(errno));
freeaddrinfo(res);
__libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
NULL);
return (-1);
}
_fcntl(s, F_SETOWN, pid);
if (_connect(s, ai->ai_addr, ai->ai_addrlen) >= 0)
break;
(void)_close(s);
if (errno == EADDRINUSE) {
lport--;
continue;
}
if (errno == ECONNREFUSED)
refused = 1;
if (ai->ai_next == NULL && (!refused || timo > 16)) {
(void)fprintf(stderr, "%s: %s\n",
*ahost, strerror(errno));
freeaddrinfo(res);
__libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask,
NULL);
return (-1);
}
if (nres > 1) {
int oerrno = errno;
getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
sizeof(paddr), NULL, 0, NI_NUMERICHOST);
(void)fprintf(stderr, "connect to address %s: ",
paddr);
errno = oerrno;
perror(0);
}
if ((ai = ai->ai_next) == NULL) {
/* refused && timo <= 16 */
struct timespec time_to_sleep, time_remaining;
time_to_sleep.tv_sec = timo;
time_to_sleep.tv_nsec = 0;
(void)_nanosleep(&time_to_sleep, &time_remaining);
timo *= 2;
ai = res;
refused = 0;
}
if (nres > 1) {
getnameinfo(ai->ai_addr, ai->ai_addrlen, paddr,
sizeof(paddr), NULL, 0, NI_NUMERICHOST);
fprintf(stderr, "Trying %s...\n", paddr);
}
}
lport--;
if (fd2p == NULL) {
_write(s, "", 1);
lport = 0;
} else {
int s2 = rresvport_af(&lport, ai->ai_family), s3;
socklen_t len = ai->ai_addrlen;
int nfds;
if (s2 < 0)
goto bad;
_listen(s2, 1);
(void)snprintf(num, sizeof(num), "%d", lport);
if (_write(s, num, strlen(num)+1) != strlen(num)+1) {
(void)fprintf(stderr,
"rcmd: write (setting up stderr): %s\n",
strerror(errno));
(void)_close(s2);
goto bad;
}
nfds = max(s, s2)+1;
if(nfds > FD_SETSIZE) {
fprintf(stderr, "rcmd: too many files\n");
(void)_close(s2);
goto bad;
}
again:
FD_ZERO(&reads);
FD_SET(s, &reads);
FD_SET(s2, &reads);
errno = 0;
if (_select(nfds, &reads, 0, 0, 0) < 1 || !FD_ISSET(s2, &reads)){
if (errno != 0)
(void)fprintf(stderr,
"rcmd: select (setting up stderr): %s\n",
strerror(errno));
else
(void)fprintf(stderr,
"select: protocol failure in circuit setup\n");
(void)_close(s2);
goto bad;
}
s3 = _accept(s2, (struct sockaddr *)&from, &len);
switch (from.ss_family) {
case AF_INET:
aport = ntohs(((struct sockaddr_in *)&from)->sin_port);
break;
#ifdef INET6
case AF_INET6:
aport = ntohs(((struct sockaddr_in6 *)&from)->sin6_port);
break;
#endif
default:
aport = 0; /* error */
break;
}
/*
* XXX careful for ftp bounce attacks. If discovered, shut them
* down and check for the real auxiliary channel to connect.
*/
if (aport == 20) {
_close(s3);
goto again;
}
(void)_close(s2);
if (s3 < 0) {
(void)fprintf(stderr,
"rcmd: accept: %s\n", strerror(errno));
lport = 0;
goto bad;
}
*fd2p = s3;
if (aport >= IPPORT_RESERVED || aport < IPPORT_RESERVED / 2) {
(void)fprintf(stderr,
"socket: protocol failure in circuit setup.\n");
goto bad2;
}
}
(void)_write(s, locuser, strlen(locuser)+1);
(void)_write(s, remuser, strlen(remuser)+1);
(void)_write(s, cmd, strlen(cmd)+1);
if (_read(s, &c, 1) != 1) {
(void)fprintf(stderr,
"rcmd: %s: %s\n", *ahost, strerror(errno));
goto bad2;
}
if (c != 0) {
while (_read(s, &c, 1) == 1) {
(void)_write(STDERR_FILENO, &c, 1);
if (c == '\n')
break;
}
goto bad2;
}
__libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
freeaddrinfo(res);
return (s);
bad2:
if (lport)
(void)_close(*fd2p);
bad:
(void)_close(s);
__libc_sigprocmask(SIG_SETMASK, (const sigset_t *)&oldmask, NULL);
freeaddrinfo(res);
return (-1);
}
int
rresvport(int *port)
{
return rresvport_af(port, AF_INET);
}
int
rresvport_af(int *alport, int family)
{
int s;
struct sockaddr_storage ss;
u_short *sport;
memset(&ss, 0, sizeof(ss));
ss.ss_family = family;
switch (family) {
case AF_INET:
((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in);
sport = &((struct sockaddr_in *)&ss)->sin_port;
((struct sockaddr_in *)&ss)->sin_addr.s_addr = INADDR_ANY;
break;
#ifdef INET6
case AF_INET6:
((struct sockaddr *)&ss)->sa_len = sizeof(struct sockaddr_in6);
sport = &((struct sockaddr_in6 *)&ss)->sin6_port;
((struct sockaddr_in6 *)&ss)->sin6_addr = in6addr_any;
break;
#endif
default:
errno = EAFNOSUPPORT;
return -1;
}
s = _socket(ss.ss_family, SOCK_STREAM, 0);
if (s < 0)
return (-1);
#if 0 /* compat_exact_traditional_rresvport_semantics */
sin.sin_port = htons((u_short)*alport);
if (_bind(s, (struct sockaddr *)&sin, sizeof(sin)) >= 0)
return (s);
if (errno != EADDRINUSE) {
(void)_close(s);
return (-1);
}
#endif
*sport = 0;
if (bindresvport_sa(s, (struct sockaddr *)&ss) == -1) {
(void)_close(s);
return (-1);
}
*alport = (int)ntohs(*sport);
return (s);
}
int __check_rhosts_file = 1;
char *__rcmd_errstr;
int
ruserok(const char *rhost, int superuser, const char *ruser, const char *luser)
{
struct addrinfo hints, *res, *r;
int error;
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
error = getaddrinfo(rhost, "0", &hints, &res);
if (error)
return (-1);
for (r = res; r; r = r->ai_next) {
if (iruserok_sa(r->ai_addr, r->ai_addrlen, superuser, ruser,
luser) == 0) {
freeaddrinfo(res);
return (0);
}
}
freeaddrinfo(res);
return (-1);
}
/*
* New .rhosts strategy: We are passed an ip address. We spin through
* hosts.equiv and .rhosts looking for a match. When the .rhosts only
* has ip addresses, we don't have to trust a nameserver. When it
* contains hostnames, we spin through the list of addresses the nameserver
* gives us and look for a match.
*
* Returns 0 if ok, -1 if not ok.
*/
int
iruserok(unsigned long raddr, int superuser, const char *ruser, const char *luser)
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(struct sockaddr_in);
memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
return iruserok_sa((struct sockaddr *)&sin, sin.sin_len, superuser,
ruser, luser);
}
/*
* AF independent extension of iruserok.
*
* Returns 0 if ok, -1 if not ok.
*/
int
iruserok_sa(const void *ra, int rlen, int superuser, const char *ruser,
const char *luser)
{
char *cp;
struct stat sbuf;
struct passwd *pwd;
FILE *hostf;
uid_t uid;
int first;
char pbuf[MAXPATHLEN];
const struct sockaddr *raddr;
struct sockaddr_storage ss;
/* avoid alignment issue */
if (rlen <= 0 || rlen > sizeof(ss))
return (-1);
memcpy(&ss, ra, rlen);
raddr = (struct sockaddr *)&ss;
first = 1;
hostf = superuser ? NULL : fopen(_PATH_HEQUIV, "re");
again:
if (hostf) {
if (__ivaliduser_sa(hostf, raddr, rlen, luser, ruser) == 0) {
(void)fclose(hostf);
return (0);
}
(void)fclose(hostf);
}
if (first == 1 && (__check_rhosts_file || superuser)) {
first = 0;
if ((pwd = getpwnam(luser)) == NULL)
return (-1);
(void)strlcpy(pbuf, pwd->pw_dir, sizeof(pbuf));
(void)strlcat(pbuf, "/.rhosts", sizeof(pbuf));
/*
* Change effective uid while opening .rhosts. If root and
* reading an NFS mounted file system, can't read files that
* are protected read/write owner only.
*/
uid = geteuid();
(void)seteuid(pwd->pw_uid);
hostf = fopen(pbuf, "re");
(void)seteuid(uid);
if (hostf == NULL)
return (-1);
/*
* If not a regular file, or is owned by someone other than
* user or root or if writeable by anyone but the owner, quit.
*/
cp = NULL;
if (lstat(pbuf, &sbuf) < 0)
cp = ".rhosts lstat failed";
else if (!S_ISREG(sbuf.st_mode))
cp = ".rhosts not regular file";
else if (_fstat(fileno(hostf), &sbuf) < 0)
cp = ".rhosts fstat failed";
else if (sbuf.st_uid && sbuf.st_uid != pwd->pw_uid)
cp = "bad .rhosts owner";
else if (sbuf.st_mode & (S_IWGRP|S_IWOTH))
cp = ".rhosts writeable by other than owner";
/* If there were any problems, quit. */
if (cp) {
__rcmd_errstr = cp;
(void)fclose(hostf);
return (-1);
}
goto again;
}
return (-1);
}
/*
* XXX
* Don't make static, used by lpd(8).
*
* Returns 0 if ok, -1 if not ok.
*/
int
__ivaliduser(FILE *hostf, u_int32_t raddr, const char *luser, const char *ruser)
{
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(struct sockaddr_in);
memcpy(&sin.sin_addr, &raddr, sizeof(sin.sin_addr));
return __ivaliduser_sa(hostf, (struct sockaddr *)&sin, sin.sin_len,
luser, ruser);
}
/*
* Returns 0 if ok, -1 if not ok.
*
* XXX obsolete API.
*/
int
__ivaliduser_af(FILE *hostf, const void *raddr, const char *luser,
const char *ruser, int af, int len)
{
struct sockaddr *sa = NULL;
struct sockaddr_in *sin = NULL;
#ifdef INET6
struct sockaddr_in6 *sin6 = NULL;
#endif
struct sockaddr_storage ss;
memset(&ss, 0, sizeof(ss));
switch (af) {
case AF_INET:
if (len != sizeof(sin->sin_addr))
return -1;
sin = (struct sockaddr_in *)&ss;
sin->sin_family = AF_INET;
sin->sin_len = sizeof(struct sockaddr_in);
memcpy(&sin->sin_addr, raddr, sizeof(sin->sin_addr));
break;
#ifdef INET6
case AF_INET6:
if (len != sizeof(sin6->sin6_addr))
return -1;
/* you will lose scope info */
sin6 = (struct sockaddr_in6 *)&ss;
sin6->sin6_family = AF_INET6;
sin6->sin6_len = sizeof(struct sockaddr_in6);
memcpy(&sin6->sin6_addr, raddr, sizeof(sin6->sin6_addr));
break;
#endif
default:
return -1;
}
sa = (struct sockaddr *)&ss;
return __ivaliduser_sa(hostf, sa, sa->sa_len, luser, ruser);
}
int
__ivaliduser_sa(FILE *hostf, const struct sockaddr *raddr, socklen_t salen,
const char *luser, const char *ruser)
{
char *user, *p;
int ch;
char buf[MAXHOSTNAMELEN + 128]; /* host + login */
char hname[MAXHOSTNAMELEN];
/* Presumed guilty until proven innocent. */
int userok = 0, hostok = 0;
#ifdef YP
char *ypdomain;
if (yp_get_default_domain(&ypdomain))
ypdomain = NULL;
#else
#define ypdomain NULL
#endif
/* We need to get the damn hostname back for netgroup matching. */
if (getnameinfo(raddr, salen, hname, sizeof(hname), NULL, 0,
NI_NAMEREQD) != 0)
hname[0] = '\0';
while (fgets(buf, sizeof(buf), hostf)) {
p = buf;
/* Skip lines that are too long. */
if (strchr(p, '\n') == NULL) {
while ((ch = getc(hostf)) != '\n' && ch != EOF);
continue;
}
if (*p == '\n' || *p == '#') {
/* comment... */
continue;
}
while (*p != '\n' && *p != ' ' && *p != '\t' && *p != '\0') {
*p = isupper((unsigned char)*p) ? tolower((unsigned char)*p) : *p;
p++;
}
if (*p == ' ' || *p == '\t') {
*p++ = '\0';
while (*p == ' ' || *p == '\t')
p++;
user = p;
while (*p != '\n' && *p != ' ' &&
*p != '\t' && *p != '\0')
p++;
} else
user = p;
*p = '\0';
/*
* Do +/- and +@/-@ checking. This looks really nasty,
* but it matches SunOS's behavior so far as I can tell.
*/
switch(buf[0]) {
case '+':
if (!buf[1]) { /* '+' matches all hosts */
hostok = 1;
break;
}
if (buf[1] == '@') /* match a host by netgroup */
hostok = hname[0] != '\0' &&
innetgr(&buf[2], hname, NULL, ypdomain);
else /* match a host by addr */
hostok = __icheckhost(raddr, salen,
(char *)&buf[1]);
break;
case '-': /* reject '-' hosts and all their users */
if (buf[1] == '@') {
if (hname[0] == '\0' ||
innetgr(&buf[2], hname, NULL, ypdomain))
return(-1);
} else {
if (__icheckhost(raddr, salen,
(char *)&buf[1]))
return(-1);
}
break;
default: /* if no '+' or '-', do a simple match */
hostok = __icheckhost(raddr, salen, buf);
break;
}
switch(*user) {
case '+':
if (!*(user+1)) { /* '+' matches all users */
userok = 1;
break;
}
if (*(user+1) == '@') /* match a user by netgroup */
userok = innetgr(user+2, NULL, ruser, ypdomain);
else /* match a user by direct specification */
userok = !(strcmp(ruser, user+1));
break;
case '-': /* if we matched a hostname, */
if (hostok) { /* check for user field rejections */
if (!*(user+1))
return(-1);
if (*(user+1) == '@') {
if (innetgr(user+2, NULL,
ruser, ypdomain))
return(-1);
} else {
if (!strcmp(ruser, user+1))
return(-1);
}
}
break;
default: /* no rejections: try to match the user */
if (hostok)
userok = !(strcmp(ruser,*user ? user : luser));
break;
}
if (hostok && userok)
return(0);
}
return (-1);
}
/*
* Returns "true" if match, 0 if no match.
*/
static int
__icheckhost(const struct sockaddr *raddr, socklen_t salen, const char *lhost)
{
struct sockaddr_in sin;
struct sockaddr_in6 *sin6;
struct addrinfo hints, *res, *r;
int error;
char h1[NI_MAXHOST], h2[NI_MAXHOST];
if (raddr->sa_family == AF_INET6) {
sin6 = (struct sockaddr_in6 *)raddr;
if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_len = sizeof(struct sockaddr_in);
memcpy(&sin.sin_addr, &sin6->sin6_addr.s6_addr[12],
sizeof(sin.sin_addr));
raddr = (struct sockaddr *)&sin;
salen = sin.sin_len;
}
}
h1[0] = '\0';
if (getnameinfo(raddr, salen, h1, sizeof(h1), NULL, 0,
NI_NUMERICHOST) != 0)
return (0);
/* Resolve laddr into sockaddr */
memset(&hints, 0, sizeof(hints));
hints.ai_family = raddr->sa_family;
hints.ai_socktype = SOCK_DGRAM; /*XXX dummy*/
res = NULL;
error = getaddrinfo(lhost, "0", &hints, &res);
if (error)
return (0);
for (r = res; r ; r = r->ai_next) {
h2[0] = '\0';
if (getnameinfo(r->ai_addr, r->ai_addrlen, h2, sizeof(h2),
NULL, 0, NI_NUMERICHOST) != 0)
continue;
if (strcmp(h1, h2) == 0) {
freeaddrinfo(res);
return (1);
}
}
/* No match. */
freeaddrinfo(res);
return (0);
}
diff --git a/lib/libc/net/rcmdsh.c b/lib/libc/net/rcmdsh.c
index ceedc51731a3..7e400e99cb3b 100644
--- a/lib/libc/net/rcmdsh.c
+++ b/lib/libc/net/rcmdsh.c
@@ -1,167 +1,166 @@
/* $OpenBSD: rcmdsh.c,v 1.7 2002/03/12 00:05:44 millert Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2001, MagniComp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* 3. Neither the name of the MagniComp nor the names of its contributors may
* be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* This is an rcmd() replacement originally by
* Chris Siebenmann <cks@utcc.utoronto.ca>.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
/*
* This is a replacement rcmd() function that uses the rsh(1)
* program in place of a direct rcmd(3) function call so as to
* avoid having to be root. Note that rport is ignored.
*/
int
rcmdsh(char **ahost, int rport, const char *locuser, const char *remuser,
const char *cmd, const char *rshprog)
{
struct addrinfo hints, *res;
int sp[2], error;
pid_t cpid;
char *p;
struct passwd *pw;
char num[8];
static char hbuf[NI_MAXHOST];
/* What rsh/shell to use. */
if (rshprog == NULL)
rshprog = _PATH_RSH;
/* locuser must exist on this host. */
if ((pw = getpwnam(locuser)) == NULL) {
(void)fprintf(stderr, "rcmdsh: unknown user: %s\n", locuser);
return (-1);
}
/* Validate remote hostname. */
if (strcmp(*ahost, "localhost") != 0) {
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME;
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
(void)snprintf(num, sizeof(num), "%u",
(unsigned int)ntohs(rport));
error = getaddrinfo(*ahost, num, &hints, &res);
if (error) {
fprintf(stderr, "rcmdsh: getaddrinfo: %s\n",
gai_strerror(error));
return (-1);
}
if (res->ai_canonname) {
strncpy(hbuf, res->ai_canonname, sizeof(hbuf) - 1);
hbuf[sizeof(hbuf) - 1] = '\0';
*ahost = hbuf;
}
freeaddrinfo(res);
}
/* Get a socketpair we'll use for stdin and stdout. */
if (_socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) == -1) {
perror("rcmdsh: socketpair");
return (-1);
}
cpid = fork();
if (cpid == -1) {
perror("rcmdsh: fork failed");
return (-1);
} else if (cpid == 0) {
/*
* Child. We use sp[1] to be stdin/stdout, and close sp[0].
*/
(void)_close(sp[0]);
if (_dup2(sp[1], 0) == -1 || _dup2(0, 1) == -1) {
perror("rcmdsh: dup2 failed");
_exit(255);
}
/* Fork again to lose parent. */
cpid = fork();
if (cpid == -1) {
perror("rcmdsh: fork to lose parent failed");
_exit(255);
}
if (cpid > 0)
_exit(0);
/* In grandchild here. Become local user for rshprog. */
if (setuid(pw->pw_uid) == -1) {
(void)fprintf(stderr, "rcmdsh: setuid(%u): %s\n",
pw->pw_uid, strerror(errno));
_exit(255);
}
/*
* If remote host is "localhost" and local and remote users
* are the same, avoid running remote shell for efficiency.
*/
if (strcmp(*ahost, "localhost") == 0 &&
strcmp(locuser, remuser) == 0) {
if (pw->pw_shell[0] == '\0')
rshprog = _PATH_BSHELL;
else
rshprog = pw->pw_shell;
p = strrchr(rshprog, '/');
execlp(rshprog, p ? p + 1 : rshprog, "-c", cmd,
(char *)NULL);
} else {
p = strrchr(rshprog, '/');
execlp(rshprog, p ? p + 1 : rshprog, *ahost, "-l",
remuser, cmd, (char *)NULL);
}
(void)fprintf(stderr, "rcmdsh: execlp %s failed: %s\n",
rshprog, strerror(errno));
_exit(255);
} else {
/* Parent. close sp[1], return sp[0]. */
(void)_close(sp[1]);
/* Reap child. */
(void)_waitpid(cpid, NULL, 0);
return (sp[0]);
}
/* NOTREACHED */
}
diff --git a/lib/libc/net/recv.c b/lib/libc/net/recv.c
index bf321f3d522d..dd6c6b950b8c 100644
--- a/lib/libc/net/recv.c
+++ b/lib/libc/net/recv.c
@@ -1,53 +1,52 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)recv.c 8.2 (Berkeley) 2/21/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "libc_private.h"
#include <stddef.h>
ssize_t
recv(int s, void *buf, size_t len, int flags)
{
/*
* POSIX says recv() shall be a cancellation point, so call the
* cancellation-enabled recvfrom() and not _recvfrom().
*/
return (((ssize_t (*)(int, void *, size_t, int,
struct sockaddr *, socklen_t *))
__libc_interposing[INTERPOS_recvfrom])(s, buf, len, flags,
NULL, NULL));
}
diff --git a/lib/libc/net/rthdr.c b/lib/libc/net/rthdr.c
index 0a2e70cf4914..0698a3f7712e 100644
--- a/lib/libc/net/rthdr.c
+++ b/lib/libc/net/rthdr.c
@@ -1,434 +1,433 @@
/* $KAME: rthdr.c,v 1.19 2003/06/06 10:48:51 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip6.h>
#include <string.h>
#include <stdio.h>
/*
* RFC2292 API
*/
size_t
inet6_rthdr_space(int type, int seg)
{
switch (type) {
case IPV6_RTHDR_TYPE_0:
if (seg < 1 || seg > 23)
return (0);
#ifdef COMPAT_RFC2292
return (CMSG_SPACE(sizeof(struct in6_addr) * (seg - 1) +
sizeof(struct ip6_rthdr0)));
#else
return (CMSG_SPACE(sizeof(struct in6_addr) * seg +
sizeof(struct ip6_rthdr0)));
#endif
default:
return (0);
}
}
struct cmsghdr *
inet6_rthdr_init(void *bp, int type)
{
struct cmsghdr *ch = (struct cmsghdr *)bp;
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(ch);
ch->cmsg_level = IPPROTO_IPV6;
ch->cmsg_type = IPV6_RTHDR;
switch (type) {
case IPV6_RTHDR_TYPE_0:
#ifdef COMPAT_RFC2292
ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0) -
sizeof(struct in6_addr));
#else
ch->cmsg_len = CMSG_LEN(sizeof(struct ip6_rthdr0));
#endif
bzero(rthdr, sizeof(struct ip6_rthdr0));
rthdr->ip6r_type = IPV6_RTHDR_TYPE_0;
return (ch);
default:
return (NULL);
}
}
/* ARGSUSED */
int
inet6_rthdr_add(struct cmsghdr *cmsg, const struct in6_addr *addr, u_int flags)
{
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch (rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
return (-1);
if (rt0->ip6r0_segleft == 23)
return (-1);
#ifdef COMPAT_RFC1883 /* XXX */
if (flags == IPV6_RTHDR_STRICT) {
int c, b;
c = rt0->ip6r0_segleft / 8;
b = rt0->ip6r0_segleft % 8;
rt0->ip6r0_slmap[c] |= (1 << (7 - b));
}
#else
if (flags != IPV6_RTHDR_LOOSE)
return (-1);
#endif
rt0->ip6r0_segleft++;
bcopy(addr, (caddr_t)rt0 + ((rt0->ip6r0_len + 1) << 3),
sizeof(struct in6_addr));
rt0->ip6r0_len += sizeof(struct in6_addr) >> 3;
cmsg->cmsg_len = CMSG_LEN((rt0->ip6r0_len + 1) << 3);
break;
}
default:
return (-1);
}
return (0);
}
/* ARGSUSED */
int
inet6_rthdr_lasthop(struct cmsghdr *cmsg, unsigned int flags)
{
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch (rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
#ifdef COMPAT_RFC1883 /* XXX */
if (flags != IPV6_RTHDR_LOOSE && flags != IPV6_RTHDR_STRICT)
return (-1);
#endif /* COMPAT_RFC1883 */
if (rt0->ip6r0_segleft > 23)
return (-1);
#ifdef COMPAT_RFC1883 /* XXX */
if (flags == IPV6_RTHDR_STRICT) {
int c, b;
c = rt0->ip6r0_segleft / 8;
b = rt0->ip6r0_segleft % 8;
rt0->ip6r0_slmap[c] |= (1 << (7 - b));
}
#else
if (flags != IPV6_RTHDR_LOOSE)
return (-1);
#endif /* COMPAT_RFC1883 */
break;
}
default:
return (-1);
}
return (0);
}
#if 0
int
inet6_rthdr_reverse(const struct cmsghdr *in, struct cmsghdr *out)
{
return (-1);
}
#endif
int
inet6_rthdr_segments(const struct cmsghdr *cmsg)
{
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch (rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
return (-1);
return (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
}
default:
return (-1);
}
}
struct in6_addr *
inet6_rthdr_getaddr(struct cmsghdr *cmsg, int idx)
{
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch (rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
int naddr;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
return NULL;
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (idx <= 0 || naddr < idx)
return NULL;
#ifdef COMPAT_RFC2292
return (((struct in6_addr *)(rt0 + 1)) + idx - 1);
#else
return (((struct in6_addr *)(rt0 + 1)) + idx);
#endif
}
default:
return NULL;
}
}
int
inet6_rthdr_getflags(const struct cmsghdr *cmsg, int idx)
{
struct ip6_rthdr *rthdr;
rthdr = (struct ip6_rthdr *)CMSG_DATA(cmsg);
switch (rthdr->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
{
struct ip6_rthdr0 *rt0 = (struct ip6_rthdr0 *)rthdr;
int naddr;
if (rt0->ip6r0_len % 2 || 46 < rt0->ip6r0_len)
return (-1);
naddr = (rt0->ip6r0_len * 8) / sizeof(struct in6_addr);
if (idx < 0 || naddr < idx)
return (-1);
#ifdef COMPAT_RFC1883 /* XXX */
if (rt0->ip6r0_slmap[idx / 8] & (0x80 >> (idx % 8)))
return IPV6_RTHDR_STRICT;
else
return IPV6_RTHDR_LOOSE;
#else
return IPV6_RTHDR_LOOSE;
#endif /* COMPAT_RFC1883 */
}
default:
return (-1);
}
}
/*
* RFC3542 API
*/
socklen_t
inet6_rth_space(int type, int segments)
{
switch (type) {
case IPV6_RTHDR_TYPE_0:
if ((segments >= 0) && (segments <= 127))
return (((segments * 2) + 1) << 3);
/* FALLTHROUGH */
default:
return (0); /* type not supported */
}
}
void *
inet6_rth_init(void *bp, socklen_t bp_len, int type, int segments)
{
struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rth0;
switch (type) {
case IPV6_RTHDR_TYPE_0:
/* length validation */
if (bp_len < inet6_rth_space(IPV6_RTHDR_TYPE_0, segments))
return (NULL);
/* segment validation */
if ((segments < 0) || (segments > 127))
return (NULL);
memset(bp, 0, bp_len);
rth0 = (struct ip6_rthdr0 *)rth;
rth0->ip6r0_len = segments * 2;
rth0->ip6r0_type = IPV6_RTHDR_TYPE_0;
rth0->ip6r0_segleft = 0;
rth0->ip6r0_reserved = 0;
break;
default:
return (NULL); /* type not supported */
}
return (bp);
}
int
inet6_rth_add(void *bp, const struct in6_addr *addr)
{
struct ip6_rthdr *rth = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rth0;
struct in6_addr *nextaddr;
switch (rth->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rth0 = (struct ip6_rthdr0 *)rth;
/* Don't exceed the number of stated segments */
if (rth0->ip6r0_segleft == (rth0->ip6r0_len / 2))
return (-1);
nextaddr = (struct in6_addr *)(rth0 + 1) + rth0->ip6r0_segleft;
*nextaddr = *addr;
rth0->ip6r0_segleft++;
break;
default:
return (-1); /* type not supported */
}
return (0);
}
int
inet6_rth_reverse(const void *in, void *out)
{
struct ip6_rthdr *rth_in = (struct ip6_rthdr *)in;
struct ip6_rthdr0 *rth0_in, *rth0_out;
int i, segments;
switch (rth_in->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rth0_in = (struct ip6_rthdr0 *)in;
rth0_out = (struct ip6_rthdr0 *)out;
/* parameter validation XXX too paranoid? */
if (rth0_in->ip6r0_len % 2)
return (-1);
segments = rth0_in->ip6r0_len / 2;
/* we can't use memcpy here, since in and out may overlap */
memmove((void *)rth0_out, (void *)rth0_in,
((rth0_in->ip6r0_len) + 1) << 3);
rth0_out->ip6r0_segleft = segments;
/* reverse the addresses */
for (i = 0; i < segments / 2; i++) {
struct in6_addr addr_tmp, *addr1, *addr2;
addr1 = (struct in6_addr *)(rth0_out + 1) + i;
addr2 = (struct in6_addr *)(rth0_out + 1) +
(segments - i - 1);
addr_tmp = *addr1;
*addr1 = *addr2;
*addr2 = addr_tmp;
}
break;
default:
return (-1); /* type not supported */
}
return (0);
}
int
inet6_rth_segments(const void *bp)
{
struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rh0;
int addrs;
switch (rh->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rh0 = (struct ip6_rthdr0 *)bp;
/*
* Validation for a type-0 routing header.
* Is this too strict?
*/
if ((rh0->ip6r0_len % 2) != 0 ||
(addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
return (-1);
return (addrs);
default:
return (-1); /* unknown type */
}
}
struct in6_addr *
inet6_rth_getaddr(const void *bp, int idx)
{
struct ip6_rthdr *rh = (struct ip6_rthdr *)bp;
struct ip6_rthdr0 *rh0;
int addrs;
switch (rh->ip6r_type) {
case IPV6_RTHDR_TYPE_0:
rh0 = (struct ip6_rthdr0 *)bp;
/*
* Validation for a type-0 routing header.
* Is this too strict?
*/
if ((rh0->ip6r0_len % 2) != 0 ||
(addrs = (rh0->ip6r0_len >> 1)) < rh0->ip6r0_segleft)
return (NULL);
if (idx < 0 || addrs <= idx)
return (NULL);
return (((struct in6_addr *)(rh0 + 1)) + idx);
default:
return (NULL); /* unknown type */
break;
}
}
diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c
index ee0de3b95691..5cb26266c888 100644
--- a/lib/libc/net/sctp_sys_calls.c
+++ b/lib/libc/net/sctp_sys_calls.c
@@ -1,1196 +1,1195 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2001-2007, by Cisco Systems, Inc. All rights reserved.
* Copyright (c) 2008-2012, by Randall Stewart. All rights reserved.
* Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* a) Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* b) Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
*
* c) Neither the name of Cisco Systems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/errno.h>
#include <sys/syscall.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/sctp_uio.h>
#include <netinet/sctp.h>
#ifndef IN6_IS_ADDR_V4MAPPED
#define IN6_IS_ADDR_V4MAPPED(a) \
((*(const uint32_t *)(const void *)(&(a)->s6_addr[0]) == 0) && \
(*(const uint32_t *)(const void *)(&(a)->s6_addr[4]) == 0) && \
(*(const uint32_t *)(const void *)(&(a)->s6_addr[8]) == ntohl(0x0000ffff)))
#endif
#define SCTP_CONTROL_VEC_SIZE_RCV 16384
static void
in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6)
{
bzero(sin, sizeof(*sin));
sin->sin_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET;
sin->sin_port = sin6->sin6_port;
sin->sin_addr.s_addr = sin6->sin6_addr.__u6_addr.__u6_addr32[3];
}
int
sctp_getaddrlen(sa_family_t family)
{
int ret, sd;
socklen_t siz;
struct sctp_assoc_value av;
av.assoc_value = family;
siz = sizeof(av);
#if defined(AF_INET)
sd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP);
#elif defined(AF_INET6)
sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP);
#else
sd = -1;
#endif
if (sd == -1) {
return (-1);
}
ret = getsockopt(sd, IPPROTO_SCTP, SCTP_GET_ADDR_LEN, &av, &siz);
close(sd);
if (ret == 0) {
return ((int)av.assoc_value);
} else {
return (-1);
}
}
int
sctp_connectx(int sd, const struct sockaddr *addrs, int addrcnt,
sctp_assoc_t *id)
{
char *buf;
int i, ret, *aa;
char *cpto;
const struct sockaddr *at;
size_t len;
/* validate the address count and list */
if ((addrs == NULL) || (addrcnt <= 0)) {
errno = EINVAL;
return (-1);
}
if ((buf = malloc(sizeof(int) + (size_t)addrcnt * sizeof(struct sockaddr_in6))) == NULL) {
errno = E2BIG;
return (-1);
}
len = sizeof(int);
at = addrs;
cpto = buf + sizeof(int);
/* validate all the addresses and get the size */
for (i = 0; i < addrcnt; i++) {
switch (at->sa_family) {
case AF_INET:
if (at->sa_len != sizeof(struct sockaddr_in)) {
free(buf);
errno = EINVAL;
return (-1);
}
memcpy(cpto, at, sizeof(struct sockaddr_in));
cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
len += sizeof(struct sockaddr_in);
break;
case AF_INET6:
if (at->sa_len != sizeof(struct sockaddr_in6)) {
free(buf);
errno = EINVAL;
return (-1);
}
if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) {
in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at);
cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
len += sizeof(struct sockaddr_in);
} else {
memcpy(cpto, at, sizeof(struct sockaddr_in6));
cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6));
len += sizeof(struct sockaddr_in6);
}
break;
default:
free(buf);
errno = EINVAL;
return (-1);
}
at = (struct sockaddr *)((caddr_t)at + at->sa_len);
}
aa = (int *)buf;
*aa = addrcnt;
ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf,
(socklen_t)len);
if ((ret == 0) && (id != NULL)) {
*id = *(sctp_assoc_t *)buf;
}
free(buf);
return (ret);
}
int
sctp_bindx(int sd, struct sockaddr *addrs, int addrcnt, int flags)
{
struct sockaddr *sa;
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6;
int i;
uint16_t sport;
bool fix_port;
/* validate the flags */
if ((flags != SCTP_BINDX_ADD_ADDR) &&
(flags != SCTP_BINDX_REM_ADDR)) {
errno = EFAULT;
return (-1);
}
/* validate the address count and list */
if ((addrcnt <= 0) || (addrs == NULL)) {
errno = EINVAL;
return (-1);
}
sport = 0;
fix_port = false;
/* First pre-screen the addresses */
sa = addrs;
for (i = 0; i < addrcnt; i++) {
switch (sa->sa_family) {
case AF_INET:
if (sa->sa_len != sizeof(struct sockaddr_in)) {
errno = EINVAL;
return (-1);
}
sin = (struct sockaddr_in *)sa;
if (sin->sin_port) {
/* non-zero port, check or save */
if (sport) {
/* Check against our port */
if (sport != sin->sin_port) {
errno = EINVAL;
return (-1);
}
} else {
/* save off the port */
sport = sin->sin_port;
fix_port = (i > 0);
}
}
break;
case AF_INET6:
if (sa->sa_len != sizeof(struct sockaddr_in6)) {
errno = EINVAL;
return (-1);
}
sin6 = (struct sockaddr_in6 *)sa;
if (sin6->sin6_port) {
/* non-zero port, check or save */
if (sport) {
/* Check against our port */
if (sport != sin6->sin6_port) {
errno = EINVAL;
return (-1);
}
} else {
/* save off the port */
sport = sin6->sin6_port;
fix_port = (i > 0);
}
}
break;
default:
/* Invalid address family specified. */
errno = EAFNOSUPPORT;
return (-1);
}
sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
}
sa = addrs;
for (i = 0; i < addrcnt; i++) {
/*
* Now, if there was a port mentioned, assure that the first
* address has that port to make sure it fails or succeeds
* correctly.
*/
if (fix_port) {
switch (sa->sa_family) {
case AF_INET:
((struct sockaddr_in *)sa)->sin_port = sport;
break;
case AF_INET6:
((struct sockaddr_in6 *)sa)->sin6_port = sport;
break;
}
fix_port = false;
}
if (setsockopt(sd, IPPROTO_SCTP, flags, sa, sa->sa_len) != 0) {
return (-1);
}
sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
}
return (0);
}
int
sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t *size)
{
if (arg == NULL) {
errno = EINVAL;
return (-1);
}
if ((id == SCTP_CURRENT_ASSOC) ||
(id == SCTP_ALL_ASSOC)) {
errno = EINVAL;
return (-1);
}
switch (opt) {
case SCTP_RTOINFO:
((struct sctp_rtoinfo *)arg)->srto_assoc_id = id;
break;
case SCTP_ASSOCINFO:
((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
break;
case SCTP_DEFAULT_SEND_PARAM:
((struct sctp_assocparams *)arg)->sasoc_assoc_id = id;
break;
case SCTP_PRIMARY_ADDR:
((struct sctp_setprim *)arg)->ssp_assoc_id = id;
break;
case SCTP_PEER_ADDR_PARAMS:
((struct sctp_paddrparams *)arg)->spp_assoc_id = id;
break;
case SCTP_MAXSEG:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_AUTH_KEY:
((struct sctp_authkey *)arg)->sca_assoc_id = id;
break;
case SCTP_AUTH_ACTIVE_KEY:
((struct sctp_authkeyid *)arg)->scact_assoc_id = id;
break;
case SCTP_DELAYED_SACK:
((struct sctp_sack_info *)arg)->sack_assoc_id = id;
break;
case SCTP_CONTEXT:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_STATUS:
((struct sctp_status *)arg)->sstat_assoc_id = id;
break;
case SCTP_GET_PEER_ADDR_INFO:
((struct sctp_paddrinfo *)arg)->spinfo_assoc_id = id;
break;
case SCTP_PEER_AUTH_CHUNKS:
((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
break;
case SCTP_LOCAL_AUTH_CHUNKS:
((struct sctp_authchunks *)arg)->gauth_assoc_id = id;
break;
case SCTP_TIMEOUTS:
((struct sctp_timeouts *)arg)->stimo_assoc_id = id;
break;
case SCTP_EVENT:
((struct sctp_event *)arg)->se_assoc_id = id;
break;
case SCTP_DEFAULT_SNDINFO:
((struct sctp_sndinfo *)arg)->snd_assoc_id = id;
break;
case SCTP_DEFAULT_PRINFO:
((struct sctp_default_prinfo *)arg)->pr_assoc_id = id;
break;
case SCTP_PEER_ADDR_THLDS:
((struct sctp_paddrthlds *)arg)->spt_assoc_id = id;
break;
case SCTP_REMOTE_UDP_ENCAPS_PORT:
((struct sctp_udpencaps *)arg)->sue_assoc_id = id;
break;
case SCTP_ECN_SUPPORTED:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_PR_SUPPORTED:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_AUTH_SUPPORTED:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_ASCONF_SUPPORTED:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_RECONFIG_SUPPORTED:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_NRSACK_SUPPORTED:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_PKTDROP_SUPPORTED:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_MAX_BURST:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_ENABLE_STREAM_RESET:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_PR_STREAM_STATUS:
((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
break;
case SCTP_PR_ASSOC_STATUS:
((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
break;
case SCTP_MAX_CWND:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
default:
break;
}
return (getsockopt(sd, IPPROTO_SCTP, opt, arg, size));
}
int
sctp_getpaddrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
{
struct sctp_getaddresses *addrs;
struct sockaddr *sa;
caddr_t lim;
socklen_t opt_len;
uint32_t size_of_addresses;
int cnt;
if (raddrs == NULL) {
errno = EFAULT;
return (-1);
}
/* When calling getsockopt(), the value contains the assoc_id. */
size_of_addresses = (uint32_t)id;
opt_len = (socklen_t)sizeof(uint32_t);
if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE,
&size_of_addresses, &opt_len) != 0) {
if (errno == ENOENT) {
return (0);
} else {
return (-1);
}
}
opt_len = (socklen_t)((size_t)size_of_addresses + sizeof(struct sctp_getaddresses));
addrs = calloc(1, (size_t)opt_len);
if (addrs == NULL) {
errno = ENOMEM;
return (-1);
}
addrs->sget_assoc_id = id;
/* Now lets get the array of addresses */
if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES,
addrs, &opt_len) != 0) {
free(addrs);
return (-1);
}
*raddrs = &addrs->addr[0].sa;
cnt = 0;
sa = &addrs->addr[0].sa;
lim = (caddr_t)addrs + opt_len;
while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
cnt++;
}
return (cnt);
}
void
sctp_freepaddrs(struct sockaddr *addrs)
{
void *fr_addr;
/* Take away the hidden association id */
fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr));
/* Now free it */
free(fr_addr);
}
int
sctp_getladdrs(int sd, sctp_assoc_t id, struct sockaddr **raddrs)
{
struct sctp_getaddresses *addrs;
struct sockaddr *sa;
caddr_t lim;
socklen_t opt_len;
uint32_t size_of_addresses;
int cnt;
if (raddrs == NULL) {
errno = EFAULT;
return (-1);
}
size_of_addresses = 0;
opt_len = (socklen_t)sizeof(uint32_t);
if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE,
&size_of_addresses, &opt_len) != 0) {
return (-1);
}
opt_len = (socklen_t)((size_t)size_of_addresses + sizeof(struct sctp_getaddresses));
addrs = calloc(1, (size_t)opt_len);
if (addrs == NULL) {
errno = ENOMEM;
return (-1);
}
addrs->sget_assoc_id = id;
/* Now lets get the array of addresses */
if (getsockopt(sd, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs,
&opt_len) != 0) {
free(addrs);
return (-1);
}
if (size_of_addresses == 0) {
free(addrs);
return (0);
}
*raddrs = &addrs->addr[0].sa;
cnt = 0;
sa = &addrs->addr[0].sa;
lim = (caddr_t)addrs + opt_len;
while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
cnt++;
}
return (cnt);
}
void
sctp_freeladdrs(struct sockaddr *addrs)
{
void *fr_addr;
/* Take away the hidden association id */
fr_addr = (void *)((caddr_t)addrs - offsetof(struct sctp_getaddresses, addr));
/* Now free it */
free(fr_addr);
}
ssize_t
sctp_sendmsg(int s,
const void *data,
size_t len,
const struct sockaddr *to,
socklen_t tolen,
uint32_t ppid,
uint32_t flags,
uint16_t stream_no,
uint32_t timetolive,
uint32_t context)
{
#ifdef SYS_sctp_generic_sendmsg
struct sctp_sndrcvinfo sinfo;
memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
sinfo.sinfo_ppid = ppid;
sinfo.sinfo_flags = flags;
sinfo.sinfo_stream = stream_no;
sinfo.sinfo_timetolive = timetolive;
sinfo.sinfo_context = context;
sinfo.sinfo_assoc_id = 0;
return (syscall(SYS_sctp_generic_sendmsg, s,
data, len, to, tolen, &sinfo, 0));
#else
struct msghdr msg;
struct sctp_sndrcvinfo *sinfo;
struct iovec iov;
char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
struct cmsghdr *cmsg;
struct sockaddr *who = NULL;
union {
struct sockaddr_in in;
struct sockaddr_in6 in6;
} addr;
if ((tolen > 0) &&
((to == NULL) || (tolen < sizeof(struct sockaddr)))) {
errno = EINVAL;
return (-1);
}
if ((to != NULL) && (tolen > 0)) {
switch (to->sa_family) {
case AF_INET:
if (tolen != sizeof(struct sockaddr_in)) {
errno = EINVAL;
return (-1);
}
if ((to->sa_len > 0) &&
(to->sa_len != sizeof(struct sockaddr_in))) {
errno = EINVAL;
return (-1);
}
memcpy(&addr, to, sizeof(struct sockaddr_in));
addr.in.sin_len = sizeof(struct sockaddr_in);
break;
case AF_INET6:
if (tolen != sizeof(struct sockaddr_in6)) {
errno = EINVAL;
return (-1);
}
if ((to->sa_len > 0) &&
(to->sa_len != sizeof(struct sockaddr_in6))) {
errno = EINVAL;
return (-1);
}
memcpy(&addr, to, sizeof(struct sockaddr_in6));
addr.in6.sin6_len = sizeof(struct sockaddr_in6);
break;
default:
errno = EAFNOSUPPORT;
return (-1);
}
who = (struct sockaddr *)&addr;
}
iov.iov_base = (char *)data;
iov.iov_len = len;
if (who) {
msg.msg_name = (caddr_t)who;
msg.msg_namelen = who->sa_len;
} else {
msg.msg_name = (caddr_t)NULL;
msg.msg_namelen = 0;
}
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
msg.msg_flags = 0;
cmsg = (struct cmsghdr *)cmsgbuf;
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_SNDRCV;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
sinfo->sinfo_stream = stream_no;
sinfo->sinfo_ssn = 0;
sinfo->sinfo_flags = flags;
sinfo->sinfo_ppid = ppid;
sinfo->sinfo_context = context;
sinfo->sinfo_assoc_id = 0;
sinfo->sinfo_timetolive = timetolive;
return (sendmsg(s, &msg, 0));
#endif
}
sctp_assoc_t
sctp_getassocid(int sd, struct sockaddr *sa)
{
struct sctp_paddrinfo sp;
socklen_t siz;
/* First get the assoc id */
siz = sizeof(sp);
memset(&sp, 0, sizeof(sp));
memcpy((caddr_t)&sp.spinfo_address, sa, sa->sa_len);
if (getsockopt(sd, IPPROTO_SCTP,
SCTP_GET_PEER_ADDR_INFO, &sp, &siz) != 0) {
/* We depend on the fact that 0 can never be returned */
return ((sctp_assoc_t)0);
}
return (sp.spinfo_assoc_id);
}
ssize_t
sctp_send(int sd, const void *data, size_t len,
const struct sctp_sndrcvinfo *sinfo,
int flags)
{
#ifdef SYS_sctp_generic_sendmsg
struct sockaddr *to = NULL;
return (syscall(SYS_sctp_generic_sendmsg, sd,
data, len, to, 0, sinfo, flags));
#else
struct msghdr msg;
struct iovec iov;
char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))];
struct cmsghdr *cmsg;
if (sinfo == NULL) {
errno = EINVAL;
return (-1);
}
iov.iov_base = (char *)data;
iov.iov_len = len;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = CMSG_SPACE(sizeof(struct sctp_sndrcvinfo));
msg.msg_flags = 0;
cmsg = (struct cmsghdr *)cmsgbuf;
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_SNDRCV;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
memcpy(CMSG_DATA(cmsg), sinfo, sizeof(struct sctp_sndrcvinfo));
return (sendmsg(sd, &msg, flags));
#endif
}
ssize_t
sctp_sendx(int sd, const void *msg, size_t msg_len,
struct sockaddr *addrs, int addrcnt,
struct sctp_sndrcvinfo *sinfo,
int flags)
{
struct sctp_sndrcvinfo __sinfo;
ssize_t ret;
int i, cnt, *aa, saved_errno;
char *buf;
int no_end_cx = 0;
size_t len, add_len;
struct sockaddr *at;
if (addrs == NULL) {
errno = EINVAL;
return (-1);
}
#ifdef SYS_sctp_generic_sendmsg
if (addrcnt == 1) {
socklen_t l;
ssize_t ret;
/*
* Quick way, we don't need to do a connectx so lets use the
* syscall directly.
*/
l = addrs->sa_len;
ret = syscall(SYS_sctp_generic_sendmsg, sd,
msg, msg_len, addrs, l, sinfo, flags);
if ((ret >= 0) && (sinfo != NULL)) {
sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
}
return (ret);
}
#endif
len = sizeof(int);
at = addrs;
cnt = 0;
/* validate all the addresses and get the size */
for (i = 0; i < addrcnt; i++) {
if (at->sa_family == AF_INET) {
add_len = sizeof(struct sockaddr_in);
} else if (at->sa_family == AF_INET6) {
add_len = sizeof(struct sockaddr_in6);
} else {
errno = EINVAL;
return (-1);
}
len += add_len;
at = (struct sockaddr *)((caddr_t)at + add_len);
cnt++;
}
/* do we have any? */
if (cnt == 0) {
errno = EINVAL;
return (-1);
}
buf = malloc(len);
if (buf == NULL) {
errno = ENOMEM;
return (-1);
}
aa = (int *)buf;
*aa = cnt;
aa++;
memcpy((caddr_t)aa, addrs, (size_t)(len - sizeof(int)));
ret = setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_DELAYED, (void *)buf,
(socklen_t)len);
free(buf);
if (ret != 0) {
if (errno == EALREADY) {
no_end_cx = 1;
goto continue_send;
}
return (ret);
}
continue_send:
if (sinfo == NULL) {
sinfo = &__sinfo;
memset(&__sinfo, 0, sizeof(__sinfo));
}
sinfo->sinfo_assoc_id = sctp_getassocid(sd, addrs);
if (sinfo->sinfo_assoc_id == 0) {
(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
(socklen_t)addrs->sa_len);
errno = ENOENT;
return (-1);
}
ret = sctp_send(sd, msg, msg_len, sinfo, flags);
saved_errno = errno;
if (no_end_cx == 0)
(void)setsockopt(sd, IPPROTO_SCTP, SCTP_CONNECT_X_COMPLETE, (void *)addrs,
(socklen_t)addrs->sa_len);
errno = saved_errno;
return (ret);
}
ssize_t
sctp_sendmsgx(int sd,
const void *msg,
size_t len,
struct sockaddr *addrs,
int addrcnt,
uint32_t ppid,
uint32_t flags,
uint16_t stream_no,
uint32_t timetolive,
uint32_t context)
{
struct sctp_sndrcvinfo sinfo;
memset((void *)&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
sinfo.sinfo_ppid = ppid;
sinfo.sinfo_flags = flags;
sinfo.sinfo_stream = stream_no;
sinfo.sinfo_timetolive = timetolive;
sinfo.sinfo_context = context;
return (sctp_sendx(sd, msg, len, addrs, addrcnt, &sinfo, 0));
}
ssize_t
sctp_recvmsg(int s,
void *dbuf,
size_t len,
struct sockaddr *from,
socklen_t *fromlen,
struct sctp_sndrcvinfo *sinfo,
int *msg_flags)
{
#ifdef SYS_sctp_generic_recvmsg
struct iovec iov;
iov.iov_base = dbuf;
iov.iov_len = len;
return (syscall(SYS_sctp_generic_recvmsg, s,
&iov, 1, from, fromlen, sinfo, msg_flags));
#else
ssize_t sz;
struct msghdr msg;
struct iovec iov;
char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
struct cmsghdr *cmsg;
if (msg_flags == NULL) {
errno = EINVAL;
return (-1);
}
iov.iov_base = dbuf;
iov.iov_len = len;
msg.msg_name = (caddr_t)from;
if (fromlen == NULL)
msg.msg_namelen = 0;
else
msg.msg_namelen = *fromlen;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
msg.msg_flags = 0;
sz = recvmsg(s, &msg, *msg_flags);
*msg_flags = msg.msg_flags;
if (sz <= 0) {
return (sz);
}
if (sinfo) {
sinfo->sinfo_assoc_id = 0;
}
if ((msg.msg_controllen > 0) && (sinfo != NULL)) {
/*
* parse through and see if we find the sctp_sndrcvinfo (if
* the user wants it).
*/
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != IPPROTO_SCTP) {
continue;
}
if (cmsg->cmsg_type == SCTP_SNDRCV) {
memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_sndrcvinfo));
break;
}
if (cmsg->cmsg_type == SCTP_EXTRCV) {
/*
* Let's hope that the user provided enough
* enough memory. At least he asked for more
* information.
*/
memcpy(sinfo, CMSG_DATA(cmsg), sizeof(struct sctp_extrcvinfo));
break;
}
}
}
return (sz);
#endif
}
ssize_t
sctp_recvv(int sd,
const struct iovec *iov,
int iovlen,
struct sockaddr *from,
socklen_t *fromlen,
void *info,
socklen_t *infolen,
unsigned int *infotype,
int *flags)
{
char cmsgbuf[SCTP_CONTROL_VEC_SIZE_RCV];
struct msghdr msg;
struct cmsghdr *cmsg;
ssize_t ret;
struct sctp_rcvinfo *rcvinfo;
struct sctp_nxtinfo *nxtinfo;
if (((info != NULL) && (infolen == NULL)) ||
((info == NULL) && (infolen != NULL) && (*infolen != 0)) ||
((info != NULL) && (infotype == NULL))) {
errno = EINVAL;
return (-1);
}
if (infotype) {
*infotype = SCTP_RECVV_NOINFO;
}
msg.msg_name = from;
if (fromlen == NULL) {
msg.msg_namelen = 0;
} else {
msg.msg_namelen = *fromlen;
}
msg.msg_iov = (struct iovec *)iov;
msg.msg_iovlen = iovlen;
msg.msg_control = cmsgbuf;
msg.msg_controllen = sizeof(cmsgbuf);
msg.msg_flags = 0;
ret = recvmsg(sd, &msg, *flags);
*flags = msg.msg_flags;
if ((ret > 0) &&
(msg.msg_controllen > 0) &&
(infotype != NULL) &&
(infolen != NULL) &&
(*infolen > 0)) {
rcvinfo = NULL;
nxtinfo = NULL;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level != IPPROTO_SCTP) {
continue;
}
if (cmsg->cmsg_type == SCTP_RCVINFO) {
rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg);
if (nxtinfo != NULL) {
break;
} else {
continue;
}
}
if (cmsg->cmsg_type == SCTP_NXTINFO) {
nxtinfo = (struct sctp_nxtinfo *)CMSG_DATA(cmsg);
if (rcvinfo != NULL) {
break;
} else {
continue;
}
}
}
if (rcvinfo != NULL) {
if ((nxtinfo != NULL) && (*infolen >= sizeof(struct sctp_recvv_rn))) {
struct sctp_recvv_rn *rn_info;
rn_info = (struct sctp_recvv_rn *)info;
rn_info->recvv_rcvinfo = *rcvinfo;
rn_info->recvv_nxtinfo = *nxtinfo;
*infolen = (socklen_t)sizeof(struct sctp_recvv_rn);
*infotype = SCTP_RECVV_RN;
} else if (*infolen >= sizeof(struct sctp_rcvinfo)) {
memcpy(info, rcvinfo, sizeof(struct sctp_rcvinfo));
*infolen = (socklen_t)sizeof(struct sctp_rcvinfo);
*infotype = SCTP_RECVV_RCVINFO;
}
} else if (nxtinfo != NULL) {
if (*infolen >= sizeof(struct sctp_nxtinfo)) {
memcpy(info, nxtinfo, sizeof(struct sctp_nxtinfo));
*infolen = (socklen_t)sizeof(struct sctp_nxtinfo);
*infotype = SCTP_RECVV_NXTINFO;
}
}
}
return (ret);
}
ssize_t
sctp_sendv(int sd,
const struct iovec *iov, int iovcnt,
struct sockaddr *addrs, int addrcnt,
void *info, socklen_t infolen, unsigned int infotype,
int flags)
{
ssize_t ret;
int i;
socklen_t addr_len;
struct msghdr msg;
in_port_t port;
struct sctp_sendv_spa *spa_info;
struct cmsghdr *cmsg;
char *cmsgbuf;
struct sockaddr *addr;
struct sockaddr_in *addr_in;
struct sockaddr_in6 *addr_in6;
sctp_assoc_t *assoc_id;
if ((addrcnt < 0) ||
(iovcnt < 0) ||
((addrs == NULL) && (addrcnt > 0)) ||
((addrs != NULL) && (addrcnt == 0)) ||
((iov == NULL) && (iovcnt > 0)) ||
((iov != NULL) && (iovcnt == 0))) {
errno = EINVAL;
return (-1);
}
cmsgbuf = malloc(CMSG_SPACE(sizeof(struct sctp_sndinfo)) +
CMSG_SPACE(sizeof(struct sctp_prinfo)) +
CMSG_SPACE(sizeof(struct sctp_authinfo)) +
(size_t)addrcnt * CMSG_SPACE(sizeof(struct in6_addr)));
if (cmsgbuf == NULL) {
errno = ENOMEM;
return (-1);
}
assoc_id = NULL;
msg.msg_control = cmsgbuf;
msg.msg_controllen = 0;
cmsg = (struct cmsghdr *)cmsgbuf;
switch (infotype) {
case SCTP_SENDV_NOINFO:
if ((infolen != 0) || (info != NULL)) {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
break;
case SCTP_SENDV_SNDINFO:
if ((info == NULL) || (infolen < sizeof(struct sctp_sndinfo))) {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_SNDINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_sndinfo));
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
assoc_id = &(((struct sctp_sndinfo *)info)->snd_assoc_id);
break;
case SCTP_SENDV_PRINFO:
if ((info == NULL) || (infolen < sizeof(struct sctp_prinfo))) {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_PRINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_prinfo));
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
break;
case SCTP_SENDV_AUTHINFO:
if ((info == NULL) || (infolen < sizeof(struct sctp_authinfo))) {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_AUTHINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
memcpy(CMSG_DATA(cmsg), info, sizeof(struct sctp_authinfo));
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
break;
case SCTP_SENDV_SPA:
if ((info == NULL) || (infolen < sizeof(struct sctp_sendv_spa))) {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
spa_info = (struct sctp_sendv_spa *)info;
if (spa_info->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_SNDINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo));
memcpy(CMSG_DATA(cmsg), &spa_info->sendv_sndinfo, sizeof(struct sctp_sndinfo));
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_sndinfo)));
assoc_id = &(spa_info->sendv_sndinfo.snd_assoc_id);
}
if (spa_info->sendv_flags & SCTP_SEND_PRINFO_VALID) {
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_PRINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo));
memcpy(CMSG_DATA(cmsg), &spa_info->sendv_prinfo, sizeof(struct sctp_prinfo));
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_prinfo)));
}
if (spa_info->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_AUTHINFO;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_authinfo));
memcpy(CMSG_DATA(cmsg), &spa_info->sendv_authinfo, sizeof(struct sctp_authinfo));
msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_authinfo));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct sctp_authinfo)));
}
break;
default:
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
addr = addrs;
msg.msg_name = NULL;
msg.msg_namelen = 0;
for (i = 0; i < addrcnt; i++) {
switch (addr->sa_family) {
case AF_INET:
addr_len = (socklen_t)sizeof(struct sockaddr_in);
addr_in = (struct sockaddr_in *)addr;
if (addr_in->sin_len != addr_len) {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
if (i == 0) {
port = addr_in->sin_port;
} else {
if (port == addr_in->sin_port) {
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_DSTADDRV4;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
memcpy(CMSG_DATA(cmsg), &addr_in->sin_addr, sizeof(struct in_addr));
msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in_addr)));
} else {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
}
break;
case AF_INET6:
addr_len = (socklen_t)sizeof(struct sockaddr_in6);
addr_in6 = (struct sockaddr_in6 *)addr;
if (addr_in6->sin6_len != addr_len) {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
if (i == 0) {
port = addr_in6->sin6_port;
} else {
if (port == addr_in6->sin6_port) {
cmsg->cmsg_level = IPPROTO_SCTP;
cmsg->cmsg_type = SCTP_DSTADDRV6;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_addr));
memcpy(CMSG_DATA(cmsg), &addr_in6->sin6_addr, sizeof(struct in6_addr));
msg.msg_controllen += CMSG_SPACE(sizeof(struct in6_addr));
cmsg = (struct cmsghdr *)((caddr_t)cmsg + CMSG_SPACE(sizeof(struct in6_addr)));
} else {
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
}
break;
default:
free(cmsgbuf);
errno = EINVAL;
return (-1);
}
if (i == 0) {
msg.msg_name = addr;
msg.msg_namelen = addr_len;
}
addr = (struct sockaddr *)((caddr_t)addr + addr_len);
}
if (msg.msg_controllen == 0) {
msg.msg_control = NULL;
}
msg.msg_iov = (struct iovec *)iov;
msg.msg_iovlen = iovcnt;
msg.msg_flags = 0;
ret = sendmsg(sd, &msg, flags);
free(cmsgbuf);
if ((ret >= 0) && (addrs != NULL) && (assoc_id != NULL)) {
*assoc_id = sctp_getassocid(sd, addrs);
}
return (ret);
}
#if !defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
int
sctp_peeloff(int sd, sctp_assoc_t assoc_id)
{
/* NOT supported, return invalid sd */
errno = ENOTSUP;
return (-1);
}
#endif
#if defined(SYS_sctp_peeloff) && !defined(HAVE_SCTP_PEELOFF_SOCKOPT)
int
sctp_peeloff(int sd, sctp_assoc_t assoc_id)
{
return (syscall(SYS_sctp_peeloff, sd, assoc_id));
}
#endif
#undef SCTP_CONTROL_VEC_SIZE_RCV
diff --git a/lib/libc/net/send.c b/lib/libc/net/send.c
index cb2f72ae8b9f..086cdffd714b 100644
--- a/lib/libc/net/send.c
+++ b/lib/libc/net/send.c
@@ -1,53 +1,52 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)send.c 8.2 (Berkeley) 2/21/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/socket.h>
#include "libc_private.h"
#include <stddef.h>
ssize_t
send(int s, const void *msg, size_t len, int flags)
{
/*
* POSIX says send() shall be a cancellation point, so call the
* cancellation-enabled sendto() and not _sendto().
*/
return (((ssize_t (*)(int, const void *, size_t, int,
const struct sockaddr *, socklen_t))
__libc_interposing[INTERPOS_sendto])(s, msg, len, flags,
NULL, 0));
}
diff --git a/lib/libc/net/sourcefilter.c b/lib/libc/net/sourcefilter.c
index 34dbde6a2577..81fa55741d0c 100644
--- a/lib/libc/net/sourcefilter.c
+++ b/lib/libc/net/sourcefilter.c
@@ -1,402 +1,401 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2007-2009 Bruce Simpson.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <net/if_dl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_var.h>
#include <assert.h>
#include <errno.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
/*
* Advanced (Full-state) multicast group membership APIs [RFC3678]
* Currently this module assumes IPv4 support (INET) in the base system.
*/
#ifndef INET
#define INET
#endif
union sockunion {
struct sockaddr_storage ss;
struct sockaddr sa;
struct sockaddr_dl sdl;
#ifdef INET
struct sockaddr_in sin;
#endif
#ifdef INET6
struct sockaddr_in6 sin6;
#endif
};
typedef union sockunion sockunion_t;
#ifndef MIN
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#endif
/*
* Internal: Map an IPv4 unicast address to an interface index.
* This is quite inefficient so it is recommended applications use
* the newer, more portable, protocol independent API.
*/
static uint32_t
__inaddr_to_index(in_addr_t ifaddr)
{
struct ifaddrs *ifa;
struct ifaddrs *ifaddrs;
char *ifname;
int ifindex;
sockunion_t *psu;
if (getifaddrs(&ifaddrs) < 0)
return (0);
ifindex = 0;
ifname = NULL;
/*
* Pass #1: Find the ifaddr entry corresponding to the
* supplied IPv4 address. We should really use the ifindex
* consistently for matches, however it is not available to
* us on this pass.
*/
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
psu = (sockunion_t *)ifa->ifa_addr;
if (psu && psu->ss.ss_family == AF_INET &&
psu->sin.sin_addr.s_addr == ifaddr) {
ifname = ifa->ifa_name;
break;
}
}
if (ifname == NULL)
goto out;
/*
* Pass #2: Find the index of the interface matching the name
* we obtained from looking up the IPv4 ifaddr in pass #1.
* There must be a better way of doing this.
*/
for (ifa = ifaddrs; ifa != NULL; ifa = ifa->ifa_next) {
psu = (sockunion_t *)ifa->ifa_addr;
if (psu && psu->ss.ss_family == AF_LINK &&
strcmp(ifa->ifa_name, ifname) == 0) {
ifindex = LLINDEX(&psu->sdl);
break;
}
}
assert(ifindex != 0);
out:
freeifaddrs(ifaddrs);
return (ifindex);
}
/*
* Set IPv4 source filter list in use on socket.
*
* Stubbed to setsourcefilter(). Performs conversion of structures which
* may be inefficient; applications are encouraged to use the
* protocol-independent API.
*/
int
setipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
uint32_t fmode, uint32_t numsrc, struct in_addr *slist)
{
#ifdef INET
sockunion_t tmpgroup;
struct in_addr *pina;
sockunion_t *psu, *tmpslist;
int err;
size_t i;
uint32_t ifindex;
assert(s != -1);
tmpslist = NULL;
if (!IN_MULTICAST(ntohl(group.s_addr)) ||
(fmode != MCAST_INCLUDE && fmode != MCAST_EXCLUDE)) {
errno = EINVAL;
return (-1);
}
ifindex = __inaddr_to_index(interface.s_addr);
if (ifindex == 0) {
errno = EADDRNOTAVAIL;
return (-1);
}
memset(&tmpgroup, 0, sizeof(sockunion_t));
tmpgroup.sin.sin_family = AF_INET;
tmpgroup.sin.sin_len = sizeof(struct sockaddr_in);
tmpgroup.sin.sin_addr = group;
if (numsrc != 0 || slist != NULL) {
tmpslist = calloc(numsrc, sizeof(sockunion_t));
if (tmpslist == NULL) {
errno = ENOMEM;
return (-1);
}
pina = slist;
psu = tmpslist;
for (i = 0; i < numsrc; i++, pina++, psu++) {
psu->sin.sin_family = AF_INET;
psu->sin.sin_len = sizeof(struct sockaddr_in);
psu->sin.sin_addr = *pina;
}
}
err = setsourcefilter(s, ifindex, (struct sockaddr *)&tmpgroup,
sizeof(struct sockaddr_in), fmode, numsrc,
(struct sockaddr_storage *)tmpslist);
if (tmpslist != NULL)
free(tmpslist);
return (err);
#else /* !INET */
return (EAFNOSUPPORT);
#endif /* INET */
}
/*
* Get IPv4 source filter list in use on socket.
*
* Stubbed to getsourcefilter(). Performs conversion of structures which
* may be inefficient; applications are encouraged to use the
* protocol-independent API.
* An slist of NULL may be used for guessing the required buffer size.
*/
int
getipv4sourcefilter(int s, struct in_addr interface, struct in_addr group,
uint32_t *fmode, uint32_t *numsrc, struct in_addr *slist)
{
sockunion_t *psu, *tmpslist;
sockunion_t tmpgroup;
struct in_addr *pina;
int err;
size_t i;
uint32_t ifindex, onumsrc;
assert(s != -1);
assert(fmode != NULL);
assert(numsrc != NULL);
onumsrc = *numsrc;
*numsrc = 0;
tmpslist = NULL;
if (!IN_MULTICAST(ntohl(group.s_addr)) ||
(onumsrc != 0 && slist == NULL)) {
errno = EINVAL;
return (-1);
}
ifindex = __inaddr_to_index(interface.s_addr);
if (ifindex == 0) {
errno = EADDRNOTAVAIL;
return (-1);
}
memset(&tmpgroup, 0, sizeof(sockunion_t));
tmpgroup.sin.sin_family = AF_INET;
tmpgroup.sin.sin_len = sizeof(struct sockaddr_in);
tmpgroup.sin.sin_addr = group;
if (onumsrc != 0 || slist != NULL) {
tmpslist = calloc(onumsrc, sizeof(sockunion_t));
if (tmpslist == NULL) {
errno = ENOMEM;
return (-1);
}
}
err = getsourcefilter(s, ifindex, (struct sockaddr *)&tmpgroup,
sizeof(struct sockaddr_in), fmode, numsrc,
(struct sockaddr_storage *)tmpslist);
if (tmpslist != NULL && *numsrc != 0) {
pina = slist;
psu = tmpslist;
for (i = 0; i < MIN(onumsrc, *numsrc); i++, psu++) {
if (psu->ss.ss_family != AF_INET)
continue;
*pina++ = psu->sin.sin_addr;
}
free(tmpslist);
}
return (err);
}
/*
* Set protocol-independent source filter list in use on socket.
*/
int
setsourcefilter(int s, uint32_t interface, struct sockaddr *group,
socklen_t grouplen, uint32_t fmode, uint32_t numsrc,
struct sockaddr_storage *slist)
{
struct __msfilterreq msfr;
sockunion_t *psu;
int level, optname;
if (fmode != MCAST_INCLUDE && fmode != MCAST_EXCLUDE) {
errno = EINVAL;
return (-1);
}
psu = (sockunion_t *)group;
switch (psu->ss.ss_family) {
#ifdef INET
case AF_INET:
if ((grouplen != sizeof(struct sockaddr_in) ||
!IN_MULTICAST(ntohl(psu->sin.sin_addr.s_addr)))) {
errno = EINVAL;
return (-1);
}
level = IPPROTO_IP;
optname = IP_MSFILTER;
break;
#endif
#ifdef INET6
case AF_INET6:
if (grouplen != sizeof(struct sockaddr_in6) ||
!IN6_IS_ADDR_MULTICAST(&psu->sin6.sin6_addr)) {
errno = EINVAL;
return (-1);
}
level = IPPROTO_IPV6;
optname = IPV6_MSFILTER;
break;
#endif
default:
errno = EAFNOSUPPORT;
return (-1);
}
memset(&msfr, 0, sizeof(msfr));
msfr.msfr_ifindex = interface;
msfr.msfr_fmode = fmode;
msfr.msfr_nsrcs = numsrc;
memcpy(&msfr.msfr_group, &psu->ss, psu->ss.ss_len);
msfr.msfr_srcs = slist; /* pointer */
return (_setsockopt(s, level, optname, &msfr, sizeof(msfr)));
}
/*
* Get protocol-independent source filter list in use on socket.
* An slist of NULL may be used for guessing the required buffer size.
*/
int
getsourcefilter(int s, uint32_t interface, struct sockaddr *group,
socklen_t grouplen, uint32_t *fmode, uint32_t *numsrc,
struct sockaddr_storage *slist)
{
struct __msfilterreq msfr;
sockunion_t *psu;
socklen_t optlen;
int err, level, nsrcs, optname;
if (interface == 0 || group == NULL || numsrc == NULL ||
fmode == NULL) {
errno = EINVAL;
return (-1);
}
nsrcs = *numsrc;
*numsrc = 0;
*fmode = 0;
psu = (sockunion_t *)group;
switch (psu->ss.ss_family) {
#ifdef INET
case AF_INET:
if ((grouplen != sizeof(struct sockaddr_in) ||
!IN_MULTICAST(ntohl(psu->sin.sin_addr.s_addr)))) {
errno = EINVAL;
return (-1);
}
level = IPPROTO_IP;
optname = IP_MSFILTER;
break;
#endif
#ifdef INET6
case AF_INET6:
if (grouplen != sizeof(struct sockaddr_in6) ||
!IN6_IS_ADDR_MULTICAST(&psu->sin6.sin6_addr)) {
errno = EINVAL;
return (-1);
}
level = IPPROTO_IPV6;
optname = IPV6_MSFILTER;
break;
#endif
default:
errno = EAFNOSUPPORT;
return (-1);
break;
}
optlen = sizeof(struct __msfilterreq);
memset(&msfr, 0, optlen);
msfr.msfr_ifindex = interface;
msfr.msfr_fmode = 0;
msfr.msfr_nsrcs = nsrcs;
memcpy(&msfr.msfr_group, &psu->ss, psu->ss.ss_len);
/*
* msfr_srcs is a pointer to a vector of sockaddr_storage. It
* may be NULL. The kernel will always return the total number
* of filter entries for the group in msfr.msfr_nsrcs.
*/
msfr.msfr_srcs = slist;
err = _getsockopt(s, level, optname, &msfr, &optlen);
if (err == 0) {
*numsrc = msfr.msfr_nsrcs;
*fmode = msfr.msfr_fmode;
}
return (err);
}
diff --git a/lib/libc/net/vars.c b/lib/libc/net/vars.c
index 7df32ca69ed6..1a8824740dec 100644
--- a/lib/libc/net/vars.c
+++ b/lib/libc/net/vars.c
@@ -1,45 +1,44 @@
/* $KAME: vars.c,v 1.2 2001/08/20 02:32:41 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <netinet/in.h>
/*
* Definitions of some costant IPv6 addresses.
*/
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
const struct in6_addr in6addr_nodelocal_allnodes = IN6ADDR_NODELOCAL_ALLNODES_INIT;
const struct in6_addr in6addr_linklocal_allnodes = IN6ADDR_LINKLOCAL_ALLNODES_INIT;
diff --git a/lib/libc/nls/msgcat.c b/lib/libc/nls/msgcat.c
index 80750dc8cfa1..32fa191c4c67 100644
--- a/lib/libc/nls/msgcat.c
+++ b/lib/libc/nls/msgcat.c
@@ -1,482 +1,481 @@
/***********************************************************
Copyright 1990, by Alfalfa Software Incorporated, Cambridge, Massachusetts.
Copyright 2010, Gabor Kovesdan <gabor@FreeBSD.org>
All Rights Reserved
Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted,
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in
supporting documentation, and that Alfalfa's name not be used in
advertising or publicity pertaining to distribution of the software
without specific, written prior permission.
ALPHALPHA DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
ALPHALPHA BE LIABLE FOR ANY SPECIAL, 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.
If you make any modifications, bugfixes or other changes to this software
we'd appreciate it if you could send a copy to us so we can keep things
up-to-date. Many thanks.
Kee Hinckley
Alfalfa Software, Inc.
267 Allston St., #3
Cambridge, MA 02139 USA
nazgul@alfalfa.com
******************************************************************/
-#include <sys/cdefs.h>
#define _NLS_PRIVATE
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/queue.h>
#include <arpa/inet.h> /* for ntohl() */
#include <machine/atomic.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <nl_types.h>
#include <paths.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "../locale/xlocale_private.h"
#include "libc_private.h"
#define _DEFAULT_NLS_PATH "/usr/share/nls/%L/%N.cat:/usr/share/nls/%N/%L:" \
_PATH_LOCALBASE "/share/nls/%L/%N.cat:" \
_PATH_LOCALBASE "/share/nls/%N/%L"
#define RLOCK(fail) { int ret; \
if (__isthreaded && \
((ret = _pthread_rwlock_rdlock(&rwlock)) != 0)) { \
errno = ret; \
return (fail); \
}}
#define WLOCK(fail) { int ret; \
if (__isthreaded && \
((ret = _pthread_rwlock_wrlock(&rwlock)) != 0)) { \
errno = ret; \
return (fail); \
}}
#define UNLOCK { if (__isthreaded) \
_pthread_rwlock_unlock(&rwlock); }
#define NLERR ((nl_catd) -1)
#define NLRETERR(errc) { errno = errc; return (NLERR); }
#define SAVEFAIL(n, l, e) { np = calloc(1, sizeof(struct catentry)); \
if (np != NULL) { \
np->name = strdup(n); \
np->catd = NLERR; \
np->lang = (l == NULL) ? NULL : \
strdup(l); \
np->caterrno = e; \
if (np->name == NULL || \
(l != NULL && np->lang == NULL)) { \
free(np->name); \
free(np->lang); \
free(np); \
} else { \
WLOCK(NLERR); \
SLIST_INSERT_HEAD(&cache, np, \
list); \
UNLOCK; \
} \
} \
errno = e; \
}
static nl_catd load_msgcat(const char *, const char *, const char *);
static pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
struct catentry {
SLIST_ENTRY(catentry) list;
char *name;
char *path;
int caterrno;
nl_catd catd;
char *lang;
int refcount;
};
SLIST_HEAD(listhead, catentry) cache =
SLIST_HEAD_INITIALIZER(cache);
nl_catd
catopen(const char *name, int type)
{
return (__catopen_l(name, type, __get_locale()));
}
nl_catd
__catopen_l(const char *name, int type, locale_t locale)
{
struct stat sbuf;
struct catentry *np;
char *base, *cptr, *cptr1, *nlspath, *pathP, *pcode;
char *plang, *pter;
int saverr, spcleft;
const char *lang, *tmpptr;
char path[PATH_MAX];
/* sanity checking */
if (name == NULL || *name == '\0')
NLRETERR(EINVAL);
if (strchr(name, '/') != NULL)
/* have a pathname */
lang = NULL;
else {
if (type == NL_CAT_LOCALE)
lang = querylocale(LC_MESSAGES_MASK, locale);
else
lang = getenv("LANG");
if (lang == NULL || *lang == '\0' || strlen(lang) > ENCODING_LEN ||
(lang[0] == '.' &&
(lang[1] == '\0' || (lang[1] == '.' && lang[2] == '\0'))) ||
strchr(lang, '/') != NULL)
lang = "C";
}
/* Try to get it from the cache first */
RLOCK(NLERR);
SLIST_FOREACH(np, &cache, list) {
if ((strcmp(np->name, name) == 0) &&
((lang != NULL && np->lang != NULL &&
strcmp(np->lang, lang) == 0) || (np->lang == lang))) {
if (np->caterrno != 0) {
/* Found cached failing entry */
UNLOCK;
NLRETERR(np->caterrno);
} else {
/* Found cached successful entry */
atomic_add_int(&np->refcount, 1);
UNLOCK;
return (np->catd);
}
}
}
UNLOCK;
/* is it absolute path ? if yes, load immediately */
if (strchr(name, '/') != NULL)
return (load_msgcat(name, name, lang));
/* sanity checking */
if ((plang = cptr1 = strdup(lang)) == NULL)
return (NLERR);
if ((cptr = strchr(cptr1, '@')) != NULL)
*cptr = '\0';
pter = pcode = "";
if ((cptr = strchr(cptr1, '_')) != NULL) {
*cptr++ = '\0';
pter = cptr1 = cptr;
}
if ((cptr = strchr(cptr1, '.')) != NULL) {
*cptr++ = '\0';
pcode = cptr;
}
if ((nlspath = secure_getenv("NLSPATH")) == NULL)
nlspath = _DEFAULT_NLS_PATH;
if ((base = cptr = strdup(nlspath)) == NULL) {
saverr = errno;
free(plang);
errno = saverr;
return (NLERR);
}
while ((nlspath = strsep(&cptr, ":")) != NULL) {
pathP = path;
if (*nlspath) {
for (; *nlspath; ++nlspath) {
if (*nlspath == '%') {
switch (*(nlspath + 1)) {
case 'l':
tmpptr = plang;
break;
case 't':
tmpptr = pter;
break;
case 'c':
tmpptr = pcode;
break;
case 'L':
tmpptr = lang;
break;
case 'N':
tmpptr = (char *)name;
break;
case '%':
++nlspath;
/* FALLTHROUGH */
default:
if (pathP - path >=
sizeof(path) - 1)
goto too_long;
*(pathP++) = *nlspath;
continue;
}
++nlspath;
put_tmpptr:
spcleft = sizeof(path) -
(pathP - path) - 1;
if (strlcpy(pathP, tmpptr, spcleft) >=
spcleft) {
too_long:
free(plang);
free(base);
SAVEFAIL(name, lang, ENAMETOOLONG);
NLRETERR(ENAMETOOLONG);
}
pathP += strlen(tmpptr);
} else {
if (pathP - path >= sizeof(path) - 1)
goto too_long;
*(pathP++) = *nlspath;
}
}
*pathP = '\0';
if (stat(path, &sbuf) == 0) {
free(plang);
free(base);
return (load_msgcat(path, name, lang));
}
} else {
tmpptr = (char *)name;
--nlspath;
goto put_tmpptr;
}
}
free(plang);
free(base);
SAVEFAIL(name, lang, ENOENT);
NLRETERR(ENOENT);
}
char *
catgets(nl_catd catd, int set_id, int msg_id, const char *s)
{
struct _nls_cat_hdr *cat_hdr;
struct _nls_msg_hdr *msg_hdr;
struct _nls_set_hdr *set_hdr;
int i, l, r, u;
if (catd == NULL || catd == NLERR) {
errno = EBADF;
/* LINTED interface problem */
return ((char *)s);
}
cat_hdr = (struct _nls_cat_hdr *)catd->__data;
set_hdr = (struct _nls_set_hdr *)(void *)((char *)catd->__data +
sizeof(struct _nls_cat_hdr));
/* binary search, see knuth algorithm b */
l = 0;
u = ntohl((u_int32_t)cat_hdr->__nsets) - 1;
while (l <= u) {
i = (l + u) / 2;
r = set_id - ntohl((u_int32_t)set_hdr[i].__setno);
if (r == 0) {
msg_hdr = (struct _nls_msg_hdr *)
(void *)((char *)catd->__data +
sizeof(struct _nls_cat_hdr) +
ntohl((u_int32_t)cat_hdr->__msg_hdr_offset));
l = ntohl((u_int32_t)set_hdr[i].__index);
u = l + ntohl((u_int32_t)set_hdr[i].__nmsgs) - 1;
while (l <= u) {
i = (l + u) / 2;
r = msg_id -
ntohl((u_int32_t)msg_hdr[i].__msgno);
if (r == 0) {
return ((char *) catd->__data +
sizeof(struct _nls_cat_hdr) +
ntohl((u_int32_t)
cat_hdr->__msg_txt_offset) +
ntohl((u_int32_t)
msg_hdr[i].__offset));
} else if (r < 0) {
u = i - 1;
} else {
l = i + 1;
}
}
/* not found */
goto notfound;
} else if (r < 0) {
u = i - 1;
} else {
l = i + 1;
}
}
notfound:
/* not found */
errno = ENOMSG;
/* LINTED interface problem */
return ((char *)s);
}
static void
catfree(struct catentry *np)
{
if (np->catd != NULL && np->catd != NLERR) {
munmap(np->catd->__data, (size_t)np->catd->__size);
free(np->catd);
}
SLIST_REMOVE(&cache, np, catentry, list);
free(np->name);
free(np->path);
free(np->lang);
free(np);
}
int
catclose(nl_catd catd)
{
struct catentry *np;
/* sanity checking */
if (catd == NULL || catd == NLERR) {
errno = EBADF;
return (-1);
}
/* Remove from cache if not referenced any more */
WLOCK(-1);
SLIST_FOREACH(np, &cache, list) {
if (catd == np->catd) {
if (atomic_fetchadd_int(&np->refcount, -1) == 1)
catfree(np);
break;
}
}
UNLOCK;
return (0);
}
/*
* Internal support functions
*/
static nl_catd
load_msgcat(const char *path, const char *name, const char *lang)
{
struct stat st;
nl_catd catd;
struct catentry *np;
void *data;
char *copy_path, *copy_name, *copy_lang;
int fd;
/* path/name will never be NULL here */
/*
* One more try in cache; if it was not found by name,
* it might still be found by absolute path.
*/
RLOCK(NLERR);
SLIST_FOREACH(np, &cache, list) {
if ((np->path != NULL) && (strcmp(np->path, path) == 0)) {
atomic_add_int(&np->refcount, 1);
UNLOCK;
return (np->catd);
}
}
UNLOCK;
if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) {
SAVEFAIL(name, lang, errno);
NLRETERR(errno);
}
if (_fstat(fd, &st) != 0) {
_close(fd);
SAVEFAIL(name, lang, EFTYPE);
NLRETERR(EFTYPE);
}
/*
* If the file size cannot be held in size_t we cannot mmap()
* it to the memory. Probably, this will not be a problem given
* that catalog files are usually small.
*/
if (st.st_size > SIZE_T_MAX) {
_close(fd);
SAVEFAIL(name, lang, EFBIG);
NLRETERR(EFBIG);
}
if ((data = mmap(0, (size_t)st.st_size, PROT_READ,
MAP_FILE|MAP_SHARED, fd, (off_t)0)) == MAP_FAILED) {
int saved_errno = errno;
_close(fd);
SAVEFAIL(name, lang, saved_errno);
NLRETERR(saved_errno);
}
_close(fd);
if (ntohl((u_int32_t)((struct _nls_cat_hdr *)data)->__magic) !=
_NLS_MAGIC) {
munmap(data, (size_t)st.st_size);
SAVEFAIL(name, lang, EFTYPE);
NLRETERR(EFTYPE);
}
copy_name = strdup(name);
copy_path = strdup(path);
copy_lang = (lang == NULL) ? NULL : strdup(lang);
catd = malloc(sizeof (*catd));
np = calloc(1, sizeof(struct catentry));
if (copy_name == NULL || copy_path == NULL ||
(lang != NULL && copy_lang == NULL) ||
catd == NULL || np == NULL) {
free(copy_name);
free(copy_path);
free(copy_lang);
free(catd);
free(np);
munmap(data, (size_t)st.st_size);
SAVEFAIL(name, lang, ENOMEM);
NLRETERR(ENOMEM);
}
catd->__data = data;
catd->__size = (int)st.st_size;
/* Caching opened catalog */
np->name = copy_name;
np->path = copy_path;
np->catd = catd;
np->lang = copy_lang;
atomic_store_int(&np->refcount, 1);
WLOCK(NLERR);
SLIST_INSERT_HEAD(&cache, np, list);
UNLOCK;
return (catd);
}
diff --git a/lib/libc/posix1e/acl_branding.c b/lib/libc/posix1e/acl_branding.c
index 4cb9feb1d281..85c0d2b86825 100644
--- a/lib/libc/posix1e/acl_branding.c
+++ b/lib/libc/posix1e/acl_branding.c
@@ -1,168 +1,167 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <errno.h>
#include <sys/acl.h>
#include "acl_support.h"
/*
* An ugly detail of the implementation - fortunately not visible
* to the API users - is the "branding": libc needs to keep track
* of what "brand" ACL is: NFSv4, POSIX.1e or unknown. It happens
* automatically - for example, during acl_get_file(3) ACL gets
* branded according to the "type" argument; during acl_set_permset
* ACL, if its brand is unknown it gets branded as NFSv4 if any of the
* NFSv4 permissions that are not valid for POSIX.1e ACL are set etc.
* Branding information is used for printing out the ACL (acl_to_text(3)),
* veryfying acl_set_whatever arguments (checking against setting
* bits that are valid only for NFSv4 in ACL branded as POSIX.1e) etc.
*/
static acl_t
entry2acl(acl_entry_t entry)
{
acl_t aclp;
aclp = (acl_t)(((long)entry >> _ACL_T_ALIGNMENT_BITS) << _ACL_T_ALIGNMENT_BITS);
return (aclp);
}
/*
* Return brand of an ACL.
*/
int
_acl_brand(const acl_t acl)
{
return (acl->ats_brand);
}
int
_entry_brand(const acl_entry_t entry)
{
return (_acl_brand(entry2acl(entry)));
}
/*
* Return 1, iff branding ACL as "brand" is ok.
*/
int
_acl_brand_may_be(const acl_t acl, int brand)
{
if (_acl_brand(acl) == ACL_BRAND_UNKNOWN)
return (1);
if (_acl_brand(acl) == brand)
return (1);
return (0);
}
int
_entry_brand_may_be(const acl_entry_t entry, int brand)
{
return (_acl_brand_may_be(entry2acl(entry), brand));
}
/*
* Brand ACL as "brand".
*/
void
_acl_brand_as(acl_t acl, int brand)
{
assert(_acl_brand_may_be(acl, brand));
acl->ats_brand = brand;
}
void
_entry_brand_as(const acl_entry_t entry, int brand)
{
_acl_brand_as(entry2acl(entry), brand);
}
int
_acl_type_not_valid_for_acl(const acl_t acl, acl_type_t type)
{
switch (_acl_brand(acl)) {
case ACL_BRAND_NFS4:
if (type == ACL_TYPE_NFS4)
return (0);
break;
case ACL_BRAND_POSIX:
if (type == ACL_TYPE_ACCESS || type == ACL_TYPE_DEFAULT)
return (0);
break;
case ACL_BRAND_UNKNOWN:
return (0);
}
return (-1);
}
void
_acl_brand_from_type(acl_t acl, acl_type_t type)
{
switch (type) {
case ACL_TYPE_NFS4:
_acl_brand_as(acl, ACL_BRAND_NFS4);
break;
case ACL_TYPE_ACCESS:
case ACL_TYPE_DEFAULT:
_acl_brand_as(acl, ACL_BRAND_POSIX);
break;
default:
/* XXX: What to do here? */
break;
}
}
int
acl_get_brand_np(acl_t acl, int *brand_p)
{
if (acl == NULL || brand_p == NULL) {
errno = EINVAL;
return (-1);
}
*brand_p = _acl_brand(acl);
return (0);
}
diff --git a/lib/libc/posix1e/acl_calc_mask.c b/lib/libc/posix1e/acl_calc_mask.c
index 74a432839c17..3e5c5afd06c2 100644
--- a/lib/libc/posix1e/acl_calc_mask.c
+++ b/lib/libc/posix1e/acl_calc_mask.c
@@ -1,129 +1,128 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001-2002 Chris D. Faulhaber
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <stdio.h>
#include "acl_support.h"
/*
* acl_calc_mask() (23.4.2): calculate and set the permissions
* associated with the ACL_MASK ACL entry. If the ACL already
* contains an ACL_MASK entry, its permissions shall be
* overwritten; if not, one shall be added.
*/
int
acl_calc_mask(acl_t *acl_p)
{
struct acl *acl_int, *acl_int_new;
acl_t acl_new;
int i, mask_mode, mask_num;
/*
* (23.4.2.4) requires acl_p to point to a pointer to a valid ACL.
* Since one of the primary reasons to use this function would be
* to calculate the appropriate mask to obtain a valid ACL, we only
* perform sanity checks here and validate the ACL prior to
* returning.
*/
if (acl_p == NULL || *acl_p == NULL) {
errno = EINVAL;
return (-1);
}
if (!_acl_brand_may_be(*acl_p, ACL_BRAND_POSIX)) {
errno = EINVAL;
return (-1);
}
_acl_brand_as(*acl_p, ACL_BRAND_POSIX);
acl_int = &(*acl_p)->ats_acl;
if ((acl_int->acl_cnt < 3) || (acl_int->acl_cnt > ACL_MAX_ENTRIES)) {
errno = EINVAL;
return (-1);
}
acl_new = acl_dup(*acl_p);
if (acl_new == NULL)
return (-1);
acl_int_new = &acl_new->ats_acl;
mask_mode = 0;
mask_num = -1;
/* gather permissions and find a mask entry */
for (i = 0; i < acl_int_new->acl_cnt; i++) {
switch(acl_int_new->acl_entry[i].ae_tag) {
case ACL_USER:
case ACL_GROUP:
case ACL_GROUP_OBJ:
mask_mode |=
acl_int_new->acl_entry[i].ae_perm & ACL_PERM_BITS;
break;
case ACL_MASK:
mask_num = i;
break;
}
}
/* if a mask entry already exists, overwrite the perms */
if (mask_num != -1)
acl_int_new->acl_entry[mask_num].ae_perm = mask_mode;
else {
/* if no mask exists, check acl_cnt... */
if (acl_int_new->acl_cnt == ACL_MAX_ENTRIES) {
errno = ENOMEM;
acl_free(acl_new);
return (-1);
}
/* ...and add the mask entry */
acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_tag = ACL_MASK;
acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_id =
ACL_UNDEFINED_ID;
acl_int_new->acl_entry[acl_int_new->acl_cnt].ae_perm =
mask_mode;
acl_int_new->acl_cnt++;
}
if (acl_valid(acl_new) == -1) {
errno = EINVAL;
acl_free(acl_new);
return (-1);
}
**acl_p = *acl_new;
acl_free(acl_new);
return (0);
}
diff --git a/lib/libc/posix1e/acl_cmp_np.c b/lib/libc/posix1e/acl_cmp_np.c
index f1ec108629a5..f7ee9c235a04 100644
--- a/lib/libc/posix1e/acl_cmp_np.c
+++ b/lib/libc/posix1e/acl_cmp_np.c
@@ -1,53 +1,52 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Gleb Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_cmp_np: Compare two ACL's.
*/
-#include <sys/cdefs.h>
#include <sys/acl.h>
#include <sys/errno.h>
#include "acl_support.h"
/*
* returns 0 if acl_t's are identical, 1 otherwise
*/
int
acl_cmp_np(acl_t acl1, acl_t acl2)
{
if (acl1 == NULL || acl2 == NULL) {
errno = EINVAL;
return (-1);
}
if (_acl_brand(acl1) != _acl_brand(acl2))
return (1);
return (_acl_differs(acl1, acl2));
}
diff --git a/lib/libc/posix1e/acl_compat.c b/lib/libc/posix1e/acl_compat.c
index f8eb55116d84..836cf3cab500 100644
--- a/lib/libc/posix1e/acl_compat.c
+++ b/lib/libc/posix1e/acl_compat.c
@@ -1,62 +1,61 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Edward Tomasz Napierała <trasz@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/acl.h>
int __oldacl_get_perm_np(acl_permset_t, oldacl_perm_t);
int __oldacl_add_perm(acl_permset_t, oldacl_perm_t);
int __oldacl_delete_perm(acl_permset_t, oldacl_perm_t);
/*
* Compatibility wrappers for applications compiled against libc from before
* NFSv4 ACLs were added.
*/
int
__oldacl_get_perm_np(acl_permset_t permset_d, oldacl_perm_t perm)
{
return (acl_get_perm_np(permset_d, perm));
}
int
__oldacl_add_perm(acl_permset_t permset_d, oldacl_perm_t perm)
{
return (acl_add_perm(permset_d, perm));
}
int
__oldacl_delete_perm(acl_permset_t permset_d, oldacl_perm_t perm)
{
return (acl_delete_perm(permset_d, perm));
}
__sym_compat(acl_get_perm_np, __oldacl_get_perm_np, FBSD_1.0);
__sym_compat(acl_add_perm, __oldacl_add_perm, FBSD_1.0);
__sym_compat(acl_delete_perm, __oldacl_delete_perm, FBSD_1.0);
diff --git a/lib/libc/posix1e/acl_copy.c b/lib/libc/posix1e/acl_copy.c
index 96a5ed479641..3f0771b1c257 100644
--- a/lib/libc/posix1e/acl_copy.c
+++ b/lib/libc/posix1e/acl_copy.c
@@ -1,86 +1,85 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001-2002 Chris D. Faulhaber
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <string.h>
#include "acl_support.h"
/*
* acl_copy_entry() (23.4.4): copy the contents of ACL entry src_d to
* ACL entry dest_d
*/
int
acl_copy_entry(acl_entry_t dest_d, acl_entry_t src_d)
{
if (src_d == NULL || dest_d == NULL || src_d == dest_d) {
errno = EINVAL;
return (-1);
}
/*
* Can we brand the new entry the same as the source entry?
*/
if (!_entry_brand_may_be(dest_d, _entry_brand(src_d))) {
errno = EINVAL;
return (-1);
}
_entry_brand_as(dest_d, _entry_brand(src_d));
dest_d->ae_tag = src_d->ae_tag;
dest_d->ae_id = src_d->ae_id;
dest_d->ae_perm = src_d->ae_perm;
dest_d->ae_entry_type = src_d->ae_entry_type;
dest_d->ae_flags = src_d->ae_flags;
return (0);
}
ssize_t
acl_copy_ext(void *buf_p, acl_t acl, ssize_t size)
{
errno = ENOSYS;
return (-1);
}
acl_t
acl_copy_int(const void *buf_p)
{
errno = ENOSYS;
return (NULL);
}
diff --git a/lib/libc/posix1e/acl_delete.c b/lib/libc/posix1e/acl_delete.c
index b0fb59391ec5..35303fe87e0f 100644
--- a/lib/libc/posix1e/acl_delete.c
+++ b/lib/libc/posix1e/acl_delete.c
@@ -1,79 +1,78 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_delete_def_file -- remove a default acl from a file
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <sys/errno.h>
#include "acl_support.h"
int
acl_delete_def_file(const char *path_p)
{
return (__acl_delete_file(path_p, ACL_TYPE_DEFAULT));
}
int
acl_delete_def_link_np(const char *path_p)
{
return (__acl_delete_link(path_p, ACL_TYPE_DEFAULT));
}
int
acl_delete_file_np(const char *path_p, acl_type_t type)
{
type = _acl_type_unold(type);
return (__acl_delete_file(path_p, type));
}
int
acl_delete_link_np(const char *path_p, acl_type_t type)
{
type = _acl_type_unold(type);
return (__acl_delete_link(path_p, type));
}
int
acl_delete_fd_np(int filedes, acl_type_t type)
{
type = _acl_type_unold(type);
return (___acl_delete_fd(filedes, type));
}
diff --git a/lib/libc/posix1e/acl_delete_entry.c b/lib/libc/posix1e/acl_delete_entry.c
index 5faa52065fe9..a787609f3853 100644
--- a/lib/libc/posix1e/acl_delete_entry.c
+++ b/lib/libc/posix1e/acl_delete_entry.c
@@ -1,159 +1,158 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001-2002 Chris D. Faulhaber
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "acl_support.h"
static int
_entry_matches(const acl_entry_t a, const acl_entry_t b)
{
/*
* There is a semantical difference here between NFSv4 and POSIX
* draft ACLs. In POSIX, there may be only one entry for the particular
* user or group. In NFSv4 ACL, there may be any number of them. We're
* trying to be more specific here in that case.
*/
switch (_entry_brand(a)) {
case ACL_BRAND_NFS4:
if (a->ae_tag != b->ae_tag || a->ae_entry_type != b->ae_entry_type)
return (0);
/* If ae_ids matter, compare them as well. */
if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
if (a->ae_id != b->ae_id)
return (0);
}
return (1);
default:
if ((a->ae_tag == b->ae_tag) && (a->ae_id == b->ae_id))
return (1);
}
return (0);
}
/*
* acl_delete_entry() (23.4.9): remove the ACL entry indicated by entry_d
* from acl.
*/
int
acl_delete_entry(acl_t acl, acl_entry_t entry_d)
{
struct acl_entry entry_int;
int i, j, found = 0;
if (acl == NULL || entry_d == NULL) {
errno = EINVAL;
return (-1);
}
if (_entry_brand(entry_d) != _acl_brand(acl)) {
errno = EINVAL;
return (-1);
}
if ((acl->ats_acl.acl_cnt < 1) ||
(acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
errno = EINVAL;
return (-1);
}
/* Use a local copy to prevent deletion of more than this entry */
entry_int = *entry_d;
for (i = 0; i < acl->ats_acl.acl_cnt;) {
if (_entry_matches(&(acl->ats_acl.acl_entry[i]), &entry_int)) {
/* ...shift the remaining entries... */
for (j = i; j < acl->ats_acl.acl_cnt - 1; ++j)
acl->ats_acl.acl_entry[j] =
acl->ats_acl.acl_entry[j+1];
/* ...drop the count and zero the unused entry... */
acl->ats_acl.acl_cnt--;
bzero(&acl->ats_acl.acl_entry[j],
sizeof(struct acl_entry));
acl->ats_cur_entry = 0;
/* Continue with the loop to remove all matching entries. */
found = 1;
} else
i++;
}
if (found)
return (0);
errno = EINVAL;
return (-1);
}
int
acl_delete_entry_np(acl_t acl, int offset)
{
struct acl *acl_int;
int i;
if (acl == NULL) {
errno = EINVAL;
return (-1);
}
acl_int = &acl->ats_acl;
if (offset < 0 || offset >= acl_int->acl_cnt) {
errno = EINVAL;
return (-1);
}
if ((acl->ats_acl.acl_cnt < 1) ||
(acl->ats_acl.acl_cnt > ACL_MAX_ENTRIES)) {
errno = EINVAL;
return (-1);
}
/* ...shift the remaining entries... */
for (i = offset; i < acl->ats_acl.acl_cnt - 1; ++i)
acl->ats_acl.acl_entry[i] =
acl->ats_acl.acl_entry[i+1];
/* ...drop the count and zero the unused entry... */
acl->ats_acl.acl_cnt--;
bzero(&acl->ats_acl.acl_entry[i],
sizeof(struct acl_entry));
acl->ats_cur_entry = 0;
return (0);
}
diff --git a/lib/libc/posix1e/acl_entry.c b/lib/libc/posix1e/acl_entry.c
index eb9103439efe..abba3a0586dc 100644
--- a/lib/libc/posix1e/acl_entry.c
+++ b/lib/libc/posix1e/acl_entry.c
@@ -1,146 +1,145 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001-2002 Chris D. Faulhaber
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <stdlib.h>
/*
* acl_create_entry() (23.4.7): create a new ACL entry in the ACL pointed
* to by acl_p.
*/
int
acl_create_entry(acl_t *acl_p, acl_entry_t *entry_p)
{
struct acl *acl_int;
if (acl_p == NULL) {
errno = EINVAL;
return (-1);
}
acl_int = &(*acl_p)->ats_acl;
/*
* +1, because we are checking if there is space left for one more
* entry.
*/
if (acl_int->acl_cnt + 1 >= ACL_MAX_ENTRIES) {
errno = EINVAL;
return (-1);
}
*entry_p = &acl_int->acl_entry[acl_int->acl_cnt++];
(**entry_p).ae_tag = ACL_UNDEFINED_TAG;
(**entry_p).ae_id = ACL_UNDEFINED_ID;
(**entry_p).ae_perm = ACL_PERM_NONE;
(**entry_p).ae_entry_type = 0;
(**entry_p).ae_flags = 0;
(*acl_p)->ats_cur_entry = 0;
return (0);
}
int
acl_create_entry_np(acl_t *acl_p, acl_entry_t *entry_p, int offset)
{
int i;
struct acl *acl_int;
if (acl_p == NULL) {
errno = EINVAL;
return (-1);
}
acl_int = &(*acl_p)->ats_acl;
if (acl_int->acl_cnt + 1 >= ACL_MAX_ENTRIES) {
errno = EINVAL;
return (-1);
}
if (offset < 0 || offset > acl_int->acl_cnt) {
errno = EINVAL;
return (-1);
}
/* Make room for the new entry. */
for (i = acl_int->acl_cnt; i > offset; i--)
acl_int->acl_entry[i] = acl_int->acl_entry[i - 1];
acl_int->acl_cnt++;
*entry_p = &acl_int->acl_entry[offset];
(**entry_p).ae_tag = ACL_UNDEFINED_TAG;
(**entry_p).ae_id = ACL_UNDEFINED_ID;
(**entry_p).ae_perm = ACL_PERM_NONE;
(**entry_p).ae_entry_type = 0;
(**entry_p).ae_flags= 0;
(*acl_p)->ats_cur_entry = 0;
return (0);
}
/*
* acl_get_entry() (23.4.14): returns an ACL entry from an ACL
* indicated by entry_id.
*/
int
acl_get_entry(acl_t acl, int entry_id, acl_entry_t *entry_p)
{
struct acl *acl_int;
if (acl == NULL) {
errno = EINVAL;
return (-1);
}
acl_int = &acl->ats_acl;
switch(entry_id) {
case ACL_FIRST_ENTRY:
acl->ats_cur_entry = 0;
/* PASSTHROUGH */
case ACL_NEXT_ENTRY:
if (acl->ats_cur_entry >= acl->ats_acl.acl_cnt)
return 0;
*entry_p = &acl_int->acl_entry[acl->ats_cur_entry++];
return (1);
}
errno = EINVAL;
return (-1);
}
diff --git a/lib/libc/posix1e/acl_equiv_mode_np.c b/lib/libc/posix1e/acl_equiv_mode_np.c
index 06bd3a3deda3..b3bf5280493a 100644
--- a/lib/libc/posix1e/acl_equiv_mode_np.c
+++ b/lib/libc/posix1e/acl_equiv_mode_np.c
@@ -1,99 +1,98 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Gleb Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_equiv_mode_np: Check if an ACL can be represented as a mode_t.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <sys/acl.h>
#include "acl_support.h"
int
acl_equiv_mode_np(acl_t acl, mode_t *mode_p)
{
mode_t ret_mode = 0;
if (acl == NULL) {
errno = EINVAL;
return (-1);
}
/* Linux returns 0 for ACL returned by acl_init() */
if (_acl_brand(acl) == ACL_BRAND_UNKNOWN && acl->ats_acl.acl_cnt == 0)
return (0);
// TODO: Do we want to handle ACL_BRAND_NFS4 in this function? */
if (_acl_brand(acl) != ACL_BRAND_POSIX)
return (1);
for (int cur_entry = 0; cur_entry < acl->ats_acl.acl_cnt; cur_entry++) {
acl_entry_t entry = &acl->ats_acl.acl_entry[cur_entry];
if ((entry->ae_perm & ACL_PERM_BITS) != entry->ae_perm)
return (1);
switch (entry->ae_tag) {
case ACL_USER_OBJ:
if (entry->ae_perm & ACL_READ)
ret_mode |= S_IRUSR;
if (entry->ae_perm & ACL_WRITE)
ret_mode |= S_IWUSR;
if (entry->ae_perm & ACL_EXECUTE)
ret_mode |= S_IXUSR;
break;
case ACL_GROUP_OBJ:
if (entry->ae_perm & ACL_READ)
ret_mode |= S_IRGRP;
if (entry->ae_perm & ACL_WRITE)
ret_mode |= S_IWGRP;
if (entry->ae_perm & ACL_EXECUTE)
ret_mode |= S_IXGRP;
break;
case ACL_OTHER:
if (entry->ae_perm & ACL_READ)
ret_mode |= S_IROTH;
if (entry->ae_perm & ACL_WRITE)
ret_mode |= S_IWOTH;
if (entry->ae_perm & ACL_EXECUTE)
ret_mode |= S_IXOTH;
break;
default:
return (1);
}
}
if (mode_p != NULL)
*mode_p = ret_mode;
return (0);
}
diff --git a/lib/libc/posix1e/acl_extended_file_np.c b/lib/libc/posix1e/acl_extended_file_np.c
index 27b5c9b20776..9c1452e96d93 100644
--- a/lib/libc/posix1e/acl_extended_file_np.c
+++ b/lib/libc/posix1e/acl_extended_file_np.c
@@ -1,83 +1,82 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Gleb Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_extended_file_np: Check if the file has extended ACLs set.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/errno.h>
#include <sys/acl.h>
#include <unistd.h>
typedef acl_t (*acl_get_func)(const char *, acl_type_t);
typedef long (*pathconf_func)(const char *, int);
static int
_acl_extended_file(acl_get_func f, pathconf_func pathconf_f, const char* path_p);
int
acl_extended_file_np(const char *path_p)
{
return (_acl_extended_file(acl_get_file, pathconf, path_p));
}
int
acl_extended_file_nofollow_np(const char *path_p)
{
return (_acl_extended_file(acl_get_link_np, lpathconf, path_p));
}
int
acl_extended_link_np(const char *path_p)
{
return (_acl_extended_file(acl_get_link_np, lpathconf, path_p));
}
int
_acl_extended_file(acl_get_func acl_get, pathconf_func pathconf_f, const char* path_p)
{
acl_t acl;
int retval, istrivial, acltype = ACL_TYPE_ACCESS;
retval = pathconf_f(path_p, _PC_ACL_NFS4);
if (retval > 0)
acltype = ACL_TYPE_NFS4;
acl = acl_get(path_p, acltype);
if (acl == NULL)
return (-1);
retval = acl_is_trivial_np(acl, &istrivial);
acl_free(acl);
if (retval == -1)
return (-1);
return (!istrivial);
}
diff --git a/lib/libc/posix1e/acl_flag.c b/lib/libc/posix1e/acl_flag.c
index 82772bf261f1..eaaaecd9a374 100644
--- a/lib/libc/posix1e/acl_flag.c
+++ b/lib/libc/posix1e/acl_flag.c
@@ -1,154 +1,153 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <errno.h>
#include <sys/acl.h>
#include "acl_support.h"
static int
_flag_is_invalid(acl_flag_t flag)
{
if ((flag & ACL_FLAGS_BITS) == flag)
return (0);
errno = EINVAL;
return (1);
}
int
acl_add_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
{
if (flagset_d == NULL) {
errno = EINVAL;
return (-1);
}
if (_flag_is_invalid(flag))
return (-1);
*flagset_d |= flag;
return (0);
}
int
acl_clear_flags_np(acl_flagset_t flagset_d)
{
if (flagset_d == NULL) {
errno = EINVAL;
return (-1);
}
*flagset_d = 0;
return (0);
}
int
acl_delete_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
{
if (flagset_d == NULL) {
errno = EINVAL;
return (-1);
}
if (_flag_is_invalid(flag))
return (-1);
*flagset_d &= ~flag;
return (0);
}
int
acl_get_flag_np(acl_flagset_t flagset_d, acl_flag_t flag)
{
if (flagset_d == NULL) {
errno = EINVAL;
return (-1);
}
if (_flag_is_invalid(flag))
return (-1);
if (*flagset_d & flag)
return (1);
return (0);
}
int
acl_get_flagset_np(acl_entry_t entry_d, acl_flagset_t *flagset_p)
{
if (entry_d == NULL || flagset_p == NULL) {
errno = EINVAL;
return (-1);
}
if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
errno = EINVAL;
return (-1);
}
*flagset_p = &entry_d->ae_flags;
return (0);
}
int
acl_set_flagset_np(acl_entry_t entry_d, acl_flagset_t flagset_d)
{
if (entry_d == NULL) {
errno = EINVAL;
return (-1);
}
if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
errno = EINVAL;
return (-1);
}
_entry_brand_as(entry_d, ACL_BRAND_NFS4);
if (_flag_is_invalid(*flagset_d))
return (-1);
entry_d->ae_flags = *flagset_d;
return (0);
}
diff --git a/lib/libc/posix1e/acl_free.c b/lib/libc/posix1e/acl_free.c
index 1de6d3105047..813ec6a35fb6 100644
--- a/lib/libc/posix1e/acl_free.c
+++ b/lib/libc/posix1e/acl_free.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_free -- free ACL objects from user memory
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <sys/errno.h>
#include <stdlib.h>
/*
* acl_free() (23.4.12): free any releasable memory allocated to the
* ACL data object identified by obj_p.
*/
int
acl_free(void *obj_p)
{
if (obj_p) {
free(obj_p);
obj_p = NULL;
}
return (0);
}
diff --git a/lib/libc/posix1e/acl_from_mode_np.c b/lib/libc/posix1e/acl_from_mode_np.c
index b08cc5b5e6a0..3d4135770917 100644
--- a/lib/libc/posix1e/acl_from_mode_np.c
+++ b/lib/libc/posix1e/acl_from_mode_np.c
@@ -1,113 +1,112 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 Robert N M Watson, Gleb Popov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_from_mode_np: Create an ACL from a mode_t.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/acl.h>
#include <sys/stat.h>
/*
* return an ACL corresponding to the permissions
* contained in mode_t
*/
acl_t
acl_from_mode_np(const mode_t mode)
{
acl_t acl;
acl_entry_t entry;
acl_permset_t perms;
/* create the ACL */
acl = acl_init(3);
/* here and below, the only possible reason to fail is ENOMEM, so
* no need to set errno again
*/
if (acl == NULL)
return (NULL);
/* First entry: ACL_USER_OBJ */
if (acl_create_entry(&acl, &entry) == -1)
return (NULL);
/* TODO: need to handle error there and below? */
acl_set_tag_type(entry, ACL_USER_OBJ);
acl_get_permset(entry, &perms);
acl_clear_perms(perms);
/* calculate user mode */
if (mode & S_IRUSR)
acl_add_perm(perms, ACL_READ);
if (mode & S_IWUSR)
acl_add_perm(perms, ACL_WRITE);
if (mode & S_IXUSR)
acl_add_perm(perms, ACL_EXECUTE);
acl_set_permset(entry, perms);
/* Second entry: ACL_GROUP_OBJ */
if (acl_create_entry(&acl, &entry) == -1)
return (NULL);
acl_set_tag_type(entry, ACL_GROUP_OBJ);
acl_get_permset(entry, &perms);
acl_clear_perms(perms);
/* calculate group mode */
if (mode & S_IRGRP)
acl_add_perm(perms, ACL_READ);
if (mode & S_IWGRP)
acl_add_perm(perms, ACL_WRITE);
if (mode & S_IXGRP)
acl_add_perm(perms, ACL_EXECUTE);
acl_set_permset(entry, perms);
/* Third entry: ACL_OTHER */
if (acl_create_entry(&acl, &entry) == -1)
return (NULL);
acl_set_tag_type(entry, ACL_OTHER);
acl_get_permset(entry, &perms);
acl_clear_perms(perms);
/* calculate other mode */
if (mode & S_IROTH)
acl_add_perm(perms, ACL_READ);
if (mode & S_IWOTH)
acl_add_perm(perms, ACL_WRITE);
if (mode & S_IXOTH)
acl_add_perm(perms, ACL_EXECUTE);
acl_set_permset(entry, perms);
return (acl);
}
diff --git a/lib/libc/posix1e/acl_from_text.c b/lib/libc/posix1e/acl_from_text.c
index 2a1c21fa7859..765b58290a04 100644
--- a/lib/libc/posix1e/acl_from_text.c
+++ b/lib/libc/posix1e/acl_from_text.c
@@ -1,313 +1,312 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_from_text: Convert a text-form ACL from a string to an acl_t.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <sys/errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "acl_support.h"
static acl_tag_t acl_string_to_tag(char *tag, char *qualifier);
int _nfs4_acl_entry_from_text(acl_t aclp, char *entry);
int _text_could_be_nfs4_acl(const char *entry);
static acl_tag_t
acl_string_to_tag(char *tag, char *qualifier)
{
if (*qualifier == '\0') {
if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
return (ACL_USER_OBJ);
} else
if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
return (ACL_GROUP_OBJ);
} else
if ((!strcmp(tag, "mask")) || (!strcmp(tag, "m"))) {
return (ACL_MASK);
} else
if ((!strcmp(tag, "other")) || (!strcmp(tag, "o"))) {
return (ACL_OTHER);
} else
return(-1);
} else {
if ((!strcmp(tag, "user")) || (!strcmp(tag, "u"))) {
return(ACL_USER);
} else
if ((!strcmp(tag, "group")) || (!strcmp(tag, "g"))) {
return(ACL_GROUP);
} else
return(-1);
}
}
static int
_posix1e_acl_entry_from_text(acl_t aclp, char *entry)
{
acl_tag_t t;
acl_perm_t p;
char *tag, *qualifier, *permission;
uid_t id;
int error;
assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
/* Split into three ':' delimited fields. */
tag = strsep(&entry, ":");
if (tag == NULL) {
errno = EINVAL;
return (-1);
}
tag = string_skip_whitespace(tag);
if ((*tag == '\0') && (!entry)) {
/*
* Is an entirely comment line, skip to next
* comma.
*/
return (0);
}
string_trim_trailing_whitespace(tag);
qualifier = strsep(&entry, ":");
if (qualifier == NULL) {
errno = EINVAL;
return (-1);
}
qualifier = string_skip_whitespace(qualifier);
string_trim_trailing_whitespace(qualifier);
permission = strsep(&entry, ":");
if (permission == NULL || entry) {
errno = EINVAL;
return (-1);
}
permission = string_skip_whitespace(permission);
string_trim_trailing_whitespace(permission);
t = acl_string_to_tag(tag, qualifier);
if (t == -1) {
errno = EINVAL;
return (-1);
}
error = _posix1e_acl_string_to_perm(permission, &p);
if (error == -1) {
errno = EINVAL;
return (-1);
}
switch(t) {
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_MASK:
case ACL_OTHER:
if (*qualifier != '\0') {
errno = EINVAL;
return (-1);
}
id = 0;
break;
case ACL_USER:
case ACL_GROUP:
error = _acl_name_to_id(t, qualifier, &id);
if (error == -1)
return (-1);
break;
default:
errno = EINVAL;
return (-1);
}
error = _posix1e_acl_add_entry(aclp, t, id, p);
if (error == -1)
return (-1);
return (0);
}
static int
_text_is_nfs4_entry(const char *entry)
{
int count = 0;
assert(strlen(entry) > 0);
while (*entry != '\0') {
if (*entry == ':' || *entry == '@')
count++;
entry++;
}
if (count <= 2)
return (0);
return (1);
}
/*
* acl_from_text -- Convert a string into an ACL.
* Postpone most validity checking until the end and call acl_valid() to do
* that.
*/
acl_t
acl_from_text(const char *buf_p)
{
acl_t acl;
char *mybuf_p, *line, *cur, *notcomment, *comment, *entry;
int error;
/* Local copy we can mess up. */
mybuf_p = strdup(buf_p);
if (mybuf_p == NULL)
return(NULL);
acl = acl_init(3); /* XXX: WTF, 3? */
if (acl == NULL) {
free(mybuf_p);
return(NULL);
}
/* Outer loop: delimit at \n boundaries. */
cur = mybuf_p;
while ((line = strsep(&cur, "\n"))) {
/* Now split the line on the first # to strip out comments. */
comment = line;
notcomment = strsep(&comment, "#");
/* Inner loop: delimit at ',' boundaries. */
while ((entry = strsep(&notcomment, ","))) {
/* Skip empty lines. */
if (strlen(string_skip_whitespace(entry)) == 0)
continue;
if (_acl_brand(acl) == ACL_BRAND_UNKNOWN) {
if (_text_is_nfs4_entry(entry))
_acl_brand_as(acl, ACL_BRAND_NFS4);
else
_acl_brand_as(acl, ACL_BRAND_POSIX);
}
switch (_acl_brand(acl)) {
case ACL_BRAND_NFS4:
error = _nfs4_acl_entry_from_text(acl, entry);
break;
case ACL_BRAND_POSIX:
error = _posix1e_acl_entry_from_text(acl, entry);
break;
default:
error = EINVAL;
break;
}
if (error)
goto error_label;
}
}
#if 0
/* XXX Should we only return ACLs valid according to acl_valid? */
/* Verify validity of the ACL we read in. */
if (acl_valid(acl) == -1) {
errno = EINVAL;
goto error_label;
}
#endif
free(mybuf_p);
return(acl);
error_label:
acl_free(acl);
free(mybuf_p);
return(NULL);
}
/*
* Given a username/groupname from a text form of an ACL, return the uid/gid
* XXX NOT THREAD SAFE, RELIES ON GETPWNAM, GETGRNAM
* XXX USES *PW* AND *GR* WHICH ARE STATEFUL AND THEREFORE THIS ROUTINE
* MAY HAVE SIDE-EFFECTS
*/
int
_acl_name_to_id(acl_tag_t tag, char *name, uid_t *id)
{
struct group *g;
struct passwd *p;
unsigned long l;
char *endp;
switch(tag) {
case ACL_USER:
p = getpwnam(name);
if (p == NULL) {
l = strtoul(name, &endp, 0);
if (*endp != '\0' || l != (unsigned long)(uid_t)l) {
errno = EINVAL;
return (-1);
}
*id = (uid_t)l;
return (0);
}
*id = p->pw_uid;
return (0);
case ACL_GROUP:
g = getgrnam(name);
if (g == NULL) {
l = strtoul(name, &endp, 0);
if (*endp != '\0' || l != (unsigned long)(gid_t)l) {
errno = EINVAL;
return (-1);
}
*id = (gid_t)l;
return (0);
}
*id = g->gr_gid;
return (0);
default:
return (EINVAL);
}
}
diff --git a/lib/libc/posix1e/acl_from_text_nfs4.c b/lib/libc/posix1e/acl_from_text_nfs4.c
index 41fb96973d91..ed82c1093bc4 100644
--- a/lib/libc/posix1e/acl_from_text_nfs4.c
+++ b/lib/libc/posix1e/acl_from_text_nfs4.c
@@ -1,282 +1,281 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <ctype.h>
#include <err.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/acl.h>
#include "acl_support.h"
#define MAX_ENTRY_LENGTH 512
/*
* Parse the tag field of ACL entry passed as "str". If qualifier
* needs to follow, then the variable referenced by "need_qualifier"
* is set to 1, otherwise it's set to 0.
*/
static int
parse_tag(const char *str, acl_entry_t entry, int *need_qualifier)
{
assert(need_qualifier != NULL);
*need_qualifier = 0;
if (strcmp(str, "owner@") == 0)
return (acl_set_tag_type(entry, ACL_USER_OBJ));
if (strcmp(str, "group@") == 0)
return (acl_set_tag_type(entry, ACL_GROUP_OBJ));
if (strcmp(str, "everyone@") == 0)
return (acl_set_tag_type(entry, ACL_EVERYONE));
*need_qualifier = 1;
if (strcmp(str, "user") == 0 || strcmp(str, "u") == 0)
return (acl_set_tag_type(entry, ACL_USER));
if (strcmp(str, "group") == 0 || strcmp(str, "g") == 0)
return (acl_set_tag_type(entry, ACL_GROUP));
warnx("malformed ACL: invalid \"tag\" field");
return (-1);
}
/*
* Parse the qualifier field of ACL entry passed as "str".
* If user or group name cannot be resolved, then the variable
* referenced by "need_qualifier" is set to 1; it will be checked
* later to figure out whether the appended_id is required.
*/
static int
parse_qualifier(char *str, acl_entry_t entry, int *need_qualifier)
{
int qualifier_length, error;
uid_t id;
acl_tag_t tag;
assert(need_qualifier != NULL);
*need_qualifier = 0;
qualifier_length = strlen(str);
if (qualifier_length == 0) {
warnx("malformed ACL: empty \"qualifier\" field");
return (-1);
}
error = acl_get_tag_type(entry, &tag);
if (error)
return (error);
error = _acl_name_to_id(tag, str, &id);
if (error) {
*need_qualifier = 1;
return (0);
}
return (acl_set_qualifier(entry, &id));
}
static int
parse_access_mask(char *str, acl_entry_t entry)
{
int error;
acl_perm_t perm;
error = _nfs4_parse_access_mask(str, &perm);
if (error)
return (error);
error = acl_set_permset(entry, &perm);
return (error);
}
static int
parse_flags(char *str, acl_entry_t entry)
{
int error;
acl_flag_t flags;
error = _nfs4_parse_flags(str, &flags);
if (error)
return (error);
error = acl_set_flagset_np(entry, &flags);
return (error);
}
static int
parse_entry_type(const char *str, acl_entry_t entry)
{
if (strcmp(str, "allow") == 0)
return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALLOW));
if (strcmp(str, "deny") == 0)
return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_DENY));
if (strcmp(str, "audit") == 0)
return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_AUDIT));
if (strcmp(str, "alarm") == 0)
return (acl_set_entry_type_np(entry, ACL_ENTRY_TYPE_ALARM));
warnx("malformed ACL: invalid \"type\" field");
return (-1);
}
static int
parse_appended_id(char *str, acl_entry_t entry)
{
int qualifier_length;
char *end;
id_t id;
qualifier_length = strlen(str);
if (qualifier_length == 0) {
warnx("malformed ACL: \"appended id\" field present, "
"but empty");
return (-1);
}
id = strtod(str, &end);
if (end - str != qualifier_length) {
warnx("malformed ACL: appended id is not a number");
return (-1);
}
return (acl_set_qualifier(entry, &id));
}
static int
number_of_colons(const char *str)
{
int count = 0;
while (*str != '\0') {
if (*str == ':')
count++;
str++;
}
return (count);
}
int
_nfs4_acl_entry_from_text(acl_t aclp, char *str)
{
int error, need_qualifier;
acl_entry_t entry;
char *field, *qualifier_field;
error = acl_create_entry(&aclp, &entry);
if (error)
return (error);
assert(_entry_brand(entry) == ACL_BRAND_NFS4);
if (str == NULL)
goto truncated_entry;
field = strsep(&str, ":");
field = string_skip_whitespace(field);
if ((*field == '\0') && (!str)) {
/*
* Is an entirely comment line, skip to next
* comma.
*/
return (0);
}
error = parse_tag(field, entry, &need_qualifier);
if (error)
goto malformed_field;
if (need_qualifier) {
if (str == NULL)
goto truncated_entry;
qualifier_field = field = strsep(&str, ":");
error = parse_qualifier(field, entry, &need_qualifier);
if (error)
goto malformed_field;
}
if (str == NULL)
goto truncated_entry;
field = strsep(&str, ":");
error = parse_access_mask(field, entry);
if (error)
goto malformed_field;
if (str == NULL)
goto truncated_entry;
/* Do we have "flags" field? */
if (number_of_colons(str) > 0) {
field = strsep(&str, ":");
error = parse_flags(field, entry);
if (error)
goto malformed_field;
}
if (str == NULL)
goto truncated_entry;
field = strsep(&str, ":");
error = parse_entry_type(field, entry);
if (error)
goto malformed_field;
if (need_qualifier) {
if (str == NULL) {
warnx("malformed ACL: unknown user or group name "
"\"%s\"", qualifier_field);
goto truncated_entry;
}
error = parse_appended_id(str, entry);
if (error)
goto malformed_field;
}
return (0);
truncated_entry:
malformed_field:
acl_delete_entry(aclp, entry);
errno = EINVAL;
return (-1);
}
diff --git a/lib/libc/posix1e/acl_get.c b/lib/libc/posix1e/acl_get.c
index f5191d739dcc..a02c2d53085d 100644
--- a/lib/libc/posix1e/acl_get.c
+++ b/lib/libc/posix1e/acl_get.c
@@ -1,216 +1,215 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_get_fd - syscall wrapper for retrieving access ACL by fd
* acl_get_fd_np - syscall wrapper for retrieving ACL by fd (non-POSIX)
* acl_get_file - syscall wrapper for retrieving ACL by filename
* acl_get_link_np - syscall wrapper for retrieving ACL by filename (NOFOLLOW)
* (non-POSIX)
* acl_get_perm_np() checks if a permission is in the specified
* permset (non-POSIX)
* acl_get_permset() returns the permission set in the ACL entry
* acl_get_qualifier() retrieves the qualifier of the tag from the ACL entry
* acl_get_tag_type() returns the tag type for the ACL entry entry_d
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "acl_support.h"
acl_t
acl_get_file(const char *path_p, acl_type_t type)
{
acl_t aclp;
int error;
aclp = acl_init(ACL_MAX_ENTRIES);
if (aclp == NULL)
return (NULL);
type = _acl_type_unold(type);
error = __acl_get_file(path_p, type, &aclp->ats_acl);
if (error) {
acl_free(aclp);
return (NULL);
}
aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
_acl_brand_from_type(aclp, type);
return (aclp);
}
acl_t
acl_get_link_np(const char *path_p, acl_type_t type)
{
acl_t aclp;
int error;
aclp = acl_init(ACL_MAX_ENTRIES);
if (aclp == NULL)
return (NULL);
type = _acl_type_unold(type);
error = __acl_get_link(path_p, type, &aclp->ats_acl);
if (error) {
acl_free(aclp);
return (NULL);
}
aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
_acl_brand_from_type(aclp, type);
return (aclp);
}
acl_t
acl_get_fd(int fd)
{
if (fpathconf(fd, _PC_ACL_NFS4) == 1)
return (acl_get_fd_np(fd, ACL_TYPE_NFS4));
return (acl_get_fd_np(fd, ACL_TYPE_ACCESS));
}
acl_t
acl_get_fd_np(int fd, acl_type_t type)
{
acl_t aclp;
int error;
aclp = acl_init(ACL_MAX_ENTRIES);
if (aclp == NULL)
return (NULL);
type = _acl_type_unold(type);
error = ___acl_get_fd(fd, type, &aclp->ats_acl);
if (error) {
acl_free(aclp);
return (NULL);
}
aclp->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
_acl_brand_from_type(aclp, type);
return (aclp);
}
/*
* acl_get_permset() (23.4.17): return via permset_p a descriptor to
* the permission set in the ACL entry entry_d.
*/
int
acl_get_permset(acl_entry_t entry_d, acl_permset_t *permset_p)
{
if (entry_d == NULL || permset_p == NULL) {
errno = EINVAL;
return (-1);
}
*permset_p = &entry_d->ae_perm;
return (0);
}
/*
* acl_get_qualifier() (23.4.18): retrieve the qualifier of the tag
* for the ACL entry entry_d.
*/
void *
acl_get_qualifier(acl_entry_t entry_d)
{
uid_t *retval;
if (entry_d == NULL) {
errno = EINVAL;
return (NULL);
}
switch(entry_d->ae_tag) {
case ACL_USER:
case ACL_GROUP:
retval = malloc(sizeof(uid_t));
if (retval == NULL)
return (NULL);
*retval = entry_d->ae_id;
return (retval);
}
errno = EINVAL;
return (NULL);
}
/*
* acl_get_tag_type() (23.4.19): return the tag type for the ACL
* entry entry_p.
*/
int
acl_get_tag_type(acl_entry_t entry_d, acl_tag_t *tag_type_p)
{
if (entry_d == NULL || tag_type_p == NULL) {
errno = EINVAL;
return (-1);
}
*tag_type_p = entry_d->ae_tag;
return (0);
}
int
acl_get_entry_type_np(acl_entry_t entry_d, acl_entry_type_t *entry_type_p)
{
if (entry_d == NULL || entry_type_p == NULL) {
errno = EINVAL;
return (-1);
}
if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
errno = EINVAL;
return (-1);
}
*entry_type_p = entry_d->ae_entry_type;
return (0);
}
diff --git a/lib/libc/posix1e/acl_id_to_name.c b/lib/libc/posix1e/acl_id_to_name.c
index b5afe7d16613..78e050a8648a 100644
--- a/lib/libc/posix1e/acl_id_to_name.c
+++ b/lib/libc/posix1e/acl_id_to_name.c
@@ -1,100 +1,99 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999-2001, 2008 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Support functionality for the POSIX.1e ACL interface
* These calls are intended only to be called within the library.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "acl_support.h"
/*
* Given a uid/gid, return a username/groupname for the text form of an ACL.
* Note that we truncate user and group names, rather than error out, as
* this is consistent with other tools manipulating user and group names.
* XXX NOT THREAD SAFE, RELIES ON GETPWUID, GETGRGID
* XXX USES *PW* AND *GR* WHICH ARE STATEFUL AND THEREFORE THIS ROUTINE
* MAY HAVE SIDE-EFFECTS
*/
int
_posix1e_acl_id_to_name(acl_tag_t tag, uid_t id, ssize_t buf_len, char *buf,
int flags)
{
struct group *g;
struct passwd *p;
int i;
switch(tag) {
case ACL_USER:
if (flags & ACL_TEXT_NUMERIC_IDS)
p = NULL;
else
p = getpwuid(id);
if (!p)
i = snprintf(buf, buf_len, "%d", id);
else
i = snprintf(buf, buf_len, "%s", p->pw_name);
if (i < 0) {
errno = ENOMEM;
return (-1);
}
return (0);
case ACL_GROUP:
if (flags & ACL_TEXT_NUMERIC_IDS)
g = NULL;
else
g = getgrgid(id);
if (g == NULL)
i = snprintf(buf, buf_len, "%d", id);
else
i = snprintf(buf, buf_len, "%s", g->gr_name);
if (i < 0) {
errno = ENOMEM;
return (-1);
}
return (0);
default:
return (EINVAL);
}
}
diff --git a/lib/libc/posix1e/acl_init.c b/lib/libc/posix1e/acl_init.c
index eaa554df4fe8..587817388081 100644
--- a/lib/libc/posix1e/acl_init.c
+++ b/lib/libc/posix1e/acl_init.c
@@ -1,95 +1,94 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_init -- return a fresh acl structure
* acl_dup -- duplicate an acl and return the new copy
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "acl_support.h"
#ifndef CTASSERT
#define CTASSERT(x) _CTASSERT(x, __LINE__)
#define _CTASSERT(x, y) __CTASSERT(x, y)
#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1]
#endif
CTASSERT(1 << _ACL_T_ALIGNMENT_BITS > sizeof(struct acl_t_struct));
acl_t
acl_init(int count)
{
int error;
acl_t acl;
if (count > ACL_MAX_ENTRIES) {
errno = ENOMEM;
return (NULL);
}
if (count < 0) {
errno = EINVAL;
return (NULL);
}
error = posix_memalign((void *)&acl, 1 << _ACL_T_ALIGNMENT_BITS,
sizeof(struct acl_t_struct));
if (error) {
errno = error;
return (NULL);
}
bzero(acl, sizeof(struct acl_t_struct));
acl->ats_brand = ACL_BRAND_UNKNOWN;
acl->ats_acl.acl_maxcnt = ACL_MAX_ENTRIES;
return (acl);
}
acl_t
acl_dup(acl_t acl)
{
acl_t acl_new;
acl_new = acl_init(ACL_MAX_ENTRIES);
if (acl_new != NULL) {
*acl_new = *acl;
acl->ats_cur_entry = 0;
acl_new->ats_cur_entry = 0;
}
return (acl_new);
}
diff --git a/lib/libc/posix1e/acl_perm.c b/lib/libc/posix1e/acl_perm.c
index f6abf404c4f8..9ad103398646 100644
--- a/lib/libc/posix1e/acl_perm.c
+++ b/lib/libc/posix1e/acl_perm.c
@@ -1,128 +1,127 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001-2002 Chris D. Faulhaber
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <string.h>
static int
_perm_is_invalid(acl_perm_t perm)
{
/* Check if more than a single bit is set. */
if ((perm & -perm) == perm &&
(perm & (ACL_POSIX1E_BITS | ACL_NFS4_PERM_BITS)) == perm)
return (0);
errno = EINVAL;
return (1);
}
/*
* acl_add_perm() (23.4.1): add the permission contained in perm to the
* permission set permset_d
*/
int
acl_add_perm(acl_permset_t permset_d, acl_perm_t perm)
{
if (permset_d == NULL) {
errno = EINVAL;
return (-1);
}
if (_perm_is_invalid(perm))
return (-1);
*permset_d |= perm;
return (0);
}
/*
* acl_clear_perms() (23.4.3): clear all permisions from the permission
* set permset_d
*/
int
acl_clear_perms(acl_permset_t permset_d)
{
if (permset_d == NULL) {
errno = EINVAL;
return (-1);
}
*permset_d = ACL_PERM_NONE;
return (0);
}
/*
* acl_delete_perm() (23.4.10): remove the permission in perm from the
* permission set permset_d
*/
int
acl_delete_perm(acl_permset_t permset_d, acl_perm_t perm)
{
if (permset_d == NULL) {
errno = EINVAL;
return (-1);
}
if (_perm_is_invalid(perm))
return (-1);
*permset_d &= ~perm;
return (0);
}
int
acl_get_perm_np(acl_permset_t permset_d, acl_perm_t perm)
{
if (permset_d == NULL) {
errno = EINVAL;
return (-1);
}
if (_perm_is_invalid(perm))
return (-1);
if (*permset_d & perm)
return (1);
return (0);
}
diff --git a/lib/libc/posix1e/acl_set.c b/lib/libc/posix1e/acl_set.c
index 5edc291b5171..359dda2c1619 100644
--- a/lib/libc/posix1e/acl_set.c
+++ b/lib/libc/posix1e/acl_set.c
@@ -1,253 +1,252 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_set_file -- set a file/directory ACL by name
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "acl_support.h"
/*
* For POSIX.1e-semantic ACLs, do a presort so the kernel doesn't have to
* (the POSIX.1e semantic code will reject unsorted ACL submission). If it's
* not a semantic that the library knows about, just submit it flat and
* assume the caller knows what they're up to.
*/
int
acl_set_file(const char *path_p, acl_type_t type, acl_t acl)
{
if (acl == NULL || path_p == NULL) {
errno = EINVAL;
return (-1);
}
type = _acl_type_unold(type);
if (_acl_type_not_valid_for_acl(acl, type)) {
errno = EINVAL;
return (-1);
}
if (_posix1e_acl(acl, type))
_posix1e_acl_sort(acl);
acl->ats_cur_entry = 0;
return (__acl_set_file(path_p, type, &acl->ats_acl));
}
int
acl_set_link_np(const char *path_p, acl_type_t type, acl_t acl)
{
if (acl == NULL || path_p == NULL) {
errno = EINVAL;
return (-1);
}
type = _acl_type_unold(type);
if (_acl_type_not_valid_for_acl(acl, type)) {
errno = EINVAL;
return (-1);
}
if (_posix1e_acl(acl, type))
_posix1e_acl_sort(acl);
acl->ats_cur_entry = 0;
return (__acl_set_link(path_p, type, &acl->ats_acl));
}
int
acl_set_fd(int fd, acl_t acl)
{
if (fpathconf(fd, _PC_ACL_NFS4) == 1)
return (acl_set_fd_np(fd, acl, ACL_TYPE_NFS4));
return (acl_set_fd_np(fd, acl, ACL_TYPE_ACCESS));
}
int
acl_set_fd_np(int fd, acl_t acl, acl_type_t type)
{
if (acl == NULL) {
errno = EINVAL;
return (-1);
}
type = _acl_type_unold(type);
if (_acl_type_not_valid_for_acl(acl, type)) {
errno = EINVAL;
return (-1);
}
if (_posix1e_acl(acl, type))
_posix1e_acl_sort(acl);
acl->ats_cur_entry = 0;
return (___acl_set_fd(fd, type, &acl->ats_acl));
}
/*
* acl_set_permset() (23.4.23): sets the permissions of ACL entry entry_d
* with the permissions in permset_d
*/
int
acl_set_permset(acl_entry_t entry_d, acl_permset_t permset_d)
{
if (!entry_d) {
errno = EINVAL;
return (-1);
}
if ((*permset_d & ACL_POSIX1E_BITS) != *permset_d) {
if ((*permset_d & ACL_NFS4_PERM_BITS) != *permset_d) {
errno = EINVAL;
return (-1);
}
if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
errno = EINVAL;
return (-1);
}
_entry_brand_as(entry_d, ACL_BRAND_NFS4);
}
entry_d->ae_perm = *permset_d;
return (0);
}
/*
* acl_set_qualifier() sets the qualifier (ae_id) of the tag for
* ACL entry entry_d to the value referred to by tag_qualifier_p
*/
int
acl_set_qualifier(acl_entry_t entry_d, const void *tag_qualifier_p)
{
if (!entry_d || !tag_qualifier_p) {
errno = EINVAL;
return (-1);
}
switch(entry_d->ae_tag) {
case ACL_USER:
case ACL_GROUP:
entry_d->ae_id = *(uid_t *)tag_qualifier_p;
break;
default:
errno = EINVAL;
return (-1);
}
return (0);
}
/*
* acl_set_tag_type() sets the tag type for ACL entry entry_d to the
* value of tag_type
*/
int
acl_set_tag_type(acl_entry_t entry_d, acl_tag_t tag_type)
{
if (entry_d == NULL) {
errno = EINVAL;
return (-1);
}
switch(tag_type) {
case ACL_OTHER:
case ACL_MASK:
if (!_entry_brand_may_be(entry_d, ACL_BRAND_POSIX)) {
errno = EINVAL;
return (-1);
}
_entry_brand_as(entry_d, ACL_BRAND_POSIX);
break;
case ACL_EVERYONE:
if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
errno = EINVAL;
return (-1);
}
_entry_brand_as(entry_d, ACL_BRAND_NFS4);
break;
}
switch(tag_type) {
case ACL_USER_OBJ:
case ACL_USER:
case ACL_GROUP_OBJ:
case ACL_GROUP:
case ACL_MASK:
case ACL_OTHER:
case ACL_EVERYONE:
entry_d->ae_tag = tag_type;
return (0);
}
errno = EINVAL;
return (-1);
}
int
acl_set_entry_type_np(acl_entry_t entry_d, acl_entry_type_t entry_type)
{
if (entry_d == NULL) {
errno = EINVAL;
return (-1);
}
if (!_entry_brand_may_be(entry_d, ACL_BRAND_NFS4)) {
errno = EINVAL;
return (-1);
}
_entry_brand_as(entry_d, ACL_BRAND_NFS4);
switch (entry_type) {
case ACL_ENTRY_TYPE_ALLOW:
case ACL_ENTRY_TYPE_DENY:
case ACL_ENTRY_TYPE_AUDIT:
case ACL_ENTRY_TYPE_ALARM:
entry_d->ae_entry_type = entry_type;
return (0);
}
errno = EINVAL;
return (-1);
}
diff --git a/lib/libc/posix1e/acl_strip.c b/lib/libc/posix1e/acl_strip.c
index ac6c94e66f86..9af1ad680036 100644
--- a/lib/libc/posix1e/acl_strip.c
+++ b/lib/libc/posix1e/acl_strip.c
@@ -1,224 +1,223 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Chris D. Faulhaber
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdio.h>
#include <assert.h>
#include <sys/acl.h>
#include <sys/stat.h>
#include "acl_support.h"
/*
* These routines from sys/kern/subr_acl_nfs4.c are used by both kernel
* and libc.
*/
void acl_nfs4_sync_mode_from_acl(mode_t *_mode, const struct acl *aclp);
void acl_nfs4_trivial_from_mode_libc(struct acl *aclp, int file_owner_id,
int canonical_six);
static acl_t
_nfs4_acl_strip_np(const acl_t aclp, int canonical_six)
{
acl_t newacl;
mode_t mode = 0;
newacl = acl_init(ACL_MAX_ENTRIES);
if (newacl == NULL) {
errno = ENOMEM;
return (NULL);
}
_acl_brand_as(newacl, ACL_BRAND_NFS4);
acl_nfs4_sync_mode_from_acl(&mode, &(aclp->ats_acl));
acl_nfs4_trivial_from_mode_libc(&(newacl->ats_acl), mode, canonical_six);
return (newacl);
}
static acl_t
_posix1e_acl_strip_np(const acl_t aclp, int recalculate_mask)
{
acl_t acl_new, acl_old;
acl_entry_t entry, entry_new;
acl_tag_t tag;
int entry_id, have_mask_entry;
assert(_acl_brand(aclp) == ACL_BRAND_POSIX);
acl_old = acl_dup(aclp);
if (acl_old == NULL)
return (NULL);
assert(_acl_brand(acl_old) == ACL_BRAND_POSIX);
have_mask_entry = 0;
acl_new = acl_init(ACL_MAX_ENTRIES);
if (acl_new == NULL) {
acl_free(acl_old);
return (NULL);
}
tag = ACL_UNDEFINED_TAG;
/* only save the default user/group/other entries */
entry_id = ACL_FIRST_ENTRY;
while (acl_get_entry(acl_old, entry_id, &entry) == 1) {
entry_id = ACL_NEXT_ENTRY;
assert(_entry_brand(entry) == ACL_BRAND_POSIX);
if (acl_get_tag_type(entry, &tag) == -1)
goto fail;
switch(tag) {
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_OTHER:
if (acl_create_entry(&acl_new, &entry_new) == -1)
goto fail;
if (acl_copy_entry(entry_new, entry) == -1)
goto fail;
assert(_entry_brand(entry_new) == ACL_BRAND_POSIX);
break;
case ACL_MASK:
have_mask_entry = 1;
break;
default:
break;
}
}
assert(_acl_brand(acl_new) == ACL_BRAND_POSIX);
if (have_mask_entry && recalculate_mask) {
if (acl_calc_mask(&acl_new) == -1)
goto fail;
}
return (acl_new);
fail:
acl_free(acl_new);
acl_free(acl_old);
return (NULL);
}
acl_t
acl_strip_np(const acl_t aclp, int recalculate_mask)
{
switch (_acl_brand(aclp)) {
case ACL_BRAND_NFS4:
return (_nfs4_acl_strip_np(aclp, 0));
case ACL_BRAND_POSIX:
return (_posix1e_acl_strip_np(aclp, recalculate_mask));
default:
errno = EINVAL;
return (NULL);
}
}
/*
* Return 1, if ACL is trivial, 0 otherwise.
*
* ACL is trivial, iff its meaning could be fully expressed using just file
* mode. In other words, ACL is trivial iff it doesn't have "+" to the right
* of the mode bits in "ls -l" output ;-)
*/
int
acl_is_trivial_np(const acl_t aclp, int *trivialp)
{
acl_t tmpacl;
int differs;
if (aclp == NULL || trivialp == NULL) {
errno = EINVAL;
return (-1);
}
switch (_acl_brand(aclp)) {
case ACL_BRAND_POSIX:
if (aclp->ats_acl.acl_cnt == 3)
*trivialp = 1;
else
*trivialp = 0;
return (0);
case ACL_BRAND_NFS4:
/*
* If the ACL has more than canonical six entries,
* it's non trivial by definition.
*/
if (aclp->ats_acl.acl_cnt > 6) {
*trivialp = 0;
return (0);
}
/*
* Calculate trivial ACL - using acl_strip_np(3) - and compare
* with the original.
*/
tmpacl = _nfs4_acl_strip_np(aclp, 0);
if (tmpacl == NULL)
return (-1);
differs = _acl_differs(aclp, tmpacl);
acl_free(tmpacl);
if (differs == 0) {
*trivialp = 1;
return (0);
}
/*
* Try again with an old-style, "canonical six" trivial ACL.
*/
tmpacl = _nfs4_acl_strip_np(aclp, 1);
if (tmpacl == NULL)
return (-1);
differs = _acl_differs(aclp, tmpacl);
acl_free(tmpacl);
if (differs)
*trivialp = 0;
else
*trivialp = 1;
return (0);
default:
errno = EINVAL;
return (-1);
}
}
diff --git a/lib/libc/posix1e/acl_support.c b/lib/libc/posix1e/acl_support.c
index c4552d9799a2..82abeb0273f9 100644
--- a/lib/libc/posix1e/acl_support.c
+++ b/lib/libc/posix1e/acl_support.c
@@ -1,416 +1,415 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999-2001, 2008 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Support functionality for the POSIX.1e ACL interface
* These calls are intended only to be called within the library.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <errno.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "acl_support.h"
#define ACL_STRING_PERM_WRITE 'w'
#define ACL_STRING_PERM_READ 'r'
#define ACL_STRING_PERM_EXEC 'x'
#define ACL_STRING_PERM_NONE '-'
/*
* Return 0, if both ACLs are identical.
*/
int
_acl_differs(const acl_t a, const acl_t b)
{
int i;
struct acl_entry *entrya, *entryb;
assert(_acl_brand(a) == _acl_brand(b));
if (a->ats_acl.acl_cnt != b->ats_acl.acl_cnt)
return (1);
for (i = 0; i < b->ats_acl.acl_cnt; i++) {
entrya = &(a->ats_acl.acl_entry[i]);
entryb = &(b->ats_acl.acl_entry[i]);
if (entrya->ae_tag != entryb->ae_tag ||
entrya->ae_id != entryb->ae_id ||
entrya->ae_perm != entryb->ae_perm ||
entrya->ae_entry_type != entryb->ae_entry_type ||
entrya->ae_flags != entryb->ae_flags)
return (1);
}
return (0);
}
/*
* _posix1e_acl_entry_compare -- compare two acl_entry structures to
* determine the order they should appear in. Used by _posix1e_acl_sort to
* sort ACL entries into the kernel-desired order -- i.e., the order useful
* for evaluation and O(n) validity checking. Beter to have an O(nlogn) sort
* in userland and an O(n) in kernel than to have both in kernel.
*/
typedef int (*compare)(const void *, const void *);
static int
_posix1e_acl_entry_compare(struct acl_entry *a, struct acl_entry *b)
{
assert(_entry_brand(a) == ACL_BRAND_POSIX);
assert(_entry_brand(b) == ACL_BRAND_POSIX);
/*
* First, sort between tags -- conveniently defined in the correct
* order for verification.
*/
if (a->ae_tag < b->ae_tag)
return (-1);
if (a->ae_tag > b->ae_tag)
return (1);
/*
* Next compare uids/gids on appropriate types.
*/
if (a->ae_tag == ACL_USER || a->ae_tag == ACL_GROUP) {
if (a->ae_id < b->ae_id)
return (-1);
if (a->ae_id > b->ae_id)
return (1);
/* shouldn't be equal, fall through to the invalid case */
}
/*
* Don't know how to sort multiple entries of the rest--either it's
* a bad entry, or there shouldn't be more than one. Ignore and the
* validity checker can get it later.
*/
return (0);
}
/*
* _posix1e_acl_sort -- sort ACL entries in POSIX.1e-formatted ACLs.
*/
void
_posix1e_acl_sort(acl_t acl)
{
struct acl *acl_int;
acl_int = &acl->ats_acl;
qsort(&acl_int->acl_entry[0], acl_int->acl_cnt,
sizeof(struct acl_entry), (compare) _posix1e_acl_entry_compare);
}
/*
* acl_posix1e -- in what situations should we acl_sort before submission?
* We apply posix1e ACL semantics for any ACL of type ACL_TYPE_ACCESS or
* ACL_TYPE_DEFAULT
*/
int
_posix1e_acl(acl_t acl, acl_type_t type)
{
if (_acl_brand(acl) != ACL_BRAND_POSIX)
return (0);
return ((type == ACL_TYPE_ACCESS) || (type == ACL_TYPE_DEFAULT));
}
/*
* _posix1e_acl_check -- given an ACL, check its validity. This is mirrored
* from code in sys/kern/kern_acl.c, and if changes are made in one, they
* should be made in the other also. This copy of acl_check is made
* available * in userland for the benefit of processes wanting to check ACLs
* for validity before submitting them to the kernel, or for performing
* in userland file system checking. Needless to say, the kernel makes
* the real checks on calls to get/setacl.
*
* See the comments in kernel for explanation -- just briefly, it assumes
* an already sorted ACL, and checks based on that assumption. The
* POSIX.1e interface, acl_valid(), will perform the sort before calling
* this. Returns 0 on success, EINVAL on failure.
*/
int
_posix1e_acl_check(acl_t acl)
{
struct acl *acl_int;
struct acl_entry *entry; /* current entry */
uid_t highest_uid=0, highest_gid=0;
int stage = ACL_USER_OBJ;
int i = 0;
int count_user_obj=0, count_user=0, count_group_obj=0,
count_group=0, count_mask=0, count_other=0;
acl_int = &acl->ats_acl;
/* printf("_posix1e_acl_check: checking acl with %d entries\n",
acl->acl_cnt); */
while (i < acl_int->acl_cnt) {
entry = &acl_int->acl_entry[i];
if ((entry->ae_perm | ACL_PERM_BITS) != ACL_PERM_BITS)
return (EINVAL);
switch(entry->ae_tag) {
case ACL_USER_OBJ:
/* printf("_posix1e_acl_check: %d: ACL_USER_OBJ\n",
i); */
if (stage > ACL_USER_OBJ)
return (EINVAL);
stage = ACL_USER;
count_user_obj++;
break;
case ACL_USER:
/* printf("_posix1e_acl_check: %d: ACL_USER\n", i); */
if (stage > ACL_USER)
return (EINVAL);
stage = ACL_USER;
if (count_user && (entry->ae_id <= highest_uid))
return (EINVAL);
highest_uid = entry->ae_id;
count_user++;
break;
case ACL_GROUP_OBJ:
/* printf("_posix1e_acl_check: %d: ACL_GROUP_OBJ\n",
i); */
if (stage > ACL_GROUP_OBJ)
return (EINVAL);
stage = ACL_GROUP;
count_group_obj++;
break;
case ACL_GROUP:
/* printf("_posix1e_acl_check: %d: ACL_GROUP\n", i); */
if (stage > ACL_GROUP)
return (EINVAL);
stage = ACL_GROUP;
if (count_group && (entry->ae_id <= highest_gid))
return (EINVAL);
highest_gid = entry->ae_id;
count_group++;
break;
case ACL_MASK:
/* printf("_posix1e_acl_check: %d: ACL_MASK\n", i); */
if (stage > ACL_MASK)
return (EINVAL);
stage = ACL_MASK;
count_mask++;
break;
case ACL_OTHER:
/* printf("_posix1e_acl_check: %d: ACL_OTHER\n", i); */
if (stage > ACL_OTHER)
return (EINVAL);
stage = ACL_OTHER;
count_other++;
break;
default:
/* printf("_posix1e_acl_check: %d: INVALID\n", i); */
return (EINVAL);
}
i++;
}
if (count_user_obj != 1)
return (EINVAL);
if (count_group_obj != 1)
return (EINVAL);
if (count_mask != 0 && count_mask != 1)
return (EINVAL);
if (count_other != 1)
return (EINVAL);
return (0);
}
/*
* Given a right-shifted permission (i.e., direct ACL_PERM_* mask), fill
* in a string describing the permissions.
*/
int
_posix1e_acl_perm_to_string(acl_perm_t perm, ssize_t buf_len, char *buf)
{
if (buf_len < _POSIX1E_ACL_STRING_PERM_MAXSIZE + 1) {
errno = ENOMEM;
return (-1);
}
if ((perm | ACL_PERM_BITS) != ACL_PERM_BITS) {
errno = EINVAL;
return (-1);
}
buf[3] = 0; /* null terminate */
if (perm & ACL_READ)
buf[0] = ACL_STRING_PERM_READ;
else
buf[0] = ACL_STRING_PERM_NONE;
if (perm & ACL_WRITE)
buf[1] = ACL_STRING_PERM_WRITE;
else
buf[1] = ACL_STRING_PERM_NONE;
if (perm & ACL_EXECUTE)
buf[2] = ACL_STRING_PERM_EXEC;
else
buf[2] = ACL_STRING_PERM_NONE;
return (0);
}
/*
* given a string, return a permission describing it
*/
int
_posix1e_acl_string_to_perm(char *string, acl_perm_t *perm)
{
acl_perm_t myperm = ACL_PERM_NONE;
char *ch;
ch = string;
while (*ch) {
switch(*ch) {
case ACL_STRING_PERM_READ:
myperm |= ACL_READ;
break;
case ACL_STRING_PERM_WRITE:
myperm |= ACL_WRITE;
break;
case ACL_STRING_PERM_EXEC:
myperm |= ACL_EXECUTE;
break;
case ACL_STRING_PERM_NONE:
break;
default:
return (EINVAL);
}
ch++;
}
*perm = myperm;
return (0);
}
/*
* Add an ACL entry without doing much checking, et al
*/
int
_posix1e_acl_add_entry(acl_t acl, acl_tag_t tag, uid_t id, acl_perm_t perm)
{
struct acl *acl_int;
struct acl_entry *e;
acl_int = &acl->ats_acl;
if (acl_int->acl_cnt >= ACL_MAX_ENTRIES) {
errno = ENOMEM;
return (-1);
}
e = &(acl_int->acl_entry[acl_int->acl_cnt]);
e->ae_perm = perm;
e->ae_tag = tag;
e->ae_id = id;
acl_int->acl_cnt++;
return (0);
}
/*
* Convert "old" type - ACL_TYPE_{ACCESS,DEFAULT}_OLD - into its "new"
* counterpart. It's necessary for the old (pre-NFSv4 ACLs) binaries
* to work with new libc and kernel. Fixing 'type' for old binaries with
* old libc and new kernel is being done by kern/vfs_acl.c:type_unold().
*/
int
_acl_type_unold(acl_type_t type)
{
switch (type) {
case ACL_TYPE_ACCESS_OLD:
return (ACL_TYPE_ACCESS);
case ACL_TYPE_DEFAULT_OLD:
return (ACL_TYPE_DEFAULT);
default:
return (type);
}
}
char *
string_skip_whitespace(char *string)
{
while (*string && ((*string == ' ') || (*string == '\t')))
string++;
return (string);
}
void
string_trim_trailing_whitespace(char *string)
{
char *end;
if (*string == '\0')
return;
end = string + strlen(string) - 1;
while (end != string) {
if ((*end == ' ') || (*end == '\t')) {
*end = '\0';
end--;
} else {
return;
}
}
return;
}
diff --git a/lib/libc/posix1e/acl_support_nfs4.c b/lib/libc/posix1e/acl_support_nfs4.c
index 9062ec31cd43..08647651933b 100644
--- a/lib/libc/posix1e/acl_support_nfs4.c
+++ b/lib/libc/posix1e/acl_support_nfs4.c
@@ -1,261 +1,260 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <err.h>
#include <sys/acl.h>
#include "acl_support.h"
struct flagnames_struct {
uint32_t flag;
const char *name;
char letter;
};
struct flagnames_struct a_flags[] =
{{ ACL_ENTRY_FILE_INHERIT, "file_inherit", 'f'},
{ ACL_ENTRY_DIRECTORY_INHERIT, "dir_inherit", 'd'},
{ ACL_ENTRY_INHERIT_ONLY, "inherit_only", 'i'},
{ ACL_ENTRY_NO_PROPAGATE_INHERIT, "no_propagate", 'n'},
{ ACL_ENTRY_SUCCESSFUL_ACCESS, "successfull_access", 'S'},
{ ACL_ENTRY_FAILED_ACCESS, "failed_access", 'F'},
{ ACL_ENTRY_INHERITED, "inherited", 'I' },
/*
* There is no ACE_IDENTIFIER_GROUP here - SunOS does not show it
* in the "flags" field. There is no ACE_OWNER, ACE_GROUP or
* ACE_EVERYONE either, for obvious reasons.
*/
{ 0, 0, 0}};
struct flagnames_struct a_access_masks[] =
{{ ACL_READ_DATA, "read_data", 'r'},
{ ACL_WRITE_DATA, "write_data", 'w'},
{ ACL_EXECUTE, "execute", 'x'},
{ ACL_APPEND_DATA, "append_data", 'p'},
{ ACL_DELETE_CHILD, "delete_child", 'D'},
{ ACL_DELETE, "delete", 'd'},
{ ACL_READ_ATTRIBUTES, "read_attributes", 'a'},
{ ACL_WRITE_ATTRIBUTES, "write_attributes", 'A'},
{ ACL_READ_NAMED_ATTRS, "read_xattr", 'R'},
{ ACL_WRITE_NAMED_ATTRS, "write_xattr", 'W'},
{ ACL_READ_ACL, "read_acl", 'c'},
{ ACL_WRITE_ACL, "write_acl", 'C'},
{ ACL_WRITE_OWNER, "write_owner", 'o'},
{ ACL_SYNCHRONIZE, "synchronize", 's'},
{ ACL_FULL_SET, "full_set", '\0'},
{ ACL_MODIFY_SET, "modify_set", '\0'},
{ ACL_READ_SET, "read_set", '\0'},
{ ACL_WRITE_SET, "write_set", '\0'},
{ 0, 0, 0}};
static const char *
format_flag(uint32_t *var, const struct flagnames_struct *flags)
{
for (; flags->name != NULL; flags++) {
if ((flags->flag & *var) == 0)
continue;
*var &= ~flags->flag;
return (flags->name);
}
return (NULL);
}
static int
format_flags_verbose(char *str, size_t size, uint32_t var,
const struct flagnames_struct *flags)
{
size_t off = 0;
const char *tmp;
while ((tmp = format_flag(&var, flags)) != NULL) {
off += snprintf(str + off, size - off, "%s/", tmp);
assert (off < size);
}
/* If there were any flags added... */
if (off > 0) {
off--;
/* ... then remove the last slash. */
assert(str[off] == '/');
}
str[off] = '\0';
return (0);
}
static int
format_flags_compact(char *str, size_t size, uint32_t var,
const struct flagnames_struct *flags)
{
size_t i;
for (i = 0; flags[i].letter != '\0'; i++) {
assert(i < size);
if ((flags[i].flag & var) == 0)
str[i] = '-';
else
str[i] = flags[i].letter;
}
str[i] = '\0';
return (0);
}
static int
parse_flags_verbose(const char *strp, uint32_t *var,
const struct flagnames_struct *flags, const char *flags_name,
int *try_compact)
{
int i, found, ever_found = 0;
char *str, *flag, *to_free;
str = strdup(strp);
to_free = str;
*try_compact = 0;
*var = 0;
while (str != NULL) {
flag = strsep(&str, "/:");
found = 0;
for (i = 0; flags[i].name != NULL; i++) {
if (strcmp(flags[i].name, flag) == 0) {
*var |= flags[i].flag;
found = 1;
ever_found = 1;
}
}
if (!found) {
if (ever_found)
warnx("malformed ACL: \"%s\" field contains "
"invalid flag \"%s\"", flags_name, flag);
else
*try_compact = 1;
free(to_free);
return (-1);
}
}
free(to_free);
return (0);
}
static int
parse_flags_compact(const char *str, uint32_t *var,
const struct flagnames_struct *flags, const char *flags_name)
{
int i, j, found;
*var = 0;
for (i = 0;; i++) {
if (str[i] == '\0')
return (0);
/* Ignore minus signs. */
if (str[i] == '-')
continue;
found = 0;
for (j = 0; flags[j].name != NULL; j++) {
if (flags[j].letter == str[i]) {
*var |= flags[j].flag;
found = 1;
break;
}
}
if (!found) {
warnx("malformed ACL: \"%s\" field contains "
"invalid flag \"%c\"", flags_name, str[i]);
return (-1);
}
}
}
int
_nfs4_format_flags(char *str, size_t size, acl_flag_t var, int verbose)
{
if (verbose)
return (format_flags_verbose(str, size, var, a_flags));
return (format_flags_compact(str, size, var, a_flags));
}
int
_nfs4_format_access_mask(char *str, size_t size, acl_perm_t var, int verbose)
{
if (verbose)
return (format_flags_verbose(str, size, var, a_access_masks));
return (format_flags_compact(str, size, var, a_access_masks));
}
int
_nfs4_parse_flags(const char *str, acl_flag_t *flags)
{
int error, try_compact;
int tmpflags;
error = parse_flags_verbose(str, &tmpflags, a_flags, "flags", &try_compact);
if (error && try_compact)
error = parse_flags_compact(str, &tmpflags, a_flags, "flags");
*flags = tmpflags;
return (error);
}
int
_nfs4_parse_access_mask(const char *str, acl_perm_t *perms)
{
int error, try_compact;
int tmpperms;
error = parse_flags_verbose(str, &tmpperms, a_access_masks,
"access permissions", &try_compact);
if (error && try_compact)
error = parse_flags_compact(str, &tmpperms,
a_access_masks, "access permissions");
*perms = tmpperms;
return (error);
}
diff --git a/lib/libc/posix1e/acl_to_text.c b/lib/libc/posix1e/acl_to_text.c
index 3b2156c61560..f03ddeb79c09 100644
--- a/lib/libc/posix1e/acl_to_text.c
+++ b/lib/libc/posix1e/acl_to_text.c
@@ -1,261 +1,260 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999-2002 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_to_text - return a text string with a text representation of the acl
* in it.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <sys/errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "acl_support.h"
/*
* acl_to_text - generate a text form of an acl
* spec says nothing about output ordering, so leave in acl order
*
* This function will not produce nice results if it is called with
* a non-POSIX.1e semantics ACL.
*/
char *_nfs4_acl_to_text_np(const acl_t acl, ssize_t *len_p, int flags);
static char *
_posix1e_acl_to_text(acl_t acl, ssize_t *len_p, int flags)
{
struct acl *acl_int;
char *buf, *tmpbuf;
char name_buf[MAXLOGNAME];
char perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1],
effective_perm_buf[_POSIX1E_ACL_STRING_PERM_MAXSIZE+1];
int i, error, len;
uid_t ae_id;
acl_tag_t ae_tag;
acl_perm_t ae_perm, effective_perm, mask_perm;
buf = strdup("");
if (buf == NULL)
return(NULL);
acl_int = &acl->ats_acl;
mask_perm = ACL_PERM_BITS; /* effective is regular if no mask */
for (i = 0; i < acl_int->acl_cnt; i++)
if (acl_int->acl_entry[i].ae_tag == ACL_MASK)
mask_perm = acl_int->acl_entry[i].ae_perm;
for (i = 0; i < acl_int->acl_cnt; i++) {
ae_tag = acl_int->acl_entry[i].ae_tag;
ae_id = acl_int->acl_entry[i].ae_id;
ae_perm = acl_int->acl_entry[i].ae_perm;
switch(ae_tag) {
case ACL_USER_OBJ:
error = _posix1e_acl_perm_to_string(ae_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
if (error)
goto error_label;
len = asprintf(&tmpbuf, "%suser::%s\n", buf,
perm_buf);
if (len == -1)
goto error_label;
free(buf);
buf = tmpbuf;
break;
case ACL_USER:
error = _posix1e_acl_perm_to_string(ae_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
if (error)
goto error_label;
error = _posix1e_acl_id_to_name(ae_tag, ae_id,
MAXLOGNAME, name_buf, flags);
if (error)
goto error_label;
effective_perm = ae_perm & mask_perm;
if (effective_perm != ae_perm) {
error = _posix1e_acl_perm_to_string(
effective_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
effective_perm_buf);
if (error)
goto error_label;
len = asprintf(&tmpbuf, "%suser:%s:%s\t\t# "
"effective: %s\n",
buf, name_buf, perm_buf,
effective_perm_buf);
} else {
len = asprintf(&tmpbuf, "%suser:%s:%s\n", buf,
name_buf, perm_buf);
}
if (len == -1)
goto error_label;
free(buf);
buf = tmpbuf;
break;
case ACL_GROUP_OBJ:
error = _posix1e_acl_perm_to_string(ae_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
if (error)
goto error_label;
effective_perm = ae_perm & mask_perm;
if (effective_perm != ae_perm) {
error = _posix1e_acl_perm_to_string(
effective_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
effective_perm_buf);
if (error)
goto error_label;
len = asprintf(&tmpbuf, "%sgroup::%s\t\t# "
"effective: %s\n",
buf, perm_buf, effective_perm_buf);
} else {
len = asprintf(&tmpbuf, "%sgroup::%s\n", buf,
perm_buf);
}
if (len == -1)
goto error_label;
free(buf);
buf = tmpbuf;
break;
case ACL_GROUP:
error = _posix1e_acl_perm_to_string(ae_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
if (error)
goto error_label;
error = _posix1e_acl_id_to_name(ae_tag, ae_id,
MAXLOGNAME, name_buf, flags);
if (error)
goto error_label;
effective_perm = ae_perm & mask_perm;
if (effective_perm != ae_perm) {
error = _posix1e_acl_perm_to_string(
effective_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1,
effective_perm_buf);
if (error)
goto error_label;
len = asprintf(&tmpbuf, "%sgroup:%s:%s\t\t# "
"effective: %s\n",
buf, name_buf, perm_buf,
effective_perm_buf);
} else {
len = asprintf(&tmpbuf, "%sgroup:%s:%s\n", buf,
name_buf, perm_buf);
}
if (len == -1)
goto error_label;
free(buf);
buf = tmpbuf;
break;
case ACL_MASK:
error = _posix1e_acl_perm_to_string(ae_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
if (error)
goto error_label;
len = asprintf(&tmpbuf, "%smask::%s\n", buf,
perm_buf);
if (len == -1)
goto error_label;
free(buf);
buf = tmpbuf;
break;
case ACL_OTHER:
error = _posix1e_acl_perm_to_string(ae_perm,
_POSIX1E_ACL_STRING_PERM_MAXSIZE+1, perm_buf);
if (error)
goto error_label;
len = asprintf(&tmpbuf, "%sother::%s\n", buf,
perm_buf);
if (len == -1)
goto error_label;
free(buf);
buf = tmpbuf;
break;
default:
errno = EINVAL;
goto error_label;
}
}
if (len_p) {
*len_p = strlen(buf);
}
return (buf);
error_label:
/* jump to here sets errno already, we just clean up */
if (buf) free(buf);
return (NULL);
}
char *
acl_to_text_np(acl_t acl, ssize_t *len_p, int flags)
{
if (acl == NULL) {
errno = EINVAL;
return(NULL);
}
switch (_acl_brand(acl)) {
case ACL_BRAND_POSIX:
return (_posix1e_acl_to_text(acl, len_p, flags));
case ACL_BRAND_NFS4:
return (_nfs4_acl_to_text_np(acl, len_p, flags));
default:
errno = EINVAL;
return (NULL);
}
}
char *
acl_to_text(acl_t acl, ssize_t *len_p)
{
return (acl_to_text_np(acl, len_p, 0));
}
diff --git a/lib/libc/posix1e/acl_to_text_nfs4.c b/lib/libc/posix1e/acl_to_text_nfs4.c
index 522ebe3d4373..d901b1cf6b88 100644
--- a/lib/libc/posix1e/acl_to_text_nfs4.c
+++ b/lib/libc/posix1e/acl_to_text_nfs4.c
@@ -1,263 +1,262 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008, 2009 Edward Tomasz Napierała <trasz@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <assert.h>
#include <string.h>
#include <pwd.h>
#include <grp.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/acl.h>
#include "acl_support.h"
#define MAX_ENTRY_LENGTH 512
static int
format_who(char *str, size_t size, const acl_entry_t entry, int numeric)
{
int error;
acl_tag_t tag;
struct passwd *pwd;
struct group *grp;
uid_t *id;
error = acl_get_tag_type(entry, &tag);
if (error)
return (error);
switch (tag) {
case ACL_USER_OBJ:
snprintf(str, size, "owner@");
break;
case ACL_USER:
id = (uid_t *)acl_get_qualifier(entry);
if (id == NULL)
return (-1);
/* XXX: Thread-unsafe. */
if (!numeric)
pwd = getpwuid(*id);
else
pwd = NULL;
if (pwd == NULL)
snprintf(str, size, "user:%d", (unsigned int)*id);
else
snprintf(str, size, "user:%s", pwd->pw_name);
break;
case ACL_GROUP_OBJ:
snprintf(str, size, "group@");
break;
case ACL_GROUP:
id = (uid_t *)acl_get_qualifier(entry);
if (id == NULL)
return (-1);
/* XXX: Thread-unsafe. */
if (!numeric)
grp = getgrgid(*id);
else
grp = NULL;
if (grp == NULL)
snprintf(str, size, "group:%d", (unsigned int)*id);
else
snprintf(str, size, "group:%s", grp->gr_name);
break;
case ACL_EVERYONE:
snprintf(str, size, "everyone@");
break;
default:
return (-1);
}
return (0);
}
static int
format_entry_type(char *str, size_t size, const acl_entry_t entry)
{
int error;
acl_entry_type_t entry_type;
error = acl_get_entry_type_np(entry, &entry_type);
if (error)
return (error);
switch (entry_type) {
case ACL_ENTRY_TYPE_ALLOW:
snprintf(str, size, "allow");
break;
case ACL_ENTRY_TYPE_DENY:
snprintf(str, size, "deny");
break;
case ACL_ENTRY_TYPE_AUDIT:
snprintf(str, size, "audit");
break;
case ACL_ENTRY_TYPE_ALARM:
snprintf(str, size, "alarm");
break;
default:
return (-1);
}
return (0);
}
static int
format_additional_id(char *str, size_t size, const acl_entry_t entry)
{
int error;
acl_tag_t tag;
uid_t *id;
error = acl_get_tag_type(entry, &tag);
if (error)
return (error);
switch (tag) {
case ACL_USER_OBJ:
case ACL_GROUP_OBJ:
case ACL_EVERYONE:
str[0] = '\0';
break;
default:
id = (uid_t *)acl_get_qualifier(entry);
if (id == NULL)
return (-1);
snprintf(str, size, ":%d", (unsigned int)*id);
}
return (0);
}
static int
format_entry(char *str, size_t size, const acl_entry_t entry, int flags)
{
size_t off = 0, min_who_field_length = 18;
acl_permset_t permset;
acl_flagset_t flagset;
int error, len;
char buf[MAX_ENTRY_LENGTH + 1];
assert(_entry_brand(entry) == ACL_BRAND_NFS4);
error = acl_get_flagset_np(entry, &flagset);
if (error)
return (error);
error = acl_get_permset(entry, &permset);
if (error)
return (error);
error = format_who(buf, sizeof(buf), entry,
flags & ACL_TEXT_NUMERIC_IDS);
if (error)
return (error);
len = strlen(buf);
if (len < min_who_field_length)
len = min_who_field_length;
off += snprintf(str + off, size - off, "%*s:", len, buf);
error = _nfs4_format_access_mask(buf, sizeof(buf), *permset,
flags & ACL_TEXT_VERBOSE);
if (error)
return (error);
off += snprintf(str + off, size - off, "%s:", buf);
error = _nfs4_format_flags(buf, sizeof(buf), *flagset,
flags & ACL_TEXT_VERBOSE);
if (error)
return (error);
off += snprintf(str + off, size - off, "%s:", buf);
error = format_entry_type(buf, sizeof(buf), entry);
if (error)
return (error);
off += snprintf(str + off, size - off, "%s", buf);
if (flags & ACL_TEXT_APPEND_ID) {
error = format_additional_id(buf, sizeof(buf), entry);
if (error)
return (error);
off += snprintf(str + off, size - off, "%s", buf);
}
off += snprintf(str + off, size - off, "\n");
/* Make sure we didn't truncate anything. */
assert (off < size);
return (0);
}
char *
_nfs4_acl_to_text_np(const acl_t aclp, ssize_t *len_p, int flags)
{
int error, off = 0, size, entry_id = ACL_FIRST_ENTRY;
char *str;
acl_entry_t entry;
if (aclp->ats_acl.acl_cnt == 0)
return strdup("");
size = aclp->ats_acl.acl_cnt * MAX_ENTRY_LENGTH;
str = malloc(size);
if (str == NULL)
return (NULL);
while (acl_get_entry(aclp, entry_id, &entry) == 1) {
entry_id = ACL_NEXT_ENTRY;
assert(off < size);
error = format_entry(str + off, size - off, entry, flags);
if (error) {
free(str);
errno = EINVAL;
return (NULL);
}
off = strlen(str);
}
assert(off < size);
str[off] = '\0';
if (len_p != NULL)
*len_p = off;
return (str);
}
diff --git a/lib/libc/posix1e/acl_valid.c b/lib/libc/posix1e/acl_valid.c
index b0468d5a57d8..c804b0840307 100644
--- a/lib/libc/posix1e/acl_valid.c
+++ b/lib/libc/posix1e/acl_valid.c
@@ -1,124 +1,123 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* acl_valid -- POSIX.1e ACL check routine
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "namespace.h"
#include <sys/acl.h>
#include "un-namespace.h"
#include <sys/errno.h>
#include <stdlib.h>
#include "acl_support.h"
/*
* acl_valid: accepts an ACL, returns 0 on valid ACL, -1 for invalid,
* and errno set to EINVAL.
*
* Implemented by calling the acl_check routine in acl_support, which
* requires ordering. We call acl_support's _posix1e_acl_sort to make this
* true. POSIX.1e allows acl_valid() to reorder the ACL as it sees fit.
*
* This call is deprecated, as it doesn't ask whether the ACL is valid
* for a particular target. However, this call is standardized, unlike
* the other two forms.
*/
int
acl_valid(acl_t acl)
{
int error;
if (acl == NULL) {
errno = EINVAL;
return (-1);
}
if (!_acl_brand_may_be(acl, ACL_BRAND_POSIX)) {
errno = EINVAL;
return (-1);
}
_posix1e_acl_sort(acl);
error = _posix1e_acl_check(acl);
if (error) {
errno = error;
return (-1);
} else {
return (0);
}
}
int
acl_valid_file_np(const char *pathp, acl_type_t type, acl_t acl)
{
if (pathp == NULL || acl == NULL) {
errno = EINVAL;
return (-1);
}
type = _acl_type_unold(type);
if (_posix1e_acl(acl, type))
_posix1e_acl_sort(acl);
return (__acl_aclcheck_file(pathp, type, &acl->ats_acl));
}
int
acl_valid_link_np(const char *pathp, acl_type_t type, acl_t acl)
{
if (pathp == NULL || acl == NULL) {
errno = EINVAL;
return (-1);
}
type = _acl_type_unold(type);
if (_posix1e_acl(acl, type))
_posix1e_acl_sort(acl);
return (__acl_aclcheck_link(pathp, type, &acl->ats_acl));
}
int
acl_valid_fd_np(int fd, acl_type_t type, acl_t acl)
{
if (acl == NULL) {
errno = EINVAL;
return (-1);
}
type = _acl_type_unold(type);
if (_posix1e_acl(acl, type))
_posix1e_acl_sort(acl);
acl->ats_cur_entry = 0;
return (___acl_aclcheck_fd(fd, type, &acl->ats_acl));
}
diff --git a/lib/libc/posix1e/extattr.c b/lib/libc/posix1e/extattr.c
index 816b3a6952ad..6938c302b8a4 100644
--- a/lib/libc/posix1e/extattr.c
+++ b/lib/libc/posix1e/extattr.c
@@ -1,77 +1,76 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Robert N. M. Watson
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* TrustedBSD: Utility functions for extended attributes.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/extattr.h>
#include <errno.h>
#include <libutil.h>
#include <string.h>
int
extattr_namespace_to_string(int attrnamespace, char **string)
{
switch(attrnamespace) {
case EXTATTR_NAMESPACE_USER:
if (string != NULL)
*string = strdup(EXTATTR_NAMESPACE_USER_STRING);
return (0);
case EXTATTR_NAMESPACE_SYSTEM:
if (string != NULL)
*string = strdup(EXTATTR_NAMESPACE_SYSTEM_STRING);
return (0);
default:
errno = EINVAL;
return (-1);
}
}
int
extattr_string_to_namespace(const char *string, int *attrnamespace)
{
if (!strcmp(string, EXTATTR_NAMESPACE_USER_STRING)) {
if (attrnamespace != NULL)
*attrnamespace = EXTATTR_NAMESPACE_USER;
return (0);
} else if (!strcmp(string, EXTATTR_NAMESPACE_SYSTEM_STRING)) {
if (attrnamespace != NULL)
*attrnamespace = EXTATTR_NAMESPACE_SYSTEM;
return (0);
} else {
errno = EINVAL;
return (-1);
}
}
diff --git a/lib/libc/posix1e/mac.c b/lib/libc/posix1e/mac.c
index c1bfcf15969a..8f3a63e40ac5 100644
--- a/lib/libc/posix1e/mac.c
+++ b/lib/libc/posix1e/mac.c
@@ -1,448 +1,447 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
* Copyright (c) 2002, 2003 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* This software was developed for the FreeBSD Project in part by Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
* as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/queue.h>
#include <sys/sysctl.h>
#include <dlfcn.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/mac.h>
static int internal_initialized;
/*
* Maintain a list of default label preparations for various object
* types. Each name will appear only once in the list.
*
* XXXMAC: Not thread-safe.
*/
static LIST_HEAD(, label_default) label_default_head;
struct label_default {
char *ld_name;
char *ld_labels;
LIST_ENTRY(label_default) ld_entries;
};
static void
mac_destroy_labels(void)
{
struct label_default *ld;
while ((ld = LIST_FIRST(&label_default_head))) {
free(ld->ld_name);
free(ld->ld_labels);
LIST_REMOVE(ld, ld_entries);
free(ld);
}
}
static void
mac_destroy_internal(void)
{
mac_destroy_labels();
internal_initialized = 0;
}
static int
mac_add_type(const char *name, const char *labels)
{
struct label_default *ld, *ld_new;
char *name_dup, *labels_dup;
/*
* Speculatively allocate all the memory now to avoid allocating
* later when we will someday hold a mutex.
*/
name_dup = strdup(name);
if (name_dup == NULL) {
errno = ENOMEM;
return (-1);
}
labels_dup = strdup(labels);
if (labels_dup == NULL) {
free(name_dup);
errno = ENOMEM;
return (-1);
}
ld_new = malloc(sizeof(*ld));
if (ld_new == NULL) {
free(name_dup);
free(labels_dup);
errno = ENOMEM;
return (-1);
}
/*
* If the type is already present, replace the current entry
* rather than add a new instance.
*/
for (ld = LIST_FIRST(&label_default_head); ld != NULL;
ld = LIST_NEXT(ld, ld_entries)) {
if (strcmp(name, ld->ld_name) == 0)
break;
}
if (ld != NULL) {
free(ld->ld_labels);
ld->ld_labels = labels_dup;
labels_dup = NULL;
} else {
ld = ld_new;
ld->ld_name = name_dup;
ld->ld_labels = labels_dup;
ld_new = NULL;
name_dup = NULL;
labels_dup = NULL;
LIST_INSERT_HEAD(&label_default_head, ld, ld_entries);
}
if (name_dup != NULL)
free(name_dup);
if (labels_dup != NULL)
free(labels_dup);
if (ld_new != NULL)
free(ld_new);
return (0);
}
static char *
next_token(char **string)
{
char *token;
token = strsep(string, " \t");
while (token != NULL && *token == '\0')
token = strsep(string, " \t");
return (token);
}
static int
mac_init_internal(int ignore_errors)
{
const char *filename;
char line[LINE_MAX];
FILE *file;
int error;
error = 0;
LIST_INIT(&label_default_head);
filename = secure_getenv("MAC_CONFFILE");
if (filename == NULL)
filename = MAC_CONFFILE;
file = fopen(filename, "re");
if (file == NULL)
return (0);
while (fgets(line, LINE_MAX, file)) {
char *comment, *parse, *statement;
if (line[strlen(line)-1] == '\n')
line[strlen(line)-1] = '\0';
else {
if (ignore_errors)
continue;
fclose(file);
error = EINVAL;
goto just_return;
}
/* Remove any comment. */
comment = line;
parse = strsep(&comment, "#");
/* Blank lines OK. */
statement = next_token(&parse);
if (statement == NULL)
continue;
if (strcmp(statement, "default_labels") == 0) {
char *name, *labels;
name = next_token(&parse);
labels = next_token(&parse);
if (name == NULL || labels == NULL ||
next_token(&parse) != NULL) {
if (ignore_errors)
continue;
error = EINVAL;
fclose(file);
goto just_return;
}
if (mac_add_type(name, labels) == -1) {
if (ignore_errors)
continue;
fclose(file);
goto just_return;
}
} else if (strcmp(statement, "default_ifnet_labels") == 0 ||
strcmp(statement, "default_file_labels") == 0 ||
strcmp(statement, "default_process_labels") == 0) {
char *labels, *type;
if (strcmp(statement, "default_ifnet_labels") == 0)
type = "ifnet";
else if (strcmp(statement, "default_file_labels") == 0)
type = "file";
else if (strcmp(statement, "default_process_labels") ==
0)
type = "process";
labels = next_token(&parse);
if (labels == NULL || next_token(&parse) != NULL) {
if (ignore_errors)
continue;
error = EINVAL;
fclose(file);
goto just_return;
}
if (mac_add_type(type, labels) == -1) {
if (ignore_errors)
continue;
fclose(file);
goto just_return;
}
} else {
if (ignore_errors)
continue;
fclose(file);
error = EINVAL;
goto just_return;
}
}
fclose(file);
internal_initialized = 1;
just_return:
if (error != 0)
mac_destroy_internal();
return (error);
}
static int
mac_maybe_init_internal(void)
{
if (!internal_initialized)
return (mac_init_internal(1));
else
return (0);
}
int
mac_reload(void)
{
if (internal_initialized)
mac_destroy_internal();
return (mac_init_internal(0));
}
int
mac_free(struct mac *mac)
{
if (mac->m_string != NULL)
free(mac->m_string);
free(mac);
return (0);
}
int
mac_from_text(struct mac **mac, const char *text)
{
*mac = (struct mac *) malloc(sizeof(**mac));
if (*mac == NULL)
return (ENOMEM);
(*mac)->m_string = strdup(text);
if ((*mac)->m_string == NULL) {
free(*mac);
*mac = NULL;
return (ENOMEM);
}
(*mac)->m_buflen = strlen((*mac)->m_string)+1;
return (0);
}
int
mac_to_text(struct mac *mac, char **text)
{
*text = strdup(mac->m_string);
if (*text == NULL)
return (ENOMEM);
return (0);
}
int
mac_prepare(struct mac **mac, const char *elements)
{
if (strlen(elements) >= MAC_MAX_LABEL_BUF_LEN)
return (EINVAL);
*mac = (struct mac *) malloc(sizeof(**mac));
if (*mac == NULL)
return (ENOMEM);
(*mac)->m_string = malloc(MAC_MAX_LABEL_BUF_LEN);
if ((*mac)->m_string == NULL) {
free(*mac);
*mac = NULL;
return (ENOMEM);
}
strcpy((*mac)->m_string, elements);
(*mac)->m_buflen = MAC_MAX_LABEL_BUF_LEN;
return (0);
}
int
mac_prepare_type(struct mac **mac, const char *name)
{
struct label_default *ld;
int error;
error = mac_maybe_init_internal();
if (error != 0)
return (error);
for (ld = LIST_FIRST(&label_default_head); ld != NULL;
ld = LIST_NEXT(ld, ld_entries)) {
if (strcmp(name, ld->ld_name) == 0)
return (mac_prepare(mac, ld->ld_labels));
}
errno = ENOENT;
return (-1); /* XXXMAC: ENOLABEL */
}
int
mac_prepare_ifnet_label(struct mac **mac)
{
return (mac_prepare_type(mac, "ifnet"));
}
int
mac_prepare_file_label(struct mac **mac)
{
return (mac_prepare_type(mac, "file"));
}
int
mac_prepare_packet_label(struct mac **mac)
{
return (mac_prepare_type(mac, "packet"));
}
int
mac_prepare_process_label(struct mac **mac)
{
return (mac_prepare_type(mac, "process"));
}
/*
* Simply test whether the TrustedBSD/MAC MIB tree is present; if so,
* return 1 to indicate that the system has MAC enabled overall or for
* a given policy.
*/
int
mac_is_present(const char *policyname)
{
int mib[5];
size_t siz;
char *mibname;
int error;
if (policyname != NULL) {
if (policyname[strcspn(policyname, ".=")] != '\0') {
errno = EINVAL;
return (-1);
}
mibname = malloc(sizeof("security.mac.") - 1 +
strlen(policyname) + sizeof(".enabled"));
if (mibname == NULL)
return (-1);
strcpy(mibname, "security.mac.");
strcat(mibname, policyname);
strcat(mibname, ".enabled");
siz = 5;
error = sysctlnametomib(mibname, mib, &siz);
free(mibname);
} else {
siz = 3;
error = sysctlnametomib("security.mac", mib, &siz);
}
if (error == -1) {
switch (errno) {
case ENOTDIR:
case ENOENT:
return (0);
default:
return (error);
}
}
return (1);
}
diff --git a/lib/libc/posix1e/mac_exec.c b/lib/libc/posix1e/mac_exec.c
index acd7c1d6e828..3016f21edd0d 100644
--- a/lib/libc/posix1e/mac_exec.c
+++ b/lib/libc/posix1e/mac_exec.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Networks Associates Technology, Inc.
* All rights reserved.
*
* This software was developed for the FreeBSD Project in part by Network
* Associates Laboratories, the Security Research Division of Network
* Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
* as part of the DARPA CHATS research program.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/mac.h>
extern int __mac_execve(char *fname, char **argv, char **envv,
struct mac *mac_p);
int
mac_execve(char *fname, char **argv, char **envv, struct mac *label)
{
return (__mac_execve(fname, argv, envv, label));
}
diff --git a/lib/libc/posix1e/mac_get.c b/lib/libc/posix1e/mac_get.c
index 5bf829e9a160..5bfc0a549754 100644
--- a/lib/libc/posix1e/mac_get.c
+++ b/lib/libc/posix1e/mac_get.c
@@ -1,87 +1,86 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/mac.h>
#include <sys/socket.h>
extern int __mac_get_fd(int fd, struct mac *mac_p);
extern int __mac_get_file(const char *path_p, struct mac *mac_p);
extern int __mac_get_link(const char *path_p, struct mac *mac_p);
extern int __mac_get_pid(pid_t pid, struct mac *mac_p);
extern int __mac_get_proc(struct mac *mac_p);
int
mac_get_fd(int fd, struct mac *label)
{
return (__mac_get_fd(fd, label));
}
int
mac_get_file(const char *path, struct mac *label)
{
return (__mac_get_file(path, label));
}
int
mac_get_link(const char *path, struct mac *label)
{
return (__mac_get_link(path, label));
}
int
mac_get_peer(int fd, struct mac *label)
{
socklen_t len;
len = sizeof(*label);
return (getsockopt(fd, SOL_SOCKET, SO_PEERLABEL, label, &len));
}
int
mac_get_pid(pid_t pid, struct mac *label)
{
return (__mac_get_pid(pid, label));
}
int
mac_get_proc(struct mac *label)
{
return (__mac_get_proc(label));
}
diff --git a/lib/libc/posix1e/mac_set.c b/lib/libc/posix1e/mac_set.c
index cded5a7cca70..8197d4354910 100644
--- a/lib/libc/posix1e/mac_set.c
+++ b/lib/libc/posix1e/mac_set.c
@@ -1,69 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
* All rights reserved.
*
* This software was developed by Robert Watson for the TrustedBSD Project.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/mac.h>
extern int __mac_set_fd(int fd, struct mac *mac_p);
extern int __mac_set_file(const char *path_p, struct mac *mac_p);
extern int __mac_set_link(const char *path_p, struct mac *mac_p);
extern int __mac_set_proc(struct mac *mac_p);
int
mac_set_fd(int fd, struct mac *label)
{
return (__mac_set_fd(fd, label));
}
int
mac_set_file(const char *path, struct mac *label)
{
return (__mac_set_file(path, label));
}
int
mac_set_link(const char *path, struct mac *label)
{
return (__mac_set_link(path, label));
}
int
mac_set_proc(struct mac *label)
{
return (__mac_set_proc(label));
}
diff --git a/lib/libc/powerpc/gen/flt_rounds.c b/lib/libc/powerpc/gen/flt_rounds.c
index 601a42321a16..77e04694dc69 100644
--- a/lib/libc/powerpc/gen/flt_rounds.c
+++ b/lib/libc/powerpc/gen/flt_rounds.c
@@ -1,56 +1,55 @@
/* $NetBSD: flt_rounds.c,v 1.4.10.3 2002/03/22 20:41:53 nathanw Exp $ */
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1996 Mark Brinicombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe
* for the NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/float.h>
#ifndef _SOFT_FLOAT
static const int map[] = {
1, /* round to nearest */
0, /* round to zero */
2, /* round to positive infinity */
3 /* round to negative infinity */
};
int
__flt_rounds()
{
uint64_t fpscr;
__asm__ __volatile("mffs %0" : "=f"(fpscr));
return map[(fpscr & 0x03)];
}
#endif
diff --git a/lib/libc/powerpc/gen/fpgetmask.c b/lib/libc/powerpc/gen/fpgetmask.c
index b4399f23cf72..6817a32bdc65 100644
--- a/lib/libc/powerpc/gen/fpgetmask.c
+++ b/lib/libc/powerpc/gen/fpgetmask.c
@@ -1,48 +1,47 @@
/* $NetBSD: fpgetmask.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_except_t
fpgetmask()
{
u_int64_t fpscr;
__asm__("mffs %0" : "=f"(fpscr));
return ((fp_except_t)((fpscr >> 3) & 0x1f));
}
#endif
diff --git a/lib/libc/powerpc/gen/fpgetround.c b/lib/libc/powerpc/gen/fpgetround.c
index f6a98d3ffe1f..b135807b613f 100644
--- a/lib/libc/powerpc/gen/fpgetround.c
+++ b/lib/libc/powerpc/gen/fpgetround.c
@@ -1,48 +1,47 @@
/* $NetBSD: fpgetround.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_rnd_t
fpgetround()
{
u_int64_t fpscr;
__asm__("mffs %0" : "=f"(fpscr));
return ((fp_rnd_t)(fpscr & 0x3));
}
#endif
diff --git a/lib/libc/powerpc/gen/fpgetsticky.c b/lib/libc/powerpc/gen/fpgetsticky.c
index a79f4062c7f9..d609586360fe 100644
--- a/lib/libc/powerpc/gen/fpgetsticky.c
+++ b/lib/libc/powerpc/gen/fpgetsticky.c
@@ -1,54 +1,53 @@
/* $NetBSD: fpgetsticky.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
#ifdef __weak_alias
__weak_alias(fpgetsticky,_fpgetsticky)
#endif
fp_except_t
fpgetsticky()
{
u_int64_t fpscr;
__asm__ __volatile("mffs %0" : "=f"(fpscr));
return ((fp_except_t)((fpscr >> 25) & 0x1f));
}
#endif
diff --git a/lib/libc/powerpc/gen/fpsetmask.c b/lib/libc/powerpc/gen/fpsetmask.c
index eb5884aa080c..4170b385e9e4 100644
--- a/lib/libc/powerpc/gen/fpsetmask.c
+++ b/lib/libc/powerpc/gen/fpsetmask.c
@@ -1,52 +1,51 @@
/* $NetBSD: fpsetmask.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_except_t
fpsetmask(fp_except_t mask)
{
u_int64_t fpscr;
fp_except_t old;
__asm__("mffs %0" : "=f"(fpscr));
old = (fp_except_t)((fpscr >> 3) & 0x1f);
fpscr = (fpscr & 0xffffff07) | ((mask & 0x1f) << 3);
__asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
return (old);
}
#endif
diff --git a/lib/libc/powerpc/gen/fpsetround.c b/lib/libc/powerpc/gen/fpsetround.c
index 82ec0ea354c2..2a70fd781474 100644
--- a/lib/libc/powerpc/gen/fpsetround.c
+++ b/lib/libc/powerpc/gen/fpsetround.c
@@ -1,52 +1,51 @@
/* $NetBSD: fpsetround.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_rnd_t
fpsetround(fp_rnd_t rnd_dir)
{
u_int64_t fpscr;
fp_rnd_t old;
__asm__ __volatile("mffs %0" : "=f"(fpscr));
old = (fp_rnd_t)(fpscr & 0x3);
fpscr = (fpscr & 0xfffffffc) | rnd_dir;
__asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
return (old);
}
#endif
diff --git a/lib/libc/powerpc/gen/makecontext.c b/lib/libc/powerpc/gen/makecontext.c
index eb3cf2bb3d3b..5fbb0a96f05c 100644
--- a/lib/libc/powerpc/gen/makecontext.c
+++ b/lib/libc/powerpc/gen/makecontext.c
@@ -1,120 +1,119 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Suleiman Souhlal
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ucontext.h>
__weak_reference(__makecontext, makecontext);
void _ctx_done(ucontext_t *ucp);
void _ctx_start(void);
void
_ctx_done(ucontext_t *ucp)
{
if (ucp->uc_link == NULL)
exit(0);
else {
/* invalidate context */
ucp->uc_mcontext.mc_len = 0;
setcontext((const ucontext_t *)ucp->uc_link);
abort(); /* should never return from above call */
}
}
void
__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
{
mcontext_t *mc;
char *sp;
va_list ap;
int i, regargs, stackargs;
/* Sanity checks */
if ((ucp == NULL) || (argc < 0)
|| (ucp->uc_stack.ss_sp == NULL)
|| (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
/* invalidate context */
ucp->uc_mcontext.mc_len = 0;
return;
}
/*
* The stack must have space for the frame pointer, saved
* link register, overflow arguments, and be 16-byte
* aligned.
*/
stackargs = (argc > 8) ? argc - 8 : 0;
sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size
- sizeof(uint32_t)*(stackargs + 2);
sp = (char *)((uint32_t)sp & ~0x1f);
mc = &ucp->uc_mcontext;
/*
* Up to 8 register args. Assumes all args are 32-bit and
* integer only. Not sure how to cater for floating point,
* although 64-bit args will work if aligned correctly
* in the arg list.
*/
regargs = (argc > 8) ? 8 : argc;
va_start(ap, argc);
for (i = 0; i < regargs; i++)
mc->mc_gpr[3 + i] = va_arg(ap, uint32_t);
/*
* Overflow args go onto the stack
*/
if (argc > 8) {
uint32_t *argp;
/* Skip past frame pointer and saved LR */
argp = (uint32_t *)sp + 2;
for (i = 0; i < stackargs; i++)
*argp++ = va_arg(ap, uint32_t);
}
va_end(ap);
/*
* Use caller-saved regs 14/15 to hold params that _ctx_start
* will use to invoke the user-supplied func
*/
mc->mc_srr0 = (uint32_t) _ctx_start;
mc->mc_gpr[1] = (uint32_t) sp; /* new stack pointer */
mc->mc_gpr[14] = (uint32_t) start; /* r14 <- start */
mc->mc_gpr[15] = (uint32_t) ucp; /* r15 <- ucp */
}
diff --git a/lib/libc/powerpc/gen/signalcontext.c b/lib/libc/powerpc/gen/signalcontext.c
index 253f1c8a7626..8cc9c1c94918 100644
--- a/lib/libc/powerpc/gen/signalcontext.c
+++ b/lib/libc/powerpc/gen/signalcontext.c
@@ -1,103 +1,102 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Marcel Moolenaar, Peter Grehan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ucontext.h>
#include <signal.h>
#include <stdlib.h>
#include <strings.h>
typedef void (*handler_t)(uint32_t, uint32_t, uint32_t);
/* Prototypes */
static void ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig,
uint32_t sig_si, uint32_t sig_uc);
__weak_reference(__signalcontext, signalcontext);
int
__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
{
siginfo_t *sig_si;
ucontext_t *sig_uc;
uint32_t sp;
/* Bail out if we don't have a valid ucontext pointer. */
if (ucp == NULL)
abort();
/*
* Build a 16-byte-aligned signal frame
*/
sp = (ucp->uc_mcontext.mc_gpr[1] - sizeof(ucontext_t)) & ~15UL;
sig_uc = (ucontext_t *)sp;
bcopy(ucp, sig_uc, sizeof(*sig_uc));
sp = (sp - sizeof(siginfo_t)) & ~15UL;
sig_si = (siginfo_t *)sp;
bzero(sig_si, sizeof(*sig_si));
sig_si->si_signo = sig;
/*
* Subtract 8 bytes from stack to allow for frameptr
*/
sp -= 2*sizeof(uint32_t);
sp &= ~15UL;
/*
* Setup the ucontext of the signal handler.
*/
bzero(&ucp->uc_mcontext, sizeof(ucp->uc_mcontext));
ucp->uc_link = sig_uc;
sigdelset(&ucp->uc_sigmask, sig);
ucp->uc_mcontext.mc_vers = _MC_VERSION;
ucp->uc_mcontext.mc_len = sizeof(struct __mcontext);
ucp->uc_mcontext.mc_srr0 = (uint32_t) ctx_wrapper;
ucp->uc_mcontext.mc_gpr[1] = (uint32_t) sp;
ucp->uc_mcontext.mc_gpr[3] = (uint32_t) func;
ucp->uc_mcontext.mc_gpr[4] = (uint32_t) sig;
ucp->uc_mcontext.mc_gpr[5] = (uint32_t) sig_si;
ucp->uc_mcontext.mc_gpr[6] = (uint32_t) sig_uc;
return (0);
}
static void
ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig, uint32_t sig_si,
uint32_t sig_uc)
{
(*func)(sig, sig_si, sig_uc);
if (ucp->uc_link == NULL)
exit(0);
setcontext((const ucontext_t *)ucp->uc_link);
/* should never get here */
abort();
/* NOTREACHED */
}
diff --git a/lib/libc/powerpc/sys/__vdso_gettc.c b/lib/libc/powerpc/sys/__vdso_gettc.c
index 21f0f2dd87ec..82b8e2f27384 100644
--- a/lib/libc/powerpc/sys/__vdso_gettc.c
+++ b/lib/libc/powerpc/sys/__vdso_gettc.c
@@ -1,66 +1,65 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Brandon Bergren <bdragon@FreeBSD.org>
*
* This software was developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/elf.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <machine/cpufunc.h>
#include <machine/spr.h>
#include <errno.h>
#include "libc_private.h"
#pragma weak __vdso_gettc
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
if (__predict_false(th->th_algo != VDSO_TH_ALGO_PPC_TB))
return (ENOSYS);
/*
* While the timebase is a 64 bit quantity, we are only interested
* in the lower 32 bits of it.
*/
*tc = mfspr(TBR_TBL);
return (0);
}
#pragma weak __vdso_gettimekeep
int
__vdso_gettimekeep(struct vdso_timekeep **tk)
{
return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
}
diff --git a/lib/libc/powerpc64/gen/flt_rounds.c b/lib/libc/powerpc64/gen/flt_rounds.c
index 16ec162fc14b..800ec6944d79 100644
--- a/lib/libc/powerpc64/gen/flt_rounds.c
+++ b/lib/libc/powerpc64/gen/flt_rounds.c
@@ -1,56 +1,55 @@
/* $NetBSD: flt_rounds.c,v 1.4.10.3 2002/03/22 20:41:53 nathanw Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1996 Mark Brinicombe
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe
* for the NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/float.h>
#ifndef _SOFT_FLOAT
static const int map[] = {
1, /* round to nearest */
0, /* round to zero */
2, /* round to positive infinity */
3 /* round to negative infinity */
};
int
__flt_rounds()
{
uint64_t fpscr;
__asm__ __volatile("mffs %0" : "=f"(fpscr));
return map[(fpscr & 0x03)];
}
#endif
diff --git a/lib/libc/powerpc64/gen/fpgetmask.c b/lib/libc/powerpc64/gen/fpgetmask.c
index b4399f23cf72..6817a32bdc65 100644
--- a/lib/libc/powerpc64/gen/fpgetmask.c
+++ b/lib/libc/powerpc64/gen/fpgetmask.c
@@ -1,48 +1,47 @@
/* $NetBSD: fpgetmask.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_except_t
fpgetmask()
{
u_int64_t fpscr;
__asm__("mffs %0" : "=f"(fpscr));
return ((fp_except_t)((fpscr >> 3) & 0x1f));
}
#endif
diff --git a/lib/libc/powerpc64/gen/fpgetround.c b/lib/libc/powerpc64/gen/fpgetround.c
index f6a98d3ffe1f..b135807b613f 100644
--- a/lib/libc/powerpc64/gen/fpgetround.c
+++ b/lib/libc/powerpc64/gen/fpgetround.c
@@ -1,48 +1,47 @@
/* $NetBSD: fpgetround.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_rnd_t
fpgetround()
{
u_int64_t fpscr;
__asm__("mffs %0" : "=f"(fpscr));
return ((fp_rnd_t)(fpscr & 0x3));
}
#endif
diff --git a/lib/libc/powerpc64/gen/fpgetsticky.c b/lib/libc/powerpc64/gen/fpgetsticky.c
index a79f4062c7f9..d609586360fe 100644
--- a/lib/libc/powerpc64/gen/fpgetsticky.c
+++ b/lib/libc/powerpc64/gen/fpgetsticky.c
@@ -1,54 +1,53 @@
/* $NetBSD: fpgetsticky.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
#ifdef __weak_alias
__weak_alias(fpgetsticky,_fpgetsticky)
#endif
fp_except_t
fpgetsticky()
{
u_int64_t fpscr;
__asm__ __volatile("mffs %0" : "=f"(fpscr));
return ((fp_except_t)((fpscr >> 25) & 0x1f));
}
#endif
diff --git a/lib/libc/powerpc64/gen/fpsetmask.c b/lib/libc/powerpc64/gen/fpsetmask.c
index eb5884aa080c..4170b385e9e4 100644
--- a/lib/libc/powerpc64/gen/fpsetmask.c
+++ b/lib/libc/powerpc64/gen/fpsetmask.c
@@ -1,52 +1,51 @@
/* $NetBSD: fpsetmask.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_except_t
fpsetmask(fp_except_t mask)
{
u_int64_t fpscr;
fp_except_t old;
__asm__("mffs %0" : "=f"(fpscr));
old = (fp_except_t)((fpscr >> 3) & 0x1f);
fpscr = (fpscr & 0xffffff07) | ((mask & 0x1f) << 3);
__asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
return (old);
}
#endif
diff --git a/lib/libc/powerpc64/gen/fpsetround.c b/lib/libc/powerpc64/gen/fpsetround.c
index 82ec0ea354c2..2a70fd781474 100644
--- a/lib/libc/powerpc64/gen/fpsetround.c
+++ b/lib/libc/powerpc64/gen/fpsetround.c
@@ -1,52 +1,51 @@
/* $NetBSD: fpsetround.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_rnd_t
fpsetround(fp_rnd_t rnd_dir)
{
u_int64_t fpscr;
fp_rnd_t old;
__asm__ __volatile("mffs %0" : "=f"(fpscr));
old = (fp_rnd_t)(fpscr & 0x3);
fpscr = (fpscr & 0xfffffffc) | rnd_dir;
__asm__ __volatile("mtfsf 0xff,%0" :: "f"(fpscr));
return (old);
}
#endif
diff --git a/lib/libc/powerpc64/gen/makecontext.c b/lib/libc/powerpc64/gen/makecontext.c
index 34d16fc673a8..75c2d40bdd60 100644
--- a/lib/libc/powerpc64/gen/makecontext.c
+++ b/lib/libc/powerpc64/gen/makecontext.c
@@ -1,127 +1,126 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Suleiman Souhlal
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ucontext.h>
__weak_reference(__makecontext, makecontext);
void _ctx_done(ucontext_t *ucp);
void _ctx_start(void);
void
_ctx_done(ucontext_t *ucp)
{
if (ucp->uc_link == NULL)
exit(0);
else {
/* invalidate context */
ucp->uc_mcontext.mc_len = 0;
setcontext((const ucontext_t *)ucp->uc_link);
abort(); /* should never return from above call */
}
}
void
__makecontext(ucontext_t *ucp, void (*start)(void), int argc, ...)
{
mcontext_t *mc;
char *sp;
va_list ap;
int i, regargs, stackargs;
/* Sanity checks */
if ((ucp == NULL) || (argc < 0)
|| (ucp->uc_stack.ss_sp == NULL)
|| (ucp->uc_stack.ss_size < MINSIGSTKSZ)) {
/* invalidate context */
ucp->uc_mcontext.mc_len = 0;
return;
}
/*
* The stack must have space for the frame pointer, saved
* link register, overflow arguments, and be 16-byte
* aligned.
*/
stackargs = (argc > 8) ? argc - 8 : 0;
sp = (char *) ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size
- sizeof(uintptr_t)*(stackargs + 2);
sp = (char *)((uintptr_t)sp & ~0x1f);
mc = &ucp->uc_mcontext;
/*
* Up to 8 register args. Assumes all args are 64-bit and
* integer only. Not sure how to cater for floating point.
*/
regargs = (argc > 8) ? 8 : argc;
va_start(ap, argc);
for (i = 0; i < regargs; i++)
mc->mc_gpr[3 + i] = va_arg(ap, uint64_t);
/*
* Overflow args go onto the stack
*/
if (argc > 8) {
uint64_t *argp;
/* Skip past frame pointer and saved LR */
#if !defined(_CALL_ELF) || _CALL_ELF == 1
argp = (uint64_t *)sp + 6;
#else
argp = (uint64_t *)sp + 4;
#endif
for (i = 0; i < stackargs; i++)
*argp++ = va_arg(ap, uint64_t);
}
va_end(ap);
/*
* Use caller-saved regs 14/15 to hold params that _ctx_start
* will use to invoke the user-supplied func
*/
#if !defined(_CALL_ELF) || _CALL_ELF == 1
/* Cast to ensure this is treated as a function descriptor. */
mc->mc_srr0 = *(uintptr_t *)_ctx_start;
#else
mc->mc_srr0 = (uintptr_t) _ctx_start;
#endif
mc->mc_gpr[1] = (uintptr_t) sp; /* new stack pointer */
mc->mc_gpr[14] = (uintptr_t) start; /* r14 <- start */
mc->mc_gpr[15] = (uintptr_t) ucp; /* r15 <- ucp */
}
diff --git a/lib/libc/powerpc64/gen/signalcontext.c b/lib/libc/powerpc64/gen/signalcontext.c
index 5fac663fb15b..de0b2109bba4 100644
--- a/lib/libc/powerpc64/gen/signalcontext.c
+++ b/lib/libc/powerpc64/gen/signalcontext.c
@@ -1,103 +1,102 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2004 Marcel Moolenaar, Peter Grehan
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/ucontext.h>
#include <signal.h>
#include <stdlib.h>
#include <strings.h>
typedef void (*handler_t)(uint32_t, uint32_t, uint32_t);
/* Prototypes */
static void ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig,
uint32_t sig_si, uint32_t sig_uc);
__weak_reference(__signalcontext, signalcontext);
int
__signalcontext(ucontext_t *ucp, int sig, __sighandler_t *func)
{
siginfo_t *sig_si;
ucontext_t *sig_uc;
uintptr_t sp;
/* Bail out if we don't have a valid ucontext pointer. */
if (ucp == NULL)
abort();
/*
* Build a 16-byte-aligned signal frame
*/
sp = (ucp->uc_mcontext.mc_gpr[1] - sizeof(ucontext_t)) & ~15UL;
sig_uc = (ucontext_t *)sp;
bcopy(ucp, sig_uc, sizeof(*sig_uc));
sp = (sp - sizeof(siginfo_t)) & ~15UL;
sig_si = (siginfo_t *)sp;
bzero(sig_si, sizeof(*sig_si));
sig_si->si_signo = sig;
/*
* Subtract 48 bytes from stack to allow for frameptr
*/
sp -= 6*sizeof(uint64_t);
sp &= ~15UL;
/*
* Setup the ucontext of the signal handler.
*/
bzero(&ucp->uc_mcontext, sizeof(ucp->uc_mcontext));
ucp->uc_link = sig_uc;
sigdelset(&ucp->uc_sigmask, sig);
ucp->uc_mcontext.mc_vers = _MC_VERSION;
ucp->uc_mcontext.mc_len = sizeof(struct __mcontext);
ucp->uc_mcontext.mc_srr0 = (uint64_t) ctx_wrapper;
ucp->uc_mcontext.mc_gpr[1] = (uint64_t) sp;
ucp->uc_mcontext.mc_gpr[3] = (uint64_t) func;
ucp->uc_mcontext.mc_gpr[4] = (uint64_t) sig;
ucp->uc_mcontext.mc_gpr[5] = (uint64_t) sig_si;
ucp->uc_mcontext.mc_gpr[6] = (uint64_t) sig_uc;
return (0);
}
static void
ctx_wrapper(ucontext_t *ucp, handler_t func, uint32_t sig, uint32_t sig_si,
uint32_t sig_uc)
{
(*func)(sig, sig_si, sig_uc);
if (ucp->uc_link == NULL)
exit(0);
setcontext((const ucontext_t *)ucp->uc_link);
/* should never get here */
abort();
/* NOTREACHED */
}
diff --git a/lib/libc/powerpc64/string/bcopy_resolver.c b/lib/libc/powerpc64/string/bcopy_resolver.c
index a551d5d3ca5e..c99c53b2f9b3 100644
--- a/lib/libc/powerpc64/string/bcopy_resolver.c
+++ b/lib/libc/powerpc64/string/bcopy_resolver.c
@@ -1,71 +1,70 @@
/*-
* Copyright (c) 2018 Instituto de Pesquisas Eldorado
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <machine/cpu.h>
#include <machine/ifunc.h>
#define _CAT(a,b) a##b
#define CAT(a,b) _CAT(a,b)
#define CAT3(a,b,c) CAT(CAT(a,b),c)
#ifdef MEMCOPY
#define FN_NAME memcpy
#define FN_RET void *
#define FN_PARAMS (void *dst, const void *src, size_t len)
#elif defined(MEMMOVE)
#define FN_NAME memmove
#define FN_RET void *
#define FN_PARAMS (void *dst, const void *src, size_t len)
#else
#define FN_NAME bcopy
#define FN_RET void
#define FN_PARAMS (const void *src, void *dst, size_t len)
#endif
#define FN_NAME_NOVSX CAT(__, FN_NAME)
#define FN_NAME_VSX CAT3(__, FN_NAME, _vsx)
FN_RET FN_NAME_NOVSX FN_PARAMS;
FN_RET FN_NAME_VSX FN_PARAMS;
DEFINE_UIFUNC(, FN_RET, FN_NAME, FN_PARAMS)
{
/* VSX instructions were added in POWER ISA 2.06,
* however it requires data to be word-aligned.
* Since POWER ISA 2.07B this is solved transparently
* by the hardware
*/
if (cpu_features & PPC_FEATURE_HAS_VSX)
return (FN_NAME_VSX);
else
return (FN_NAME_NOVSX);
}
diff --git a/lib/libc/powerpc64/string/strcpy.c b/lib/libc/powerpc64/string/strcpy.c
index 23531264d8f4..d0be3ca468a0 100644
--- a/lib/libc/powerpc64/string/strcpy.c
+++ b/lib/libc/powerpc64/string/strcpy.c
@@ -1,31 +1,30 @@
/*-
* Copyright (c) 2019 Leandro Lupori
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define WEAK_STRCPY
#include "../../string/strcpy.c"
diff --git a/lib/libc/powerpc64/string/strcpy_resolver.c b/lib/libc/powerpc64/string/strcpy_resolver.c
index 513d33e96e28..7a64ce41c7e4 100644
--- a/lib/libc/powerpc64/string/strcpy_resolver.c
+++ b/lib/libc/powerpc64/string/strcpy_resolver.c
@@ -1,45 +1,44 @@
/*-
* Copyright (c) 2019 Leandro Lupori
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/cpu.h>
#include <machine/ifunc.h>
char *
__strcpy_arch_2_05(char * restrict dst, const char * restrict src);
char *
__strcpy(char * restrict dst, const char * restrict src);
DEFINE_UIFUNC(, char *, strcpy, (char * restrict, const char * restrict))
{
if (cpu_features & PPC_FEATURE_ARCH_2_05)
return (__strcpy_arch_2_05);
else
return (__strcpy);
}
diff --git a/lib/libc/powerpc64/string/strncpy.c b/lib/libc/powerpc64/string/strncpy.c
index 6879834c5818..aef3fb88724a 100644
--- a/lib/libc/powerpc64/string/strncpy.c
+++ b/lib/libc/powerpc64/string/strncpy.c
@@ -1,31 +1,30 @@
/*-
* Copyright (c) 2019 Leandro Lupori
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define WEAK_STRNCPY
#include "../../string/strncpy.c"
diff --git a/lib/libc/powerpc64/string/strncpy_resolver.c b/lib/libc/powerpc64/string/strncpy_resolver.c
index b3b5511c74b5..402b5c5226d0 100644
--- a/lib/libc/powerpc64/string/strncpy_resolver.c
+++ b/lib/libc/powerpc64/string/strncpy_resolver.c
@@ -1,46 +1,45 @@
/*-
* Copyright (c) 2019 Leandro Lupori
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of its contributors may
* be used to endorse or promote products derived from this software
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <machine/cpu.h>
#include <machine/ifunc.h>
char *
__strncpy_arch_2_05(char * restrict dst, const char * restrict src, size_t len);
char *
__strncpy(char * restrict dst, const char * restrict src, size_t len);
DEFINE_UIFUNC(, char *, strncpy,
(char * restrict, const char * restrict, size_t))
{
if (cpu_features & PPC_FEATURE_ARCH_2_05)
return (__strncpy_arch_2_05);
else
return (__strncpy);
}
diff --git a/lib/libc/powerpc64/sys/__vdso_gettc.c b/lib/libc/powerpc64/sys/__vdso_gettc.c
index b9c924e0e542..c1de60a5b956 100644
--- a/lib/libc/powerpc64/sys/__vdso_gettc.c
+++ b/lib/libc/powerpc64/sys/__vdso_gettc.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Brandon Bergren <bdragon@FreeBSD.org>
*
* This software was developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/elf.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <machine/cpufunc.h>
#include <errno.h>
#include "libc_private.h"
#pragma weak __vdso_gettc
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
u_quad_t tb;
if (__predict_false(th->th_algo != VDSO_TH_ALGO_PPC_TB))
return (ENOSYS);
__asm __volatile ("mftb %0" : "=r"(tb));
*tc = tb;
return (0);
}
#pragma weak __vdso_gettimekeep
int
__vdso_gettimekeep(struct vdso_timekeep **tk)
{
return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
}
diff --git a/lib/libc/powerpcspe/gen/flt_rounds.c b/lib/libc/powerpcspe/gen/flt_rounds.c
index eec1d3a05693..26dfca0e0e3a 100644
--- a/lib/libc/powerpcspe/gen/flt_rounds.c
+++ b/lib/libc/powerpcspe/gen/flt_rounds.c
@@ -1,55 +1,54 @@
/* $NetBSD: flt_rounds.c,v 1.4.10.3 2002/03/22 20:41:53 nathanw Exp $ */
/*
* Copyright (c) 2016 Justin Hibbits
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Mark Brinicombe
* for the NetBSD Project.
* 4. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/float.h>
#include <machine/spr.h>
#ifndef _SOFT_FLOAT
static const int map[] = {
1, /* round to nearest */
0, /* round to zero */
2, /* round to positive infinity */
3 /* round to negative infinity */
};
int
__flt_rounds()
{
uint32_t fpscr;
__asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
return map[(fpscr & 0x03)];
}
#endif
diff --git a/lib/libc/powerpcspe/gen/fpgetmask.c b/lib/libc/powerpcspe/gen/fpgetmask.c
index b46a52fae220..f7679be4ca54 100644
--- a/lib/libc/powerpcspe/gen/fpgetmask.c
+++ b/lib/libc/powerpcspe/gen/fpgetmask.c
@@ -1,47 +1,46 @@
/* $NetBSD: fpgetmask.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
/*
* Copyright (c) 2016 Justin Hibbits
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/spr.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_except_t
fpgetmask()
{
uint32_t fpscr;
__asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
return ((fp_except_t)((fpscr >> 2) & 0x1f));
}
#endif
diff --git a/lib/libc/powerpcspe/gen/fpgetround.c b/lib/libc/powerpcspe/gen/fpgetround.c
index 1021a1ad4cc6..9c01bcbaf327 100644
--- a/lib/libc/powerpcspe/gen/fpgetround.c
+++ b/lib/libc/powerpcspe/gen/fpgetround.c
@@ -1,47 +1,46 @@
/* $NetBSD: fpgetround.c,v 1.3 2002/01/13 21:45:47 thorpej Exp $ */
/*
* Copyright (c) 2016 Justin Hibbits
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/spr.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_rnd_t
fpgetround()
{
uint32_t fpscr;
__asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
return ((fp_rnd_t)(fpscr & 0x3));
}
#endif
diff --git a/lib/libc/powerpcspe/gen/fpgetsticky.c b/lib/libc/powerpcspe/gen/fpgetsticky.c
index abe83bb2da31..58bdc43cef38 100644
--- a/lib/libc/powerpcspe/gen/fpgetsticky.c
+++ b/lib/libc/powerpcspe/gen/fpgetsticky.c
@@ -1,53 +1,52 @@
/* $NetBSD: fpgetsticky.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*
* Copyright (c) 2016 Justin Hibbits
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <machine/spr.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
#ifdef __weak_alias
__weak_alias(fpgetsticky,_fpgetsticky)
#endif
fp_except_t
fpgetsticky()
{
uint32_t fpscr;
__asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
return ((fp_except_t)((fpscr >> 25) & 0x1f));
}
#endif
diff --git a/lib/libc/powerpcspe/gen/fpsetmask.c b/lib/libc/powerpcspe/gen/fpsetmask.c
index 0563da982c2e..a7a2569df905 100644
--- a/lib/libc/powerpcspe/gen/fpsetmask.c
+++ b/lib/libc/powerpcspe/gen/fpsetmask.c
@@ -1,51 +1,50 @@
/* $NetBSD: fpsetmask.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*
* Copyright (c) 2016 Justin Hibbits
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/spr.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_except_t
fpsetmask(fp_except_t mask)
{
uint32_t fpscr;
fp_except_t old;
__asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR));
old = (fp_except_t)((fpscr >> 2) & 0x1f);
fpscr = (fpscr & 0xffffff83) | ((mask & 0x1f) << 2);
__asm__ __volatile("mtspr %1,%0;isync" :: "r"(fpscr), "K"(SPR_SPEFSCR));
return (old);
}
#endif
diff --git a/lib/libc/powerpcspe/gen/fpsetround.c b/lib/libc/powerpcspe/gen/fpsetround.c
index 85b55087935a..2280e190b2f9 100644
--- a/lib/libc/powerpcspe/gen/fpsetround.c
+++ b/lib/libc/powerpcspe/gen/fpsetround.c
@@ -1,51 +1,50 @@
/* $NetBSD: fpsetround.c,v 1.3 2002/01/13 21:45:48 thorpej Exp $ */
/*
* Copyright (c) 2016 Justin Hibbits
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dan Winship.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <machine/spr.h>
#include <ieeefp.h>
#ifndef _SOFT_FLOAT
fp_rnd_t
fpsetround(fp_rnd_t rnd_dir)
{
uint32_t fpscr;
fp_rnd_t old;
__asm__ __volatile("mfspr %0, %1" : "=r"(fpscr) : "K"(SPR_SPEFSCR) );
old = (fp_rnd_t)(fpscr & 0x3);
fpscr = (fpscr & 0xfffffffc) | rnd_dir;
__asm__ __volatile("mtspr %1, %0;isync" :: "r"(fpscr), "K"(SPR_SPEFSCR));
return (old);
}
#endif
diff --git a/lib/libc/quad/TESTS/divrem.c b/lib/libc/quad/TESTS/divrem.c
index 1fd83e52d13b..2a18ec3efbe5 100644
--- a/lib/libc/quad/TESTS/divrem.c
+++ b/lib/libc/quad/TESTS/divrem.c
@@ -1,76 +1,75 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)divrem.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
main()
{
union { long long q; unsigned long v[2]; } a, b, q, r;
char buf[300];
extern long long __qdivrem(unsigned long long, unsigned long long,
unsigned long long *);
for (;;) {
printf("> ");
if (fgets(buf, sizeof buf, stdin) == NULL)
break;
if (sscanf(buf, "%lu:%lu %lu:%lu",
&a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4 &&
sscanf(buf, "0x%lx:%lx 0x%lx:%lx",
&a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4) {
printf("eh?\n");
continue;
}
q.q = __qdivrem(a.q, b.q, &r.q);
printf("%lx:%lx /%% %lx:%lx => q=%lx:%lx r=%lx:%lx\n",
a.v[0], a.v[1], b.v[0], b.v[1],
q.v[0], q.v[1], r.v[0], r.v[1]);
printf(" = %lX%08lX / %lX%08lX => %lX%08lX\n\
= %lX%08lX %% %lX%08lX => %lX%08lX\n",
a.v[0], a.v[1], b.v[0], b.v[1], q.v[0], q.v[1],
a.v[0], a.v[1], b.v[0], b.v[1], r.v[0], r.v[1]);
}
exit(0);
}
diff --git a/lib/libc/quad/TESTS/mul.c b/lib/libc/quad/TESTS/mul.c
index f347e4f1e026..b361eee8ad2a 100644
--- a/lib/libc/quad/TESTS/mul.c
+++ b/lib/libc/quad/TESTS/mul.c
@@ -1,72 +1,71 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef lint
static char copyright[] =
"@(#) Copyright (c) 1992, 1993\n\
The Regents of the University of California. All rights reserved.\n";
#endif /* not lint */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mul.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
main()
{
union { long long q; unsigned long v[2]; } a, b, m;
char buf[300];
extern long long __muldi3(long long, long long);
for (;;) {
printf("> ");
if (fgets(buf, sizeof buf, stdin) == NULL)
break;
if (sscanf(buf, "%lu:%lu %lu:%lu",
&a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4 &&
sscanf(buf, "0x%lx:%lx 0x%lx:%lx",
&a.v[0], &a.v[1], &b.v[0], &b.v[1]) != 4) {
printf("eh?\n");
continue;
}
m.q = __muldi3(a.q, b.q);
printf("%lx:%lx * %lx:%lx => %lx:%lx\n",
a.v[0], a.v[1], b.v[0], b.v[1], m.v[0], m.v[1]);
printf(" = %lX%08lX * %lX%08lX => %lX%08lX\n",
a.v[0], a.v[1], b.v[0], b.v[1], m.v[0], m.v[1]);
}
exit(0);
}
diff --git a/lib/libc/quad/adddi3.c b/lib/libc/quad/adddi3.c
index 0f3a41ff4e2c..e3cccf1bb5a3 100644
--- a/lib/libc/quad/adddi3.c
+++ b/lib/libc/quad/adddi3.c
@@ -1,57 +1,56 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)adddi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Add two quads. This is trivial since a one-bit carry from a single
* u_long addition x+y occurs if and only if the sum x+y is less than
* either x or y (the choice to compare with x or y is arbitrary).
*/
quad_t
__adddi3(quad_t a, quad_t b)
{
union uu aa, bb, sum;
aa.q = a;
bb.q = b;
sum.ul[L] = aa.ul[L] + bb.ul[L];
sum.ul[H] = aa.ul[H] + bb.ul[H] + (sum.ul[L] < bb.ul[L]);
return (sum.q);
}
diff --git a/lib/libc/quad/anddi3.c b/lib/libc/quad/anddi3.c
index ad9ec24c1651..9b753a0e9c44 100644
--- a/lib/libc/quad/anddi3.c
+++ b/lib/libc/quad/anddi3.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)anddi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return a & b, in quad.
*/
quad_t
__anddi3(quad_t a, quad_t b)
{
union uu aa, bb;
aa.q = a;
bb.q = b;
aa.ul[0] &= bb.ul[0];
aa.ul[1] &= bb.ul[1];
return (aa.q);
}
diff --git a/lib/libc/quad/ashldi3.c b/lib/libc/quad/ashldi3.c
index b18267c723c1..c3b697a27de0 100644
--- a/lib/libc/quad/ashldi3.c
+++ b/lib/libc/quad/ashldi3.c
@@ -1,62 +1,61 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ashldi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Shift a (signed) quad value left (arithmetic shift left).
* This is the same as logical shift left!
*/
quad_t
__ashldi3(quad_t a, qshift_t shift)
{
union uu aa;
aa.q = a;
if (shift >= LONG_BITS) {
aa.ul[H] = shift >= QUAD_BITS ? 0 :
aa.ul[L] << (shift - LONG_BITS);
aa.ul[L] = 0;
} else if (shift > 0) {
aa.ul[H] = (aa.ul[H] << shift) |
(aa.ul[L] >> (LONG_BITS - shift));
aa.ul[L] <<= shift;
}
return (aa.q);
}
diff --git a/lib/libc/quad/ashrdi3.c b/lib/libc/quad/ashrdi3.c
index a5157c0dc958..7b0117a6f2a6 100644
--- a/lib/libc/quad/ashrdi3.c
+++ b/lib/libc/quad/ashrdi3.c
@@ -1,71 +1,70 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ashrdi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Shift a (signed) quad value right (arithmetic shift right).
*/
quad_t
__ashrdi3(quad_t a, qshift_t shift)
{
union uu aa;
aa.q = a;
if (shift >= LONG_BITS) {
long s;
/*
* Smear bits rightward using the machine's right-shift
* method, whether that is sign extension or zero fill,
* to get the `sign word' s. Note that shifting by
* LONG_BITS is undefined, so we shift (LONG_BITS-1),
* then 1 more, to get our answer.
*/
s = (aa.sl[H] >> (LONG_BITS - 1)) >> 1;
aa.ul[L] = shift >= QUAD_BITS ? s :
aa.sl[H] >> (shift - LONG_BITS);
aa.ul[H] = s;
} else if (shift > 0) {
aa.ul[L] = (aa.ul[L] >> shift) |
(aa.ul[H] << (LONG_BITS - shift));
aa.sl[H] >>= shift;
}
return (aa.q);
}
diff --git a/lib/libc/quad/cmpdi2.c b/lib/libc/quad/cmpdi2.c
index f8aae7f018c6..6f70c5a04cc5 100644
--- a/lib/libc/quad/cmpdi2.c
+++ b/lib/libc/quad/cmpdi2.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)cmpdi2.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return 0, 1, or 2 as a <, =, > b respectively.
* Both a and b are considered signed---which means only the high word is
* signed.
*/
int
__cmpdi2(quad_t a, quad_t b)
{
union uu aa, bb;
aa.q = a;
bb.q = b;
return (aa.sl[H] < bb.sl[H] ? 0 : aa.sl[H] > bb.sl[H] ? 2 :
aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
}
diff --git a/lib/libc/quad/divdi3.c b/lib/libc/quad/divdi3.c
index c913faf4c31c..69da818e389d 100644
--- a/lib/libc/quad/divdi3.c
+++ b/lib/libc/quad/divdi3.c
@@ -1,62 +1,61 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)divdi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Divide two signed quads.
* ??? if -1/2 should produce -1 on this machine, this code is wrong
*/
quad_t
__divdi3(quad_t a, quad_t b)
{
u_quad_t ua, ub, uq;
int neg;
if (a < 0)
ua = -(u_quad_t)a, neg = 1;
else
ua = a, neg = 0;
if (b < 0)
ub = -(u_quad_t)b, neg ^= 1;
else
ub = b;
uq = __qdivrem(ua, ub, (u_quad_t *)0);
return (neg ? -uq : uq);
}
diff --git a/lib/libc/quad/fixdfdi.c b/lib/libc/quad/fixdfdi.c
index 5237a5decfaf..1bc8fae84ac2 100644
--- a/lib/libc/quad/fixdfdi.c
+++ b/lib/libc/quad/fixdfdi.c
@@ -1,59 +1,58 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fixdfdi.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Convert double to (signed) quad.
* We clamp anything that is out of range.
*/
quad_t
__fixdfdi(double x)
{
if (x < 0)
if (x <= (double)QUAD_MIN)
return (QUAD_MIN);
else
return ((quad_t)-(u_quad_t)-x);
else
if (x >= (double)QUAD_MAX)
return (QUAD_MAX);
else
return ((quad_t)(u_quad_t)x);
}
diff --git a/lib/libc/quad/fixsfdi.c b/lib/libc/quad/fixsfdi.c
index 2cbb41767890..4febbedcad62 100644
--- a/lib/libc/quad/fixsfdi.c
+++ b/lib/libc/quad/fixsfdi.c
@@ -1,61 +1,60 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992 The Regents of the University of California.
* All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fixsfdi.c 5.1 (Berkeley) 7/7/92";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Convert float to (signed) quad.
* We clamp anything that is out of range.
*
* N.B.: must use new ANSI syntax (sorry).
*/
long long
__fixsfdi(float x)
{
if (x < 0)
if (x <= (float)QUAD_MIN)
return (QUAD_MIN);
else
return ((quad_t)-(u_quad_t)-x);
else
if (x >= (float)QUAD_MAX)
return (QUAD_MAX);
else
return ((quad_t)(u_quad_t)x);
}
diff --git a/lib/libc/quad/fixunsdfdi.c b/lib/libc/quad/fixunsdfdi.c
index 8fb23d60d363..f22f71faa506 100644
--- a/lib/libc/quad/fixunsdfdi.c
+++ b/lib/libc/quad/fixunsdfdi.c
@@ -1,93 +1,92 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fixunsdfdi.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
#define ONE_FOURTH (1L << (LONG_BITS - 2))
#define ONE_HALF (ONE_FOURTH * 2.0)
#define ONE (ONE_FOURTH * 4.0)
/*
* Convert double to (unsigned) quad.
* Not sure what to do with negative numbers---for now, anything out
* of range becomes UQUAD_MAX.
*/
u_quad_t
__fixunsdfdi(double x)
{
double toppart;
union uu t;
if (x < 0)
return (UQUAD_MAX); /* ??? should be 0? ERANGE??? */
#ifdef notdef /* this falls afoul of a GCC bug */
if (x >= UQUAD_MAX)
return (UQUAD_MAX);
#else /* so we wire in 2^64-1 instead */
if (x >= 18446744073709551615.0)
return (UQUAD_MAX);
#endif
/*
* Get the upper part of the result. Note that the divide
* may round up; we want to avoid this if possible, so we
* subtract `1/2' first.
*/
toppart = (x - ONE_HALF) / ONE;
/*
* Now build a u_quad_t out of the top part. The difference
* between x and this is the bottom part (this may introduce
* a few fuzzy bits, but what the heck). With any luck this
* difference will be nonnegative: x should wind up in the
* range [0..ULONG_MAX]. For paranoia, we assume [LONG_MIN..
* 2*ULONG_MAX] instead.
*/
t.ul[H] = (unsigned long)toppart;
t.ul[L] = 0;
x -= (double)t.uq;
if (x < 0) {
t.ul[H]--;
x += (double)ULONG_MAX;
}
if (x > (double)ULONG_MAX) {
t.ul[H]++;
x -= (double)ULONG_MAX;
}
t.ul[L] = (u_long)x;
return (t.uq);
}
diff --git a/lib/libc/quad/fixunssfdi.c b/lib/libc/quad/fixunssfdi.c
index a1f03f075d9f..40041567f42c 100644
--- a/lib/libc/quad/fixunssfdi.c
+++ b/lib/libc/quad/fixunssfdi.c
@@ -1,98 +1,97 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fixunssfdi.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
#define ONE_FOURTH (1L << (LONG_BITS - 2))
#define ONE_HALF (ONE_FOURTH * 2.0)
#define ONE (ONE_FOURTH * 4.0)
/*
* Convert float to (unsigned) quad. We do most of our work in double,
* out of sheer paranoia.
*
* Not sure what to do with negative numbers---for now, anything out
* of range becomes UQUAD_MAX.
*
* N.B.: must use new ANSI syntax (sorry).
*/
u_quad_t
__fixunssfdi(float f)
{
double x, toppart;
union uu t;
if (f < 0)
return (UQUAD_MAX); /* ??? should be 0? ERANGE??? */
#ifdef notdef /* this falls afoul of a GCC bug */
if (f >= UQUAD_MAX)
return (UQUAD_MAX);
#else /* so we wire in 2^64-1 instead */
if (f >= 18446744073709551615.0)
return (UQUAD_MAX);
#endif
x = f;
/*
* Get the upper part of the result. Note that the divide
* may round up; we want to avoid this if possible, so we
* subtract `1/2' first.
*/
toppart = (x - ONE_HALF) / ONE;
/*
* Now build a u_quad_t out of the top part. The difference
* between x and this is the bottom part (this may introduce
* a few fuzzy bits, but what the heck). With any luck this
* difference will be nonnegative: x should wind up in the
* range [0..ULONG_MAX]. For paranoia, we assume [LONG_MIN..
* 2*ULONG_MAX] instead.
*/
t.ul[H] = (unsigned long)toppart;
t.ul[L] = 0;
x -= (double)t.uq;
if (x < 0) {
t.ul[H]--;
x += (double)ULONG_MAX;
}
if (x > (double)ULONG_MAX) {
t.ul[H]++;
x -= (double)ULONG_MAX;
}
t.ul[L] = (u_long)x;
return (t.uq);
}
diff --git a/lib/libc/quad/floatdidf.c b/lib/libc/quad/floatdidf.c
index 2c4f79da4e45..448bd23c3aba 100644
--- a/lib/libc/quad/floatdidf.c
+++ b/lib/libc/quad/floatdidf.c
@@ -1,71 +1,70 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)floatdidf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Convert (signed) quad to double.
*/
double
__floatdidf(quad_t x)
{
double d;
union uu u;
int neg;
/*
* Get an unsigned number first, by negating if necessary.
*/
if (x < 0)
u.q = -x, neg = 1;
else
u.q = x, neg = 0;
/*
* Now u.ul[H] has the factor of 2^32 (or whatever) and u.ul[L]
* has the units. Ideally we could just set d, add LONG_BITS to
* its exponent, and then add the units, but this is portable
* code and does not know how to get at an exponent. Machine-
* specific code may be able to do this more efficiently.
*/
d = (double)u.ul[H] * ((1L << (LONG_BITS - 2)) * 4.0);
d += u.ul[L];
return (neg ? -d : d);
}
diff --git a/lib/libc/quad/floatdisf.c b/lib/libc/quad/floatdisf.c
index 9b0251eaff2e..ef80183bcd71 100644
--- a/lib/libc/quad/floatdisf.c
+++ b/lib/libc/quad/floatdisf.c
@@ -1,73 +1,72 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)floatdisf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Convert (signed) quad to float.
*/
float
__floatdisf(quad_t x)
{
float f;
union uu u;
int neg;
/*
* Get an unsigned number first, by negating if necessary.
*/
if (x < 0)
u.q = -x, neg = 1;
else
u.q = x, neg = 0;
/*
* Now u.ul[H] has the factor of 2^32 (or whatever) and u.ul[L]
* has the units. Ideally we could just set f, add LONG_BITS to
* its exponent, and then add the units, but this is portable
* code and does not know how to get at an exponent. Machine-
* specific code may be able to do this more efficiently.
*
* Using double here may be excessive paranoia.
*/
f = (double)u.ul[H] * ((1L << (LONG_BITS - 2)) * 4.0);
f += u.ul[L];
return (neg ? -f : f);
}
diff --git a/lib/libc/quad/floatunsdidf.c b/lib/libc/quad/floatunsdidf.c
index 143b0f7da5a4..66c862bb47b6 100644
--- a/lib/libc/quad/floatunsdidf.c
+++ b/lib/libc/quad/floatunsdidf.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)floatunsdidf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Convert (unsigned) quad to double.
* This is exactly like floatdidf.c except that negatives never occur.
*/
double
__floatunsdidf(u_quad_t x)
{
double d;
union uu u;
u.uq = x;
d = (double)u.ul[H] * ((1L << (LONG_BITS - 2)) * 4.0);
d += u.ul[L];
return (d);
}
diff --git a/lib/libc/quad/iordi3.c b/lib/libc/quad/iordi3.c
index 295c075ed18c..5fcf5ecfc71c 100644
--- a/lib/libc/quad/iordi3.c
+++ b/lib/libc/quad/iordi3.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)iordi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return a | b, in quad.
*/
quad_t
__iordi3(quad_t a, quad_t b)
{
union uu aa, bb;
aa.q = a;
bb.q = b;
aa.ul[0] |= bb.ul[0];
aa.ul[1] |= bb.ul[1];
return (aa.q);
}
diff --git a/lib/libc/quad/lshldi3.c b/lib/libc/quad/lshldi3.c
index 1f86398cb54c..5dc89c7b6df4 100644
--- a/lib/libc/quad/lshldi3.c
+++ b/lib/libc/quad/lshldi3.c
@@ -1,62 +1,61 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)lshldi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Shift an (unsigned) quad value left (logical shift left).
* This is the same as arithmetic shift left!
*/
quad_t
__lshldi3(quad_t a, qshift_t shift)
{
union uu aa;
aa.q = a;
if (shift >= LONG_BITS) {
aa.ul[H] = shift >= QUAD_BITS ? 0 :
aa.ul[L] << (shift - LONG_BITS);
aa.ul[L] = 0;
} else if (shift > 0) {
aa.ul[H] = (aa.ul[H] << shift) |
(aa.ul[L] >> (LONG_BITS - shift));
aa.ul[L] <<= shift;
}
return (aa.q);
}
diff --git a/lib/libc/quad/lshrdi3.c b/lib/libc/quad/lshrdi3.c
index 1af382b16da6..c757856a5b5f 100644
--- a/lib/libc/quad/lshrdi3.c
+++ b/lib/libc/quad/lshrdi3.c
@@ -1,61 +1,60 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)lshrdi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Shift an (unsigned) quad value right (logical shift right).
*/
quad_t
__lshrdi3(quad_t a, qshift_t shift)
{
union uu aa;
aa.q = a;
if (shift >= LONG_BITS) {
aa.ul[L] = shift >= QUAD_BITS ? 0 :
aa.ul[H] >> (shift - LONG_BITS);
aa.ul[H] = 0;
} else if (shift > 0) {
aa.ul[L] = (aa.ul[L] >> shift) |
(aa.ul[H] << (LONG_BITS - shift));
aa.ul[H] >>= shift;
}
return (aa.q);
}
diff --git a/lib/libc/quad/moddi3.c b/lib/libc/quad/moddi3.c
index dacd7f849118..13ced7b17112 100644
--- a/lib/libc/quad/moddi3.c
+++ b/lib/libc/quad/moddi3.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)moddi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return remainder after dividing two signed quads.
*
* XXX
* If -1/2 should produce -1 on this machine, this code is wrong.
*/
quad_t
__moddi3(quad_t a, quad_t b)
{
u_quad_t ua, ub, ur;
int neg;
if (a < 0)
ua = -(u_quad_t)a, neg = 1;
else
ua = a, neg = 0;
if (b < 0)
ub = -(u_quad_t)b;
else
ub = b;
(void)__qdivrem(ua, ub, &ur);
return (neg ? -ur : ur);
}
diff --git a/lib/libc/quad/muldi3.c b/lib/libc/quad/muldi3.c
index 194b7d9dd75c..b9c0e8d3a2c5 100644
--- a/lib/libc/quad/muldi3.c
+++ b/lib/libc/quad/muldi3.c
@@ -1,243 +1,242 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)muldi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Multiply two quads.
*
* Our algorithm is based on the following. Split incoming quad values
* u and v (where u,v >= 0) into
*
* u = 2^n u1 * u0 (n = number of bits in `u_long', usu. 32)
*
* and
*
* v = 2^n v1 * v0
*
* Then
*
* uv = 2^2n u1 v1 + 2^n u1 v0 + 2^n v1 u0 + u0 v0
* = 2^2n u1 v1 + 2^n (u1 v0 + v1 u0) + u0 v0
*
* Now add 2^n u1 v1 to the first term and subtract it from the middle,
* and add 2^n u0 v0 to the last term and subtract it from the middle.
* This gives:
*
* uv = (2^2n + 2^n) (u1 v1) +
* (2^n) (u1 v0 - u1 v1 + u0 v1 - u0 v0) +
* (2^n + 1) (u0 v0)
*
* Factoring the middle a bit gives us:
*
* uv = (2^2n + 2^n) (u1 v1) + [u1v1 = high]
* (2^n) (u1 - u0) (v0 - v1) + [(u1-u0)... = mid]
* (2^n + 1) (u0 v0) [u0v0 = low]
*
* The terms (u1 v1), (u1 - u0) (v0 - v1), and (u0 v0) can all be done
* in just half the precision of the original. (Note that either or both
* of (u1 - u0) or (v0 - v1) may be negative.)
*
* This algorithm is from Knuth vol. 2 (2nd ed), section 4.3.3, p. 278.
*
* Since C does not give us a `long * long = quad' operator, we split
* our input quads into two longs, then split the two longs into two
* shorts. We can then calculate `short * short = long' in native
* arithmetic.
*
* Our product should, strictly speaking, be a `long quad', with 128
* bits, but we are going to discard the upper 64. In other words,
* we are not interested in uv, but rather in (uv mod 2^2n). This
* makes some of the terms above vanish, and we get:
*
* (2^n)(high) + (2^n)(mid) + (2^n + 1)(low)
*
* or
*
* (2^n)(high + mid + low) + low
*
* Furthermore, `high' and `mid' can be computed mod 2^n, as any factor
* of 2^n in either one will also vanish. Only `low' need be computed
* mod 2^2n, and only because of the final term above.
*/
static quad_t __lmulq(u_long, u_long);
quad_t
__muldi3(quad_t a, quad_t b)
{
union uu u, v, low, prod;
u_long high, mid, udiff, vdiff;
int negall, negmid;
#define u1 u.ul[H]
#define u0 u.ul[L]
#define v1 v.ul[H]
#define v0 v.ul[L]
/*
* Get u and v such that u, v >= 0. When this is finished,
* u1, u0, v1, and v0 will be directly accessible through the
* longword fields.
*/
if (a >= 0)
u.q = a, negall = 0;
else
u.q = -a, negall = 1;
if (b >= 0)
v.q = b;
else
v.q = -b, negall ^= 1;
if (u1 == 0 && v1 == 0) {
/*
* An (I hope) important optimization occurs when u1 and v1
* are both 0. This should be common since most numbers
* are small. Here the product is just u0*v0.
*/
prod.q = __lmulq(u0, v0);
} else {
/*
* Compute the three intermediate products, remembering
* whether the middle term is negative. We can discard
* any upper bits in high and mid, so we can use native
* u_long * u_long => u_long arithmetic.
*/
low.q = __lmulq(u0, v0);
if (u1 >= u0)
negmid = 0, udiff = u1 - u0;
else
negmid = 1, udiff = u0 - u1;
if (v0 >= v1)
vdiff = v0 - v1;
else
vdiff = v1 - v0, negmid ^= 1;
mid = udiff * vdiff;
high = u1 * v1;
/*
* Assemble the final product.
*/
prod.ul[H] = high + (negmid ? -mid : mid) + low.ul[L] +
low.ul[H];
prod.ul[L] = low.ul[L];
}
return (negall ? -prod.q : prod.q);
#undef u1
#undef u0
#undef v1
#undef v0
}
/*
* Multiply two 2N-bit longs to produce a 4N-bit quad, where N is half
* the number of bits in a long (whatever that is---the code below
* does not care as long as quad.h does its part of the bargain---but
* typically N==16).
*
* We use the same algorithm from Knuth, but this time the modulo refinement
* does not apply. On the other hand, since N is half the size of a long,
* we can get away with native multiplication---none of our input terms
* exceeds (ULONG_MAX >> 1).
*
* Note that, for u_long l, the quad-precision result
*
* l << N
*
* splits into high and low longs as HHALF(l) and LHUP(l) respectively.
*/
static quad_t
__lmulq(u_long u, u_long v)
{
u_long u1, u0, v1, v0, udiff, vdiff, high, mid, low;
u_long prodh, prodl, was;
union uu prod;
int neg;
u1 = HHALF(u);
u0 = LHALF(u);
v1 = HHALF(v);
v0 = LHALF(v);
low = u0 * v0;
/* This is the same small-number optimization as before. */
if (u1 == 0 && v1 == 0)
return (low);
if (u1 >= u0)
udiff = u1 - u0, neg = 0;
else
udiff = u0 - u1, neg = 1;
if (v0 >= v1)
vdiff = v0 - v1;
else
vdiff = v1 - v0, neg ^= 1;
mid = udiff * vdiff;
high = u1 * v1;
/* prod = (high << 2N) + (high << N); */
prodh = high + HHALF(high);
prodl = LHUP(high);
/* if (neg) prod -= mid << N; else prod += mid << N; */
if (neg) {
was = prodl;
prodl -= LHUP(mid);
prodh -= HHALF(mid) + (prodl > was);
} else {
was = prodl;
prodl += LHUP(mid);
prodh += HHALF(mid) + (prodl < was);
}
/* prod += low << N */
was = prodl;
prodl += LHUP(low);
prodh += HHALF(low) + (prodl < was);
/* ... + low; */
if ((prodl += low) < low)
prodh++;
/* return 4N-bit product */
prod.ul[H] = prodh;
prod.ul[L] = prodl;
return (prod.q);
}
diff --git a/lib/libc/quad/negdi2.c b/lib/libc/quad/negdi2.c
index 6f05db6e966a..beee96f4365c 100644
--- a/lib/libc/quad/negdi2.c
+++ b/lib/libc/quad/negdi2.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)negdi2.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return -a (or, equivalently, 0 - a), in quad. See subdi3.c.
*/
quad_t
__negdi2(quad_t a)
{
union uu aa, res;
aa.q = a;
res.ul[L] = -aa.ul[L];
res.ul[H] = -aa.ul[H] - (res.ul[L] > 0);
return (res.q);
}
diff --git a/lib/libc/quad/notdi2.c b/lib/libc/quad/notdi2.c
index 072eed6e4234..c681f7c2f6ec 100644
--- a/lib/libc/quad/notdi2.c
+++ b/lib/libc/quad/notdi2.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)notdi2.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return ~a. For some reason gcc calls this `one's complement' rather
* than `not'.
*/
quad_t
__one_cmpldi2(quad_t a)
{
union uu aa;
aa.q = a;
aa.ul[0] = ~aa.ul[0];
aa.ul[1] = ~aa.ul[1];
return (aa.q);
}
diff --git a/lib/libc/quad/qdivrem.c b/lib/libc/quad/qdivrem.c
index d89d02c2bcd9..c47dc840d671 100644
--- a/lib/libc/quad/qdivrem.c
+++ b/lib/libc/quad/qdivrem.c
@@ -1,276 +1,275 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)qdivrem.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* Multiprecision divide. This algorithm is from Knuth vol. 2 (2nd ed),
* section 4.3.1, pp. 257--259.
*/
#include "quad.h"
#define B (1L << HALF_BITS) /* digit base */
/* Combine two `digits' to make a single two-digit number. */
#define COMBINE(a, b) (((u_long)(a) << HALF_BITS) | (b))
/* select a type for digits in base B: use unsigned short if they fit */
#if ULONG_MAX == 0xffffffff && USHRT_MAX >= 0xffff
typedef unsigned short digit;
#else
typedef u_long digit;
#endif
/*
* Shift p[0]..p[len] left `sh' bits, ignoring any bits that
* `fall out' the left (there never will be any such anyway).
* We may assume len >= 0. NOTE THAT THIS WRITES len+1 DIGITS.
*/
static void
shl(digit *p, int len, int sh)
{
int i;
for (i = 0; i < len; i++)
p[i] = LHALF(p[i] << sh) | (p[i + 1] >> (HALF_BITS - sh));
p[i] = LHALF(p[i] << sh);
}
/*
* __qdivrem(u, v, rem) returns u/v and, optionally, sets *rem to u%v.
*
* We do this in base 2-sup-HALF_BITS, so that all intermediate products
* fit within u_long. As a consequence, the maximum length dividend and
* divisor are 4 `digits' in this base (they are shorter if they have
* leading zeros).
*/
u_quad_t
__qdivrem(u_quad_t uq, u_quad_t vq, u_quad_t *arq)
{
union uu tmp;
digit *u, *v, *q;
digit v1, v2;
u_long qhat, rhat, t;
int m, n, d, j, i;
digit uspace[5], vspace[5], qspace[5];
/*
* Take care of special cases: divide by zero, and u < v.
*/
if (__predict_false(vq == 0)) {
/* divide by zero. */
static volatile const unsigned int zero = 0;
tmp.ul[H] = tmp.ul[L] = 1 / zero;
if (arq)
*arq = uq;
return (tmp.q);
}
if (uq < vq) {
if (arq)
*arq = uq;
return (0);
}
u = &uspace[0];
v = &vspace[0];
q = &qspace[0];
/*
* Break dividend and divisor into digits in base B, then
* count leading zeros to determine m and n. When done, we
* will have:
* u = (u[1]u[2]...u[m+n]) sub B
* v = (v[1]v[2]...v[n]) sub B
* v[1] != 0
* 1 < n <= 4 (if n = 1, we use a different division algorithm)
* m >= 0 (otherwise u < v, which we already checked)
* m + n = 4
* and thus
* m = 4 - n <= 2
*/
tmp.uq = uq;
u[0] = 0;
u[1] = HHALF(tmp.ul[H]);
u[2] = LHALF(tmp.ul[H]);
u[3] = HHALF(tmp.ul[L]);
u[4] = LHALF(tmp.ul[L]);
tmp.uq = vq;
v[1] = HHALF(tmp.ul[H]);
v[2] = LHALF(tmp.ul[H]);
v[3] = HHALF(tmp.ul[L]);
v[4] = LHALF(tmp.ul[L]);
for (n = 4; v[1] == 0; v++) {
if (--n == 1) {
u_long rbj; /* r*B+u[j] (not root boy jim) */
digit q1, q2, q3, q4;
/*
* Change of plan, per exercise 16.
* r = 0;
* for j = 1..4:
* q[j] = floor((r*B + u[j]) / v),
* r = (r*B + u[j]) % v;
* We unroll this completely here.
*/
t = v[2]; /* nonzero, by definition */
q1 = u[1] / t;
rbj = COMBINE(u[1] % t, u[2]);
q2 = rbj / t;
rbj = COMBINE(rbj % t, u[3]);
q3 = rbj / t;
rbj = COMBINE(rbj % t, u[4]);
q4 = rbj / t;
if (arq)
*arq = rbj % t;
tmp.ul[H] = COMBINE(q1, q2);
tmp.ul[L] = COMBINE(q3, q4);
return (tmp.q);
}
}
/*
* By adjusting q once we determine m, we can guarantee that
* there is a complete four-digit quotient at &qspace[1] when
* we finally stop.
*/
for (m = 4 - n; u[1] == 0; u++)
m--;
for (i = 4 - m; --i >= 0;)
q[i] = 0;
q += 4 - m;
/*
* Here we run Program D, translated from MIX to C and acquiring
* a few minor changes.
*
* D1: choose multiplier 1 << d to ensure v[1] >= B/2.
*/
d = 0;
for (t = v[1]; t < B / 2; t <<= 1)
d++;
if (d > 0) {
shl(&u[0], m + n, d); /* u <<= d */
shl(&v[1], n - 1, d); /* v <<= d */
}
/*
* D2: j = 0.
*/
j = 0;
v1 = v[1]; /* for D3 -- note that v[1..n] are constant */
v2 = v[2]; /* for D3 */
do {
digit uj0, uj1, uj2;
/*
* D3: Calculate qhat (\^q, in TeX notation).
* Let qhat = min((u[j]*B + u[j+1])/v[1], B-1), and
* let rhat = (u[j]*B + u[j+1]) mod v[1].
* While rhat < B and v[2]*qhat > rhat*B+u[j+2],
* decrement qhat and increase rhat correspondingly.
* Note that if rhat >= B, v[2]*qhat < rhat*B.
*/
uj0 = u[j + 0]; /* for D3 only -- note that u[j+...] change */
uj1 = u[j + 1]; /* for D3 only */
uj2 = u[j + 2]; /* for D3 only */
if (uj0 == v1) {
qhat = B;
rhat = uj1;
goto qhat_too_big;
} else {
u_long n = COMBINE(uj0, uj1);
qhat = n / v1;
rhat = n % v1;
}
while (v2 * qhat > COMBINE(rhat, uj2)) {
qhat_too_big:
qhat--;
if ((rhat += v1) >= B)
break;
}
/*
* D4: Multiply and subtract.
* The variable `t' holds any borrows across the loop.
* We split this up so that we do not require v[0] = 0,
* and to eliminate a final special case.
*/
for (t = 0, i = n; i > 0; i--) {
t = u[i + j] - v[i] * qhat - t;
u[i + j] = LHALF(t);
t = (B - HHALF(t)) & (B - 1);
}
t = u[j] - t;
u[j] = LHALF(t);
/*
* D5: test remainder.
* There is a borrow if and only if HHALF(t) is nonzero;
* in that (rare) case, qhat was too large (by exactly 1).
* Fix it by adding v[1..n] to u[j..j+n].
*/
if (HHALF(t)) {
qhat--;
for (t = 0, i = n; i > 0; i--) { /* D6: add back. */
t += u[i + j] + v[i];
u[i + j] = LHALF(t);
t = HHALF(t);
}
u[j] = LHALF(u[j] + t);
}
q[j] = qhat;
} while (++j <= m); /* D7: loop on j. */
/*
* If caller wants the remainder, we have to calculate it as
* u[m..m+n] >> d (this is at most n digits and thus fits in
* u[m+1..m+n], but we may need more source digits).
*/
if (arq) {
if (d) {
for (i = m + n; i > m; --i)
u[i] = (u[i] >> d) |
LHALF(u[i - 1] << (HALF_BITS - d));
u[i] = 0;
}
tmp.ul[H] = COMBINE(uspace[1], uspace[2]);
tmp.ul[L] = COMBINE(uspace[3], uspace[4]);
*arq = tmp.q;
}
tmp.ul[H] = COMBINE(qspace[1], qspace[2]);
tmp.ul[L] = COMBINE(qspace[3], qspace[4]);
return (tmp.q);
}
diff --git a/lib/libc/quad/subdi3.c b/lib/libc/quad/subdi3.c
index 149c0d07259a..2082643bdda7 100644
--- a/lib/libc/quad/subdi3.c
+++ b/lib/libc/quad/subdi3.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)subdi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Subtract two quad values. This is trivial since a one-bit carry
* from a single u_long difference x-y occurs if and only if (x-y) > x.
*/
quad_t
__subdi3(quad_t a, quad_t b)
{
union uu aa, bb, diff;
aa.q = a;
bb.q = b;
diff.ul[L] = aa.ul[L] - bb.ul[L];
diff.ul[H] = aa.ul[H] - bb.ul[H] - (diff.ul[L] > aa.ul[L]);
return (diff.q);
}
diff --git a/lib/libc/quad/ucmpdi2.c b/lib/libc/quad/ucmpdi2.c
index 796ec7b089db..51bb757463fb 100644
--- a/lib/libc/quad/ucmpdi2.c
+++ b/lib/libc/quad/ucmpdi2.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ucmpdi2.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return 0, 1, or 2 as a <, =, > b respectively.
* Neither a nor b are considered signed.
*/
int
__ucmpdi2(u_quad_t a, u_quad_t b)
{
union uu aa, bb;
aa.uq = a;
bb.uq = b;
return (aa.ul[H] < bb.ul[H] ? 0 : aa.ul[H] > bb.ul[H] ? 2 :
aa.ul[L] < bb.ul[L] ? 0 : aa.ul[L] > bb.ul[L] ? 2 : 1);
}
diff --git a/lib/libc/quad/udivdi3.c b/lib/libc/quad/udivdi3.c
index b36e1ca6558f..be89cf703b81 100644
--- a/lib/libc/quad/udivdi3.c
+++ b/lib/libc/quad/udivdi3.c
@@ -1,50 +1,49 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)udivdi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Divide two unsigned quads.
*/
u_quad_t
__udivdi3(u_quad_t a, u_quad_t b)
{
return (__qdivrem(a, b, (u_quad_t *)0));
}
diff --git a/lib/libc/quad/umoddi3.c b/lib/libc/quad/umoddi3.c
index 719b6fa49243..53cf1e0d4208 100644
--- a/lib/libc/quad/umoddi3.c
+++ b/lib/libc/quad/umoddi3.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)umoddi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return remainder after dividing two unsigned quads.
*/
u_quad_t
__umoddi3(u_quad_t a, u_quad_t b)
{
u_quad_t r;
(void)__qdivrem(a, b, &r);
return (r);
}
diff --git a/lib/libc/quad/xordi3.c b/lib/libc/quad/xordi3.c
index ce958f799137..a8cfa5c707ca 100644
--- a/lib/libc/quad/xordi3.c
+++ b/lib/libc/quad/xordi3.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This software was developed by the Computer Systems Engineering group
* at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
* contributed to Berkeley.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)xordi3.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "quad.h"
/*
* Return a ^ b, in quad.
*/
quad_t
__xordi3(quad_t a, quad_t b)
{
union uu aa, bb;
aa.q = a;
bb.q = b;
aa.ul[0] ^= bb.ul[0];
aa.ul[1] ^= bb.ul[1];
return (aa.q);
}
diff --git a/lib/libc/regex/engine.c b/lib/libc/regex/engine.c
index 1efaf9a62f67..94a859684468 100644
--- a/lib/libc/regex/engine.c
+++ b/lib/libc/regex/engine.c
@@ -1,1216 +1,1215 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)engine.c 8.5 (Berkeley) 3/20/94
*/
-#include <sys/cdefs.h>
#include <stdbool.h>
/*
* The matching engine and friends. This file is #included by regexec.c
* after suitable #defines of a variety of macros used herein, so that
* different state representations can be used without duplicating masses
* of code.
*/
#ifdef SNAMES
#define stepback sstepback
#define matcher smatcher
#define walk swalk
#define dissect sdissect
#define backref sbackref
#define step sstep
#define print sprint
#define at sat
#define match smat
#endif
#ifdef LNAMES
#define stepback lstepback
#define matcher lmatcher
#define walk lwalk
#define dissect ldissect
#define backref lbackref
#define step lstep
#define print lprint
#define at lat
#define match lmat
#endif
#ifdef MNAMES
#define stepback mstepback
#define matcher mmatcher
#define walk mwalk
#define dissect mdissect
#define backref mbackref
#define step mstep
#define print mprint
#define at mat
#define match mmat
#endif
/* another structure passed up and down to avoid zillions of parameters */
struct match {
struct re_guts *g;
int eflags;
regmatch_t *pmatch; /* [nsub+1] (0 element unused) */
const char *offp; /* offsets work from here */
const char *beginp; /* start of string -- virtual NUL precedes */
const char *endp; /* end of string -- virtual NUL here */
const char *coldp; /* can be no match starting before here */
const char **lastpos; /* [nplus+1] */
STATEVARS;
states st; /* current states */
states fresh; /* states for a fresh start */
states tmp; /* temporary */
states empty; /* empty set of states */
mbstate_t mbs; /* multibyte conversion state */
};
/* ========= begin header generated by ./mkh ========= */
#ifdef __cplusplus
extern "C" {
#endif
/* === engine.c === */
static int matcher(struct re_guts *g, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
static const char *dissect(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst);
static const char *backref(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, sopno lev, int);
static const char *walk(struct match *m, const char *start, const char *stop, sopno startst, sopno stopst, bool fast);
static states step(struct re_guts *g, sopno start, sopno stop, states bef, wint_t ch, states aft, int sflags);
#define MAX_RECURSION 100
#define BOL (OUT-1)
#define EOL (BOL-1)
#define BOLEOL (BOL-2)
#define NOTHING (BOL-3)
#define BOW (BOL-4)
#define EOW (BOL-5)
#define BADCHAR (BOL-6)
#define NWBND (BOL-7)
#define NONCHAR(c) ((c) <= OUT)
/* sflags */
#define SBOS 0x0001
#define SEOS 0x0002
#ifdef REDEBUG
static void print(struct match *m, const char *caption, states st, int ch, FILE *d);
#endif
#ifdef REDEBUG
static void at(struct match *m, const char *title, const char *start, const char *stop, sopno startst, sopno stopst);
#endif
#ifdef REDEBUG
static const char *pchar(int ch);
#endif
#ifdef __cplusplus
}
#endif
/* ========= end header generated by ./mkh ========= */
#ifdef REDEBUG
#define SP(t, s, c) print(m, t, s, c, stdout)
#define AT(t, p1, p2, s1, s2) at(m, t, p1, p2, s1, s2)
#define NOTE(str) { if (m->eflags&REG_TRACE) printf("=%s\n", (str)); }
#else
#define SP(t, s, c) /* nothing */
#define AT(t, p1, p2, s1, s2) /* nothing */
#define NOTE(s) /* nothing */
#endif
/*
* Given a multibyte string pointed to by start, step back nchar characters
* from current position pointed to by cur.
*/
static const char *
stepback(const char *start, const char *cur, int nchar)
{
const char *ret;
int wc, mbc;
mbstate_t mbs;
size_t clen;
if (MB_CUR_MAX == 1)
return ((cur - nchar) > start ? cur - nchar : NULL);
ret = cur;
for (wc = nchar; wc > 0; wc--) {
for (mbc = 1; mbc <= MB_CUR_MAX; mbc++) {
if ((ret - mbc) < start)
return (NULL);
memset(&mbs, 0, sizeof(mbs));
clen = mbrtowc(NULL, ret - mbc, mbc, &mbs);
if (clen != (size_t)-1 && clen != (size_t)-2)
break;
}
if (mbc > MB_CUR_MAX)
return (NULL);
ret -= mbc;
}
return (ret);
}
/*
- matcher - the actual matching engine
== static int matcher(struct re_guts *g, const char *string, \
== size_t nmatch, regmatch_t pmatch[], int eflags);
*/
static int /* 0 success, REG_NOMATCH failure */
matcher(struct re_guts *g,
const char *string,
size_t nmatch,
regmatch_t pmatch[],
int eflags)
{
const char *endp;
size_t i;
struct match mv;
struct match *m = &mv;
const char *dp = NULL;
const sopno gf = g->firststate+1; /* +1 for OEND */
const sopno gl = g->laststate;
const char *start;
const char *stop;
/* Boyer-Moore algorithms variables */
const char *pp;
int cj, mj;
const char *mustfirst;
const char *mustlast;
int *matchjump;
int *charjump;
/* simplify the situation where possible */
if (g->cflags&REG_NOSUB)
nmatch = 0;
if (eflags&REG_STARTEND) {
start = string + pmatch[0].rm_so;
stop = string + pmatch[0].rm_eo;
} else {
start = string;
stop = start + strlen(start);
}
if (stop < start)
return(REG_INVARG);
/* prescreening; this does wonders for this rather slow code */
if (g->must != NULL) {
if (g->charjump != NULL && g->matchjump != NULL) {
mustfirst = g->must;
mustlast = g->must + g->mlen - 1;
charjump = g->charjump;
matchjump = g->matchjump;
pp = mustlast;
for (dp = start+g->mlen-1; dp < stop;) {
/* Fast skip non-matches */
while (dp < stop && charjump[(int)*dp])
dp += charjump[(int)*dp];
if (dp >= stop)
break;
/* Greedy matcher */
/* We depend on not being used for
* for strings of length 1
*/
while (*--dp == *--pp && pp != mustfirst);
if (*dp == *pp)
break;
/* Jump to next possible match */
mj = matchjump[pp - mustfirst];
cj = charjump[(int)*dp];
dp += (cj < mj ? mj : cj);
pp = mustlast;
}
if (pp != mustfirst)
return(REG_NOMATCH);
} else {
for (dp = start; dp < stop; dp++)
if (*dp == g->must[0] &&
stop - dp >= g->mlen &&
memcmp(dp, g->must, (size_t)g->mlen) == 0)
break;
if (dp == stop) /* we didn't find g->must */
return(REG_NOMATCH);
}
}
/* match struct setup */
m->g = g;
m->eflags = eflags;
m->pmatch = NULL;
m->lastpos = NULL;
m->offp = string;
m->beginp = start;
m->endp = stop;
STATESETUP(m, 4);
SETUP(m->st);
SETUP(m->fresh);
SETUP(m->tmp);
SETUP(m->empty);
CLEAR(m->empty);
ZAPSTATE(&m->mbs);
/* Adjust start according to moffset, to speed things up */
if (dp != NULL && g->moffset > -1) {
const char *nstart;
nstart = stepback(start, dp, g->moffset);
if (nstart != NULL)
start = nstart;
}
SP("mloop", m->st, *start);
/* this loop does only one repetition except for backrefs */
for (;;) {
endp = walk(m, start, stop, gf, gl, true);
if (endp == NULL) { /* a miss */
if (m->pmatch != NULL)
free((char *)m->pmatch);
if (m->lastpos != NULL)
free((char *)m->lastpos);
STATETEARDOWN(m);
return(REG_NOMATCH);
}
if (nmatch == 0 && !g->backrefs)
break; /* no further info needed */
/* where? */
assert(m->coldp != NULL);
for (;;) {
NOTE("finding start");
endp = walk(m, m->coldp, stop, gf, gl, false);
if (endp != NULL)
break;
assert(m->coldp < m->endp);
m->coldp += XMBRTOWC(NULL, m->coldp,
m->endp - m->coldp, &m->mbs, 0);
}
if (nmatch == 1 && !g->backrefs)
break; /* no further info needed */
/* oh my, he wants the subexpressions... */
if (m->pmatch == NULL)
m->pmatch = (regmatch_t *)malloc((m->g->nsub + 1) *
sizeof(regmatch_t));
if (m->pmatch == NULL) {
STATETEARDOWN(m);
return(REG_ESPACE);
}
for (i = 1; i <= m->g->nsub; i++)
m->pmatch[i].rm_so = m->pmatch[i].rm_eo = -1;
if (!g->backrefs && !(m->eflags&REG_BACKR)) {
NOTE("dissecting");
dp = dissect(m, m->coldp, endp, gf, gl);
} else {
if (g->nplus > 0 && m->lastpos == NULL)
m->lastpos = malloc((g->nplus+1) *
sizeof(const char *));
if (g->nplus > 0 && m->lastpos == NULL) {
free(m->pmatch);
STATETEARDOWN(m);
return(REG_ESPACE);
}
NOTE("backref dissect");
dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
}
if (dp != NULL)
break;
/* uh-oh... we couldn't find a subexpression-level match */
assert(g->backrefs); /* must be back references doing it */
assert(g->nplus == 0 || m->lastpos != NULL);
for (;;) {
if (dp != NULL || endp <= m->coldp)
break; /* defeat */
NOTE("backoff");
endp = walk(m, m->coldp, endp-1, gf, gl, false);
if (endp == NULL)
break; /* defeat */
/* try it on a shorter possibility */
#ifndef NDEBUG
for (i = 1; i <= m->g->nsub; i++) {
assert(m->pmatch[i].rm_so == -1);
assert(m->pmatch[i].rm_eo == -1);
}
#endif
NOTE("backoff dissect");
dp = backref(m, m->coldp, endp, gf, gl, (sopno)0, 0);
}
assert(dp == NULL || dp == endp);
if (dp != NULL) /* found a shorter one */
break;
/* despite initial appearances, there is no match here */
NOTE("false alarm");
/* recycle starting later */
start = m->coldp + XMBRTOWC(NULL, m->coldp,
stop - m->coldp, &m->mbs, 0);
assert(start <= stop);
}
/* fill in the details if requested */
if (nmatch > 0) {
pmatch[0].rm_so = m->coldp - m->offp;
pmatch[0].rm_eo = endp - m->offp;
}
if (nmatch > 1) {
assert(m->pmatch != NULL);
for (i = 1; i < nmatch; i++)
if (i <= m->g->nsub)
pmatch[i] = m->pmatch[i];
else {
pmatch[i].rm_so = -1;
pmatch[i].rm_eo = -1;
}
}
if (m->pmatch != NULL)
free((char *)m->pmatch);
if (m->lastpos != NULL)
free((char *)m->lastpos);
STATETEARDOWN(m);
return(0);
}
/*
- dissect - figure out what matched what, no back references
== static const char *dissect(struct match *m, const char *start, \
== const char *stop, sopno startst, sopno stopst);
*/
static const char * /* == stop (success) always */
dissect(struct match *m,
const char *start,
const char *stop,
sopno startst,
sopno stopst)
{
int i;
sopno ss; /* start sop of current subRE */
sopno es; /* end sop of current subRE */
const char *sp; /* start of string matched by it */
const char *stp; /* string matched by it cannot pass here */
const char *rest; /* start of rest of string */
const char *tail; /* string unmatched by rest of RE */
sopno ssub; /* start sop of subsubRE */
sopno esub; /* end sop of subsubRE */
const char *ssp; /* start of string matched by subsubRE */
const char *sep; /* end of string matched by subsubRE */
const char *oldssp; /* previous ssp */
const char *dp __unused;
AT("diss", start, stop, startst, stopst);
sp = start;
for (ss = startst; ss < stopst; ss = es) {
/* identify end of subRE */
es = ss;
switch (OP(m->g->strip[es])) {
case OPLUS_:
case OQUEST_:
es += OPND(m->g->strip[es]);
break;
case OCH_:
while (OP(m->g->strip[es]) != (sop)O_CH)
es += OPND(m->g->strip[es]);
break;
}
es++;
/* figure out what it matched */
switch (OP(m->g->strip[ss])) {
case OEND:
assert(nope);
break;
case OCHAR:
sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
break;
case OBOL:
case OEOL:
case OBOW:
case OEOW:
case OBOS:
case OEOS:
case OWBND:
case ONWBND:
break;
case OANY:
case OANYOF:
sp += XMBRTOWC(NULL, sp, stop - start, &m->mbs, 0);
break;
case OBACK_:
case O_BACK:
assert(nope);
break;
/* cases where length of match is hard to find */
case OQUEST_:
stp = stop;
for (;;) {
/* how long could this one be? */
rest = walk(m, sp, stp, ss, es, false);
assert(rest != NULL); /* it did match */
/* could the rest match the rest? */
tail = walk(m, rest, stop, es, stopst, false);
if (tail == stop)
break; /* yes! */
/* no -- try a shorter match for this one */
stp = rest - 1;
assert(stp >= sp); /* it did work */
}
ssub = ss + 1;
esub = es - 1;
/* did innards match? */
if (walk(m, sp, rest, ssub, esub, false) != NULL) {
dp = dissect(m, sp, rest, ssub, esub);
assert(dp == rest);
} else /* no */
assert(sp == rest);
sp = rest;
break;
case OPLUS_:
stp = stop;
for (;;) {
/* how long could this one be? */
rest = walk(m, sp, stp, ss, es, false);
assert(rest != NULL); /* it did match */
/* could the rest match the rest? */
tail = walk(m, rest, stop, es, stopst, false);
if (tail == stop)
break; /* yes! */
/* no -- try a shorter match for this one */
stp = rest - 1;
assert(stp >= sp); /* it did work */
}
ssub = ss + 1;
esub = es - 1;
ssp = sp;
oldssp = ssp;
for (;;) { /* find last match of innards */
sep = walk(m, ssp, rest, ssub, esub, false);
if (sep == NULL || sep == ssp)
break; /* failed or matched null */
oldssp = ssp; /* on to next try */
ssp = sep;
}
if (sep == NULL) {
/* last successful match */
sep = ssp;
ssp = oldssp;
}
assert(sep == rest); /* must exhaust substring */
assert(walk(m, ssp, sep, ssub, esub, false) == rest);
dp = dissect(m, ssp, sep, ssub, esub);
assert(dp == sep);
sp = rest;
break;
case OCH_:
stp = stop;
for (;;) {
/* how long could this one be? */
rest = walk(m, sp, stp, ss, es, false);
assert(rest != NULL); /* it did match */
/* could the rest match the rest? */
tail = walk(m, rest, stop, es, stopst, false);
if (tail == stop)
break; /* yes! */
/* no -- try a shorter match for this one */
stp = rest - 1;
assert(stp >= sp); /* it did work */
}
ssub = ss + 1;
esub = ss + OPND(m->g->strip[ss]) - 1;
assert(OP(m->g->strip[esub]) == OOR1);
for (;;) { /* find first matching branch */
if (walk(m, sp, rest, ssub, esub, false) == rest)
break; /* it matched all of it */
/* that one missed, try next one */
assert(OP(m->g->strip[esub]) == OOR1);
esub++;
assert(OP(m->g->strip[esub]) == OOR2);
ssub = esub + 1;
esub += OPND(m->g->strip[esub]);
if (OP(m->g->strip[esub]) == (sop)OOR2)
esub--;
else
assert(OP(m->g->strip[esub]) == O_CH);
}
dp = dissect(m, sp, rest, ssub, esub);
assert(dp == rest);
sp = rest;
break;
case O_PLUS:
case O_QUEST:
case OOR1:
case OOR2:
case O_CH:
assert(nope);
break;
case OLPAREN:
i = OPND(m->g->strip[ss]);
assert(0 < i && i <= m->g->nsub);
m->pmatch[i].rm_so = sp - m->offp;
break;
case ORPAREN:
i = OPND(m->g->strip[ss]);
assert(0 < i && i <= m->g->nsub);
m->pmatch[i].rm_eo = sp - m->offp;
break;
default: /* uh oh */
assert(nope);
break;
}
}
assert(sp == stop);
return(sp);
}
#define ISBOW(m, sp) \
(sp < m->endp && ISWORD(*sp) && \
((sp == m->beginp && !(m->eflags&REG_NOTBOL)) || \
(sp > m->offp && !ISWORD(*(sp-1)))))
#define ISEOW(m, sp) \
(((sp == m->endp && !(m->eflags&REG_NOTEOL)) || \
(sp < m->endp && *sp == '\n' && \
(m->g->cflags&REG_NEWLINE)) || \
(sp < m->endp && !ISWORD(*sp)) ) && \
(sp > m->beginp && ISWORD(*(sp-1)))) \
/*
- backref - figure out what matched what, figuring in back references
== static const char *backref(struct match *m, const char *start, \
== const char *stop, sopno startst, sopno stopst, sopno lev);
*/
static const char * /* == stop (success) or NULL (failure) */
backref(struct match *m,
const char *start,
const char *stop,
sopno startst,
sopno stopst,
sopno lev, /* PLUS nesting level */
int rec)
{
int i;
sopno ss; /* start sop of current subRE */
const char *sp; /* start of string matched by it */
sopno ssub; /* start sop of subsubRE */
sopno esub; /* end sop of subsubRE */
const char *ssp; /* start of string matched by subsubRE */
const char *dp;
size_t len;
int hard;
sop s;
regoff_t offsave;
cset *cs;
wint_t wc;
AT("back", start, stop, startst, stopst);
sp = start;
/* get as far as we can with easy stuff */
hard = 0;
for (ss = startst; !hard && ss < stopst; ss++)
switch (OP(s = m->g->strip[ss])) {
case OCHAR:
if (sp == stop)
return(NULL);
sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
if (wc != OPND(s))
return(NULL);
break;
case OANY:
if (sp == stop)
return(NULL);
sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
if (wc == BADCHAR)
return (NULL);
break;
case OANYOF:
if (sp == stop)
return (NULL);
cs = &m->g->sets[OPND(s)];
sp += XMBRTOWC(&wc, sp, stop - sp, &m->mbs, BADCHAR);
if (wc == BADCHAR || !CHIN(cs, wc))
return(NULL);
break;
case OBOS:
if (sp == m->beginp && (m->eflags & REG_NOTBOL) == 0)
{ /* yes */ }
else
return(NULL);
break;
case OEOS:
if (sp == m->endp && (m->eflags & REG_NOTEOL) == 0)
{ /* yes */ }
else
return(NULL);
break;
case OBOL:
if ((sp == m->beginp && !(m->eflags&REG_NOTBOL)) ||
(sp > m->offp && sp < m->endp &&
*(sp-1) == '\n' && (m->g->cflags&REG_NEWLINE)))
{ /* yes */ }
else
return(NULL);
break;
case OEOL:
if ( (sp == m->endp && !(m->eflags&REG_NOTEOL)) ||
(sp < m->endp && *sp == '\n' &&
(m->g->cflags&REG_NEWLINE)) )
{ /* yes */ }
else
return(NULL);
break;
case OWBND:
if (ISBOW(m, sp) || ISEOW(m, sp))
{ /* yes */ }
else
return(NULL);
break;
case ONWBND:
if (((sp == m->beginp) && !ISWORD(*sp)) ||
(sp == m->endp && !ISWORD(*(sp - 1))))
{ /* yes, beginning/end of subject */ }
else if (ISWORD(*(sp - 1)) == ISWORD(*sp))
{ /* yes, beginning/end of subject */ }
else
return(NULL);
break;
case OBOW:
if (ISBOW(m, sp))
{ /* yes */ }
else
return(NULL);
break;
case OEOW:
if (ISEOW(m, sp))
{ /* yes */ }
else
return(NULL);
break;
case O_QUEST:
break;
case OOR1: /* matches null but needs to skip */
ss++;
s = m->g->strip[ss];
do {
assert(OP(s) == OOR2);
ss += OPND(s);
} while (OP(s = m->g->strip[ss]) != (sop)O_CH);
/* note that the ss++ gets us past the O_CH */
break;
default: /* have to make a choice */
hard = 1;
break;
}
if (!hard) { /* that was it! */
if (sp != stop)
return(NULL);
return(sp);
}
ss--; /* adjust for the for's final increment */
/* the hard stuff */
AT("hard", sp, stop, ss, stopst);
s = m->g->strip[ss];
switch (OP(s)) {
case OBACK_: /* the vilest depths */
i = OPND(s);
assert(0 < i && i <= m->g->nsub);
if (m->pmatch[i].rm_eo == -1)
return(NULL);
assert(m->pmatch[i].rm_so != -1);
len = m->pmatch[i].rm_eo - m->pmatch[i].rm_so;
if (len == 0 && rec++ > MAX_RECURSION)
return(NULL);
assert(stop - m->beginp >= len);
if (sp > stop - len)
return(NULL); /* not enough left to match */
ssp = m->offp + m->pmatch[i].rm_so;
if (memcmp(sp, ssp, len) != 0)
return(NULL);
while (m->g->strip[ss] != (sop)SOP(O_BACK, i))
ss++;
return(backref(m, sp+len, stop, ss+1, stopst, lev, rec));
case OQUEST_: /* to null or not */
dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
if (dp != NULL)
return(dp); /* not */
return(backref(m, sp, stop, ss+OPND(s)+1, stopst, lev, rec));
case OPLUS_:
assert(m->lastpos != NULL);
assert(lev+1 <= m->g->nplus);
m->lastpos[lev+1] = sp;
return(backref(m, sp, stop, ss+1, stopst, lev+1, rec));
case O_PLUS:
if (sp == m->lastpos[lev]) /* last pass matched null */
return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
/* try another pass */
m->lastpos[lev] = sp;
dp = backref(m, sp, stop, ss-OPND(s)+1, stopst, lev, rec);
if (dp == NULL)
return(backref(m, sp, stop, ss+1, stopst, lev-1, rec));
else
return(dp);
case OCH_: /* find the right one, if any */
ssub = ss + 1;
esub = ss + OPND(s) - 1;
assert(OP(m->g->strip[esub]) == OOR1);
for (;;) { /* find first matching branch */
dp = backref(m, sp, stop, ssub, esub, lev, rec);
if (dp != NULL)
return(dp);
/* that one missed, try next one */
if (OP(m->g->strip[esub]) == (sop)O_CH)
return(NULL); /* there is none */
esub++;
assert(OP(m->g->strip[esub]) == (sop)OOR2);
ssub = esub + 1;
esub += OPND(m->g->strip[esub]);
if (OP(m->g->strip[esub]) == (sop)OOR2)
esub--;
else
assert(OP(m->g->strip[esub]) == O_CH);
}
/* NOTREACHED */
break;
case OLPAREN: /* must undo assignment if rest fails */
i = OPND(s);
assert(0 < i && i <= m->g->nsub);
offsave = m->pmatch[i].rm_so;
m->pmatch[i].rm_so = sp - m->offp;
dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
if (dp != NULL)
return(dp);
m->pmatch[i].rm_so = offsave;
return(NULL);
case ORPAREN: /* must undo assignment if rest fails */
i = OPND(s);
assert(0 < i && i <= m->g->nsub);
offsave = m->pmatch[i].rm_eo;
m->pmatch[i].rm_eo = sp - m->offp;
dp = backref(m, sp, stop, ss+1, stopst, lev, rec);
if (dp != NULL)
return(dp);
m->pmatch[i].rm_eo = offsave;
return(NULL);
default: /* uh oh */
assert(nope);
break;
}
/* "can't happen" */
assert(nope);
/* NOTREACHED */
return "shut up gcc";
}
/*
- walk - step through the string either quickly or slowly
== static const char *walk(struct match *m, const char *start, \
== const char *stop, sopno startst, sopno stopst, bool fast);
*/
static const char * /* where it ended, or NULL */
walk(struct match *m, const char *start, const char *stop, sopno startst,
sopno stopst, bool fast)
{
states st = m->st;
states fresh = m->fresh;
states empty = m->empty;
states tmp = m->tmp;
const char *p = start;
wint_t c;
wint_t lastc; /* previous c */
wint_t flagch;
int i, sflags;
const char *matchp; /* last p at which a match ended */
size_t clen;
sflags = 0;
AT("slow", start, stop, startst, stopst);
CLEAR(st);
SET1(st, startst);
SP("sstart", st, *p);
st = step(m->g, startst, stopst, st, NOTHING, st, sflags);
if (fast)
ASSIGN(fresh, st);
matchp = NULL;
if (start == m->offp || (start == m->beginp && !(m->eflags&REG_NOTBOL)))
c = OUT;
else {
/*
* XXX Wrong if the previous character was multi-byte.
* Newline never is (in encodings supported by FreeBSD),
* so this only breaks the ISWORD tests below.
*/
c = (uch)*(start - 1);
}
for (;;) {
/* next character */
lastc = c;
sflags = 0;
if (p == m->endp) {
c = OUT;
clen = 0;
} else
clen = XMBRTOWC(&c, p, m->endp - p, &m->mbs, BADCHAR);
if (fast && EQ(st, fresh))
matchp = p;
/* is there an EOL and/or BOL between lastc and c? */
flagch = '\0';
i = 0;
if ( (lastc == '\n' && m->g->cflags&REG_NEWLINE) ||
(lastc == OUT && !(m->eflags&REG_NOTBOL)) ) {
flagch = BOL;
i = m->g->nbol;
}
if ( (c == '\n' && m->g->cflags&REG_NEWLINE) ||
(c == OUT && !(m->eflags&REG_NOTEOL)) ) {
flagch = (flagch == BOL) ? BOLEOL : EOL;
i += m->g->neol;
}
if (lastc == OUT && (m->eflags & REG_NOTBOL) == 0) {
sflags |= SBOS;
/* Step one more for BOS. */
i++;
}
if (c == OUT && (m->eflags & REG_NOTEOL) == 0) {
sflags |= SEOS;
/* Step one more for EOS. */
i++;
}
if (i != 0) {
for (; i > 0; i--)
st = step(m->g, startst, stopst, st, flagch, st,
sflags);
SP("sboleol", st, c);
}
/* how about a word boundary? */
if ( (flagch == BOL || (lastc != OUT && !ISWORD(lastc))) &&
(c != OUT && ISWORD(c)) ) {
flagch = BOW;
}
if ( (lastc != OUT && ISWORD(lastc)) &&
(flagch == EOL || (c != OUT && !ISWORD(c))) ) {
flagch = EOW;
}
if (flagch == BOW || flagch == EOW) {
st = step(m->g, startst, stopst, st, flagch, st, sflags);
SP("sboweow", st, c);
}
if (lastc != OUT && c != OUT &&
ISWORD(lastc) == ISWORD(c)) {
flagch = NWBND;
} else if ((lastc == OUT && !ISWORD(c)) ||
(c == OUT && !ISWORD(lastc))) {
flagch = NWBND;
}
if (flagch == NWBND) {
st = step(m->g, startst, stopst, st, flagch, st, sflags);
SP("snwbnd", st, c);
}
/* are we done? */
if (ISSET(st, stopst)) {
if (fast)
break;
else
matchp = p;
}
if (EQ(st, empty) || p == stop || clen > (size_t)(stop - p))
break; /* NOTE BREAK OUT */
/* no, we must deal with this character */
ASSIGN(tmp, st);
if (fast)
ASSIGN(st, fresh);
else
ASSIGN(st, empty);
assert(c != OUT);
st = step(m->g, startst, stopst, tmp, c, st, sflags);
SP("saft", st, c);
assert(EQ(step(m->g, startst, stopst, st, NOTHING, st, sflags),
st));
p += clen;
}
if (fast) {
assert(matchp != NULL);
m->coldp = matchp;
if (ISSET(st, stopst))
return (p + XMBRTOWC(NULL, p, stop - p, &m->mbs, 0));
else
return (NULL);
} else
return (matchp);
}
/*
- step - map set of states reachable before char to set reachable after
== static states step(struct re_guts *g, sopno start, sopno stop, \
== states bef, int ch, states aft);
== #define BOL (OUT-1)
== #define EOL (BOL-1)
== #define BOLEOL (BOL-2)
== #define NOTHING (BOL-3)
== #define BOW (BOL-4)
== #define EOW (BOL-5)
== #define BADCHAR (BOL-6)
== #define NONCHAR(c) ((c) <= OUT)
*/
static states
step(struct re_guts *g,
sopno start, /* start state within strip */
sopno stop, /* state after stop state within strip */
states bef, /* states reachable before */
wint_t ch, /* character or NONCHAR code */
states aft, /* states already known reachable after */
int sflags) /* state flags */
{
cset *cs;
sop s;
sopno pc;
onestate here; /* note, macros know this name */
sopno look;
int i;
for (pc = start, INIT(here, pc); pc != stop; pc++, INC(here)) {
s = g->strip[pc];
switch (OP(s)) {
case OEND:
assert(pc == stop-1);
break;
case OCHAR:
/* only characters can match */
assert(!NONCHAR(ch) || ch != OPND(s));
if (ch == OPND(s))
FWD(aft, bef, 1);
break;
case OBOS:
if ((ch == BOL || ch == BOLEOL) && (sflags & SBOS) != 0)
FWD(aft, bef, 1);
break;
case OEOS:
if ((ch == EOL || ch == BOLEOL) && (sflags & SEOS) != 0)
FWD(aft, bef, 1);
break;
case OBOL:
if (ch == BOL || ch == BOLEOL)
FWD(aft, bef, 1);
break;
case OEOL:
if (ch == EOL || ch == BOLEOL)
FWD(aft, bef, 1);
break;
case OBOW:
if (ch == BOW)
FWD(aft, bef, 1);
break;
case OEOW:
if (ch == EOW)
FWD(aft, bef, 1);
break;
case OWBND:
if (ch == BOW || ch == EOW)
FWD(aft, bef, 1);
break;
case ONWBND:
if (ch == NWBND)
FWD(aft, aft, 1);
break;
case OANY:
if (!NONCHAR(ch))
FWD(aft, bef, 1);
break;
case OANYOF:
cs = &g->sets[OPND(s)];
if (!NONCHAR(ch) && CHIN(cs, ch))
FWD(aft, bef, 1);
break;
case OBACK_: /* ignored here */
case O_BACK:
FWD(aft, aft, 1);
break;
case OPLUS_: /* forward, this is just an empty */
FWD(aft, aft, 1);
break;
case O_PLUS: /* both forward and back */
FWD(aft, aft, 1);
i = ISSETBACK(aft, OPND(s));
BACK(aft, aft, OPND(s));
if (!i && ISSETBACK(aft, OPND(s))) {
/* oho, must reconsider loop body */
pc -= OPND(s) + 1;
INIT(here, pc);
}
break;
case OQUEST_: /* two branches, both forward */
FWD(aft, aft, 1);
FWD(aft, aft, OPND(s));
break;
case O_QUEST: /* just an empty */
FWD(aft, aft, 1);
break;
case OLPAREN: /* not significant here */
case ORPAREN:
FWD(aft, aft, 1);
break;
case OCH_: /* mark the first two branches */
FWD(aft, aft, 1);
assert(OP(g->strip[pc+OPND(s)]) == (sop)OOR2);
FWD(aft, aft, OPND(s));
break;
case OOR1: /* done a branch, find the O_CH */
if (ISSTATEIN(aft, here)) {
for (look = 1;
OP(s = g->strip[pc+look]) != (sop)O_CH;
look += OPND(s))
assert(OP(s) == (sop)OOR2);
FWD(aft, aft, look + 1);
}
break;
case OOR2: /* propagate OCH_'s marking */
FWD(aft, aft, 1);
if (OP(g->strip[pc+OPND(s)]) != (sop)O_CH) {
assert(OP(g->strip[pc+OPND(s)]) == (sop)OOR2);
FWD(aft, aft, OPND(s));
}
break;
case O_CH: /* just empty */
FWD(aft, aft, 1);
break;
default: /* ooooops... */
assert(nope);
break;
}
}
return(aft);
}
#ifdef REDEBUG
/*
- print - print a set of states
== #ifdef REDEBUG
== static void print(struct match *m, const char *caption, states st, \
== int ch, FILE *d);
== #endif
*/
static void
print(struct match *m,
const char *caption,
states st,
int ch,
FILE *d)
{
struct re_guts *g = m->g;
sopno i;
int first = 1;
if (!(m->eflags&REG_TRACE))
return;
fprintf(d, "%s", caption);
if (ch != '\0')
fprintf(d, " %s", pchar(ch));
for (i = 0; i < g->nstates; i++)
if (ISSET(st, i)) {
fprintf(d, "%s%lu", (first) ? "\t" : ", ", i);
first = 0;
}
fprintf(d, "\n");
}
/*
- at - print current situation
== #ifdef REDEBUG
== static void at(struct match *m, const char *title, const char *start, \
== const char *stop, sopno startst, sopno stopst);
== #endif
*/
static void
at( struct match *m,
const char *title,
const char *start,
const char *stop,
sopno startst,
sopno stopst)
{
if (!(m->eflags&REG_TRACE))
return;
printf("%s %s-", title, pchar(*start));
printf("%s ", pchar(*stop));
printf("%ld-%ld\n", (long)startst, (long)stopst);
}
#ifndef PCHARDONE
#define PCHARDONE /* never again */
/*
- pchar - make a character printable
== #ifdef REDEBUG
== static const char *pchar(int ch);
== #endif
*
* Is this identical to regchar() over in debug.c? Well, yes. But a
* duplicate here avoids having a debugging-capable regexec.o tied to
* a matching debug.o, and this is convenient. It all disappears in
* the non-debug compilation anyway, so it doesn't matter much.
*/
static const char * /* -> representation */
pchar(int ch)
{
static char pbuf[10];
if (isprint((uch)ch) || ch == ' ')
sprintf(pbuf, "%c", ch);
else
sprintf(pbuf, "\\%o", ch);
return(pbuf);
}
#endif
#endif
#undef stepback
#undef matcher
#undef walk
#undef dissect
#undef backref
#undef step
#undef print
#undef at
#undef match
diff --git a/lib/libc/regex/grot/debug.c b/lib/libc/regex/grot/debug.c
index 24e34138007e..f5984366f3c6 100644
--- a/lib/libc/regex/grot/debug.c
+++ b/lib/libc/regex/grot/debug.c
@@ -1,210 +1,209 @@
-#include <sys/cdefs.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
#include <sys/types.h>
#include <regex.h>
#include <wchar.h>
#include <wctype.h>
#include "utils.h"
#include "regex2.h"
#include "debug.ih"
/*
- regprint - print a regexp for debugging
== void regprint(regex_t *r, FILE *d);
*/
void
regprint(r, d)
regex_t *r;
FILE *d;
{
struct re_guts *g = r->re_g;
int i;
int c;
int last;
fprintf(d, "%ld states", (long)g->nstates);
fprintf(d, ", first %ld last %ld", (long)g->firststate,
(long)g->laststate);
if (g->iflags&USEBOL)
fprintf(d, ", USEBOL");
if (g->iflags&USEEOL)
fprintf(d, ", USEEOL");
if (g->iflags&BAD)
fprintf(d, ", BAD");
if (g->nsub > 0)
fprintf(d, ", nsub=%ld", (long)g->nsub);
if (g->must != NULL)
fprintf(d, ", must(%ld) `%*s'", (long)g->mlen, (int)g->mlen,
g->must);
if (g->backrefs)
fprintf(d, ", backrefs");
if (g->nplus > 0)
fprintf(d, ", nplus %ld", (long)g->nplus);
fprintf(d, "\n");
s_print(g, d);
}
/*
- s_print - print the strip for debugging
== static void s_print(struct re_guts *g, FILE *d);
*/
static void
s_print(g, d)
struct re_guts *g;
FILE *d;
{
sop *s;
cset *cs;
int i;
int done = 0;
sop opnd;
int col = 0;
int last;
sopno offset = 2;
# define GAP() { if (offset % 5 == 0) { \
if (col > 40) { \
fprintf(d, "\n\t"); \
col = 0; \
} else { \
fprintf(d, " "); \
col++; \
} \
} else \
col++; \
offset++; \
}
if (OP(g->strip[0]) != OEND)
fprintf(d, "missing initial OEND!\n");
for (s = &g->strip[1]; !done; s++) {
opnd = OPND(*s);
switch (OP(*s)) {
case OEND:
fprintf(d, "\n");
done = 1;
break;
case OCHAR:
if (strchr("\\|()^$.[+*?{}!<> ", (char)opnd) != NULL)
fprintf(d, "\\%c", (char)opnd);
else
fprintf(d, "%s", regchar((char)opnd));
break;
case OBOL:
fprintf(d, "^");
break;
case OEOL:
fprintf(d, "$");
break;
case OBOW:
fprintf(d, "\\{");
break;
case OEOW:
fprintf(d, "\\}");
break;
case OANY:
fprintf(d, ".");
break;
case OANYOF:
fprintf(d, "[(%ld)", (long)opnd);
#if 0
cs = &g->sets[opnd];
last = -1;
for (i = 0; i < g->csetsize+1; i++) /* +1 flushes */
if (CHIN(cs, i) && i < g->csetsize) {
if (last < 0) {
fprintf(d, "%s", regchar(i));
last = i;
}
} else {
if (last >= 0) {
if (last != i-1)
fprintf(d, "-%s",
regchar(i-1));
last = -1;
}
}
#endif
fprintf(d, "]");
break;
case OBACK_:
fprintf(d, "(\\<%ld>", (long)opnd);
break;
case O_BACK:
fprintf(d, "<%ld>\\)", (long)opnd);
break;
case OPLUS_:
fprintf(d, "(+");
if (OP(*(s+opnd)) != O_PLUS)
fprintf(d, "<%ld>", (long)opnd);
break;
case O_PLUS:
if (OP(*(s-opnd)) != OPLUS_)
fprintf(d, "<%ld>", (long)opnd);
fprintf(d, "+)");
break;
case OQUEST_:
fprintf(d, "(?");
if (OP(*(s+opnd)) != O_QUEST)
fprintf(d, "<%ld>", (long)opnd);
break;
case O_QUEST:
if (OP(*(s-opnd)) != OQUEST_)
fprintf(d, "<%ld>", (long)opnd);
fprintf(d, "?)");
break;
case OLPAREN:
fprintf(d, "((<%ld>", (long)opnd);
break;
case ORPAREN:
fprintf(d, "<%ld>))", (long)opnd);
break;
case OCH_:
fprintf(d, "<");
if (OP(*(s+opnd)) != OOR2)
fprintf(d, "<%ld>", (long)opnd);
break;
case OOR1:
if (OP(*(s-opnd)) != OOR1 && OP(*(s-opnd)) != OCH_)
fprintf(d, "<%ld>", (long)opnd);
fprintf(d, "|");
break;
case OOR2:
fprintf(d, "|");
if (OP(*(s+opnd)) != OOR2 && OP(*(s+opnd)) != O_CH)
fprintf(d, "<%ld>", (long)opnd);
break;
case O_CH:
if (OP(*(s-opnd)) != OOR1)
fprintf(d, "<%ld>", (long)opnd);
fprintf(d, ">");
break;
default:
fprintf(d, "!%ld(%ld)!", OP(*s), (long)opnd);
break;
}
if (!done)
GAP();
}
}
/*
- regchar - make a character printable
== static char *regchar(int ch);
*/
static char * /* -> representation */
regchar(ch)
int ch;
{
static char buf[10];
if (isprint(ch) || ch == ' ')
sprintf(buf, "%c", ch);
else
sprintf(buf, "\\%o", ch);
return(buf);
}
diff --git a/lib/libc/regex/grot/main.c b/lib/libc/regex/grot/main.c
index 248fe0ca438a..e9d57c84e6f4 100644
--- a/lib/libc/regex/grot/main.c
+++ b/lib/libc/regex/grot/main.c
@@ -1,492 +1,491 @@
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <assert.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "debug.ih"
#include "main.ih"
#include "split.ih"
char *progname;
int debug = 0;
int line = 0;
int status = 0;
int copts = REG_EXTENDED;
int eopts = 0;
regoff_t startoff = 0;
regoff_t endoff = 0;
/*
- main - do the simple case, hand off to regress() for regression
*/
int
main(int argc, char **argv)
{
regex_t re;
# define NS 10
regmatch_t subs[NS];
char erbuf[100];
int err;
size_t len;
int c;
int errflg = 0;
int i;
extern int optind;
extern char *optarg;
progname = argv[0];
while ((c = getopt(argc, argv, "c:e:S:E:x")) != -1)
switch (c) {
case 'c': /* compile options */
copts = options('c', optarg);
break;
case 'e': /* execute options */
eopts = options('e', optarg);
break;
case 'S': /* start offset */
startoff = (regoff_t)atoi(optarg);
break;
case 'E': /* end offset */
endoff = (regoff_t)atoi(optarg);
break;
case 'x': /* Debugging. */
debug++;
break;
case '?':
default:
errflg++;
break;
}
if (errflg) {
fprintf(stderr, "usage: %s ", progname);
fprintf(stderr, "[-c copt][-C][-d] [re]\n");
exit(2);
}
if (optind >= argc) {
regress(stdin);
exit(status);
}
err = regcomp(&re, argv[optind++], copts);
if (err) {
len = regerror(err, &re, erbuf, sizeof(erbuf));
fprintf(stderr, "error %s, %zu/%zu `%s'\n",
eprint(err), len, sizeof(erbuf), erbuf);
exit(status);
}
regprint(&re, stdout);
if (optind >= argc) {
regfree(&re);
exit(status);
}
if ((eopts & REG_STARTEND) != 0) {
subs[0].rm_so = startoff;
subs[0].rm_eo = strlen(argv[optind]) - endoff;
}
err = regexec(&re, argv[optind], (size_t)NS, subs, eopts);
if (err) {
len = regerror(err, &re, erbuf, sizeof(erbuf));
fprintf(stderr, "error %s, %zu/%zu `%s'\n",
eprint(err), len, sizeof(erbuf), erbuf);
exit(status);
}
if ((copts & REG_NOSUB) == 0) {
len = (int)(subs[0].rm_eo - subs[0].rm_so);
if (subs[0].rm_so != -1) {
if (len != 0)
printf("match `%.*s'\n", (int)len,
argv[optind] + subs[0].rm_so);
else
printf("match `'@%.1s\n",
argv[optind] + subs[0].rm_so);
}
for (i = 1; i < NS; i++)
if (subs[i].rm_so != -1)
printf("(%d) `%.*s'\n", i,
(int)(subs[i].rm_eo - subs[i].rm_so),
argv[optind] + subs[i].rm_so);
}
exit(status);
}
/*
- regress - main loop of regression test
== void regress(FILE *in);
*/
void
regress(FILE *in)
{
char inbuf[1000];
# define MAXF 10
char *f[MAXF];
int nf;
int i;
char erbuf[100];
size_t ne;
char *badpat = "invalid regular expression";
# define SHORT 10
char *bpname = "REG_BADPAT";
regex_t re;
while (fgets(inbuf, sizeof(inbuf), in) != NULL) {
line++;
if (inbuf[0] == '#' || inbuf[0] == '\n')
continue; /* NOTE CONTINUE */
inbuf[strlen(inbuf)-1] = '\0'; /* get rid of stupid \n */
if (debug)
fprintf(stdout, "%d:\n", line);
nf = split(inbuf, f, MAXF, "\t\t");
if (nf < 3) {
fprintf(stderr, "bad input, line %d\n", line);
exit(1);
}
for (i = 0; i < nf; i++)
if (strcmp(f[i], "\"\"") == 0)
f[i] = "";
if (nf <= 3)
f[3] = NULL;
if (nf <= 4)
f[4] = NULL;
try(f[0], f[1], f[2], f[3], f[4], options('c', f[1]));
if (opt('&', f[1])) /* try with either type of RE */
try(f[0], f[1], f[2], f[3], f[4],
options('c', f[1]) &~ REG_EXTENDED);
}
ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
if (strcmp(erbuf, badpat) != 0 || ne != strlen(badpat)+1) {
fprintf(stderr, "end: regerror() test gave `%s' not `%s'\n",
erbuf, badpat);
status = 1;
}
ne = regerror(REG_BADPAT, (regex_t *)NULL, erbuf, (size_t)SHORT);
if (strncmp(erbuf, badpat, SHORT-1) != 0 || erbuf[SHORT-1] != '\0' ||
ne != strlen(badpat)+1) {
fprintf(stderr, "end: regerror() short test gave `%s' not `%.*s'\n",
erbuf, SHORT-1, badpat);
status = 1;
}
ne = regerror(REG_ITOA|REG_BADPAT, (regex_t *)NULL, erbuf, sizeof(erbuf));
if (strcmp(erbuf, bpname) != 0 || ne != strlen(bpname) + 1) {
fprintf(stderr, "end: regerror() ITOA test gave `%s' not `%s'\n",
erbuf, bpname);
status = 1;
}
re.re_endp = bpname;
ne = regerror(REG_ATOI, &re, erbuf, sizeof(erbuf));
if (atoi(erbuf) != (int)REG_BADPAT) {
fprintf(stderr, "end: regerror() ATOI test gave `%s' not `%ld'\n",
erbuf, (long)REG_BADPAT);
status = 1;
} else if (ne != strlen(erbuf) + 1) {
fprintf(stderr, "end: regerror() ATOI test len(`%s') = %ld\n",
erbuf, (long)REG_BADPAT);
status = 1;
}
}
/*
- try - try it, and report on problems
== void try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts);
- opts: may not match f1
*/
void
try(char *f0, char *f1, char *f2, char *f3, char *f4, int opts)
{
regex_t re;
# define NSUBS 10
regmatch_t subs[NSUBS];
# define NSHOULD 15
char *should[NSHOULD];
char erbuf[100];
size_t len;
int err, i, nshould;
char *grump;
char *type = (opts & REG_EXTENDED) ? "ERE" : "BRE";
char f0copy[1000];
char f2copy[1000];
strcpy(f0copy, f0);
re.re_endp = (opts&REG_PEND) ? f0copy + strlen(f0copy) : NULL;
fixstr(f0copy);
err = regcomp(&re, f0copy, opts);
if (err != 0 && (!opt('C', f1) || err != efind(f2))) {
/* unexpected error or wrong error */
len = regerror(err, &re, erbuf, sizeof(erbuf));
fprintf(stderr, "%d: %s error %s, %zu/%zu `%s'\n",
line, type, eprint(err), len, sizeof(erbuf), erbuf);
status = 1;
} else if (err == 0 && opt('C', f1)) {
/* unexpected success */
fprintf(stderr, "%d: %s should have given REG_%s\n",
line, type, f2);
status = 1;
err = 1; /* so we won't try regexec */
}
if (err != 0) {
regfree(&re);
return;
}
strcpy(f2copy, f2);
fixstr(f2copy);
if (options('e', f1)&REG_STARTEND) {
if (strchr(f2, '(') == NULL || strchr(f2, ')') == NULL)
fprintf(stderr, "%d: bad STARTEND syntax\n", line);
subs[0].rm_so = strchr(f2, '(') - f2 + 1;
subs[0].rm_eo = strchr(f2, ')') - f2;
}
err = regexec(&re, f2copy, NSUBS, subs, options('e', f1));
if (err != 0 && (f3 != NULL || err != REG_NOMATCH)) {
/* unexpected error or wrong error */
len = regerror(err, &re, erbuf, sizeof(erbuf));
fprintf(stderr, "%d: %s exec error %s, %zu/%zu `%s'\n",
line, type, eprint(err), len, sizeof(erbuf), erbuf);
status = 1;
} else if (err != 0) {
/* nothing more to check */
} else if (f3 == NULL) {
/* unexpected success */
fprintf(stderr, "%d: %s exec should have failed\n",
line, type);
status = 1;
err = 1; /* just on principle */
} else if (opts&REG_NOSUB) {
/* nothing more to check */
} else if ((grump = check(f2, subs[0], f3)) != NULL) {
fprintf(stderr, "%d: %s %s\n", line, type, grump);
status = 1;
err = 1;
}
if (err != 0 || f4 == NULL) {
regfree(&re);
return;
}
for (i = 1; i < NSHOULD; i++)
should[i] = NULL;
nshould = split(f4, should+1, NSHOULD-1, ",");
if (nshould == 0) {
nshould = 1;
should[1] = "";
}
for (i = 1; i < NSUBS; i++) {
grump = check(f2, subs[i], should[i]);
if (grump != NULL) {
fprintf(stderr, "%d: %s $%d %s\n", line,
type, i, grump);
status = 1;
err = 1;
}
}
regfree(&re);
}
/*
- options - pick options out of a regression-test string
- type: 'c' - compile, 'e' - exec
== int options(int type, char *s);
*/
int
options(int type, char *s)
{
char *p;
int o = (type == 'c') ? copts : eopts;
char *legal = (type == 'c') ? "bisnmp" : "^$#tl";
for (p = s; *p != '\0'; p++)
if (strchr(legal, *p) != NULL)
switch (*p) {
case 'b':
o &= ~REG_EXTENDED;
break;
case 'i':
o |= REG_ICASE;
break;
case 's':
o |= REG_NOSUB;
break;
case 'n':
o |= REG_NEWLINE;
break;
case 'm':
o &= ~REG_EXTENDED;
o |= REG_NOSPEC;
break;
case 'p':
o |= REG_PEND;
break;
case '^':
o |= REG_NOTBOL;
break;
case '$':
o |= REG_NOTEOL;
break;
case '#':
o |= REG_STARTEND;
break;
case 't': /* trace */
o |= REG_TRACE;
break;
case 'l': /* force long representation */
o |= REG_LARGE;
break;
case 'r': /* force backref use */
o |= REG_BACKR;
break;
}
return(o);
}
/*
- opt - is a particular option in a regression string?
== int opt(int c, char *s);
*/
int /* predicate */
opt(int c, char *s)
{
return(strchr(s, c) != NULL);
}
/*
- fixstr - transform magic characters in strings
== void fixstr(char *p);
*/
void
fixstr(char *p)
{
if (p == NULL)
return;
for (; *p != '\0'; p++)
if (*p == 'N')
*p = '\n';
else if (*p == 'T')
*p = '\t';
else if (*p == 'S')
*p = ' ';
else if (*p == 'Z')
*p = '\0';
}
/*
- check - check a substring match
== char *check(char *str, regmatch_t sub, char *should);
*/
char * /* NULL or complaint */
check(char *str, regmatch_t sub, char *should)
{
int len;
int shlen;
char *p;
static char grump[500];
char *at = NULL;
if (should != NULL && strcmp(should, "-") == 0)
should = NULL;
if (should != NULL && should[0] == '@') {
at = should + 1;
should = "";
}
/* check rm_so and rm_eo for consistency */
if (sub.rm_so > sub.rm_eo || (sub.rm_so == -1 && sub.rm_eo != -1) ||
(sub.rm_so != -1 && sub.rm_eo == -1) ||
(sub.rm_so != -1 && sub.rm_so < 0) ||
(sub.rm_eo != -1 && sub.rm_eo < 0) ) {
sprintf(grump, "start %ld end %ld", (long)sub.rm_so,
(long)sub.rm_eo);
return(grump);
}
/* check for no match */
if (sub.rm_so == -1 && should == NULL)
return(NULL);
if (sub.rm_so == -1)
return("did not match");
/* check for in range */
if (sub.rm_eo > strlen(str)) {
sprintf(grump, "start %ld end %ld, past end of string",
(long)sub.rm_so, (long)sub.rm_eo);
return(grump);
}
len = (int)(sub.rm_eo - sub.rm_so);
shlen = (int)strlen(should);
p = str + sub.rm_so;
/* check for not supposed to match */
if (should == NULL) {
sprintf(grump, "matched `%.*s'", len, p);
return(grump);
}
/* check for wrong match */
if (len != shlen || strncmp(p, should, (size_t)shlen) != 0) {
sprintf(grump, "matched `%.*s' instead", len, p);
return(grump);
}
if (shlen > 0)
return(NULL);
/* check null match in right place */
if (at == NULL)
return(NULL);
shlen = strlen(at);
if (shlen == 0)
shlen = 1; /* force check for end-of-string */
if (strncmp(p, at, shlen) != 0) {
sprintf(grump, "matched null at `%.20s'", p);
return(grump);
}
return(NULL);
}
/*
- eprint - convert error number to name
== static char *eprint(int err);
*/
static char *
eprint(int err)
{
static char epbuf[100];
size_t len;
len = regerror(REG_ITOA|err, (regex_t *)NULL, epbuf, sizeof(epbuf));
assert(len <= sizeof(epbuf));
return(epbuf);
}
/*
- efind - convert error name to number
== static int efind(char *name);
*/
static int
efind(char *name)
{
static char efbuf[100];
size_t n;
regex_t re;
sprintf(efbuf, "REG_%s", name);
assert(strlen(efbuf) < sizeof(efbuf));
re.re_endp = efbuf;
(void) regerror(REG_ATOI, &re, efbuf, sizeof(efbuf));
return(atoi(efbuf));
}
diff --git a/lib/libc/regex/grot/split.c b/lib/libc/regex/grot/split.c
index 89afef0f7cee..37d593e5eb4f 100644
--- a/lib/libc/regex/grot/split.c
+++ b/lib/libc/regex/grot/split.c
@@ -1,314 +1,313 @@
-#include <sys/cdefs.h>
#include <stdio.h>
#include <string.h>
#include "split.ih"
/*
- split - divide a string into fields, like awk split()
== int split(char *string, char *fields[], int nfields, char *sep);
- fields: list is not NULL-terminated
- nfields: number of entries available in fields[]
- sep: "" white, "c" single char, "ab" [ab]+
*/
int /* number of fields, including overflow */
split(char *string, char *fields[], int nfields, char *sep)
{
char *p = string;
char c; /* latest character */
char sepc = sep[0];
char sepc2;
int fn;
char **fp = fields;
char *sepp;
int trimtrail;
/* white space */
if (sepc == '\0') {
while ((c = *p++) == ' ' || c == '\t')
continue;
p--;
trimtrail = 1;
sep = " \t"; /* note, code below knows this is 2 long */
sepc = ' ';
} else
trimtrail = 0;
sepc2 = sep[1]; /* now we can safely pick this up */
/* catch empties */
if (*p == '\0')
return(0);
/* single separator */
if (sepc2 == '\0') {
fn = nfields;
for (;;) {
*fp++ = p;
fn--;
if (fn == 0)
break;
while ((c = *p++) != sepc)
if (c == '\0')
return(nfields - fn);
*(p-1) = '\0';
}
/* we have overflowed the fields vector -- just count them */
fn = nfields;
for (;;) {
while ((c = *p++) != sepc)
if (c == '\0')
return(fn);
fn++;
}
/* not reached */
}
/* two separators */
if (sep[2] == '\0') {
fn = nfields;
for (;;) {
*fp++ = p;
fn--;
while ((c = *p++) != sepc && c != sepc2)
if (c == '\0') {
if (trimtrail && **(fp-1) == '\0')
fn++;
return(nfields - fn);
}
if (fn == 0)
break;
*(p-1) = '\0';
while ((c = *p++) == sepc || c == sepc2)
continue;
p--;
}
/* we have overflowed the fields vector -- just count them */
fn = nfields;
while (c != '\0') {
while ((c = *p++) == sepc || c == sepc2)
continue;
p--;
fn++;
while ((c = *p++) != '\0' && c != sepc && c != sepc2)
continue;
}
/* might have to trim trailing white space */
if (trimtrail) {
p--;
while ((c = *--p) == sepc || c == sepc2)
continue;
p++;
if (*p != '\0') {
if (fn == nfields+1)
*p = '\0';
fn--;
}
}
return(fn);
}
/* n separators */
fn = 0;
for (;;) {
if (fn < nfields)
*fp++ = p;
fn++;
for (;;) {
c = *p++;
if (c == '\0')
return(fn);
sepp = sep;
while ((sepc = *sepp++) != '\0' && sepc != c)
continue;
if (sepc != '\0') /* it was a separator */
break;
}
if (fn < nfields)
*(p-1) = '\0';
for (;;) {
c = *p++;
sepp = sep;
while ((sepc = *sepp++) != '\0' && sepc != c)
continue;
if (sepc == '\0') /* it wasn't a separator */
break;
}
p--;
}
/* not reached */
}
#ifdef TEST_SPLIT
/*
* test program
* pgm runs regression
* pgm sep splits stdin lines by sep
* pgm str sep splits str by sep
* pgm str sep n splits str by sep n times
*/
int
main(int argc, char *argv[])
{
char buf[512];
int n;
# define MNF 10
char *fields[MNF];
if (argc > 4)
for (n = atoi(argv[3]); n > 0; n--) {
(void) strcpy(buf, argv[1]);
}
else if (argc > 3)
for (n = atoi(argv[3]); n > 0; n--) {
(void) strcpy(buf, argv[1]);
(void) split(buf, fields, MNF, argv[2]);
}
else if (argc > 2)
dosplit(argv[1], argv[2]);
else if (argc > 1)
while (fgets(buf, sizeof(buf), stdin) != NULL) {
buf[strlen(buf)-1] = '\0'; /* stomp newline */
dosplit(buf, argv[1]);
}
else
regress();
exit(0);
}
void
dosplit(char *string, char *seps)
{
# define NF 5
char *fields[NF];
int nf;
nf = split(string, fields, NF, seps);
print(nf, NF, fields);
}
void
print(int nf, int nfp, char *fields[])
{
int fn;
int bound;
bound = (nf > nfp) ? nfp : nf;
printf("%d:\t", nf);
for (fn = 0; fn < bound; fn++)
printf("\"%s\"%s", fields[fn], (fn+1 < nf) ? ", " : "\n");
}
#define RNF 5 /* some table entries know this */
struct {
char *str;
char *seps;
int nf;
char *fi[RNF];
} tests[] = {
"", " ", 0, { "" },
" ", " ", 2, { "", "" },
"x", " ", 1, { "x" },
"xy", " ", 1, { "xy" },
"x y", " ", 2, { "x", "y" },
"abc def g ", " ", 5, { "abc", "def", "", "g", "" },
" a bcd", " ", 4, { "", "", "a", "bcd" },
"a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
" a b c d ", " ", 6, { "", "a", "b", "c", "d " },
"", " _", 0, { "" },
" ", " _", 2, { "", "" },
"x", " _", 1, { "x" },
"x y", " _", 2, { "x", "y" },
"ab _ cd", " _", 2, { "ab", "cd" },
" a_b c ", " _", 5, { "", "a", "b", "c", "" },
"a b c_d e f", " _", 6, { "a", "b", "c", "d", "e f" },
" a b c d ", " _", 6, { "", "a", "b", "c", "d " },
"", " _~", 0, { "" },
" ", " _~", 2, { "", "" },
"x", " _~", 1, { "x" },
"x y", " _~", 2, { "x", "y" },
"ab _~ cd", " _~", 2, { "ab", "cd" },
" a_b c~", " _~", 5, { "", "a", "b", "c", "" },
"a b_c d~e f", " _~", 6, { "a", "b", "c", "d", "e f" },
"~a b c d ", " _~", 6, { "", "a", "b", "c", "d " },
"", " _~-", 0, { "" },
" ", " _~-", 2, { "", "" },
"x", " _~-", 1, { "x" },
"x y", " _~-", 2, { "x", "y" },
"ab _~- cd", " _~-", 2, { "ab", "cd" },
" a_b c~", " _~-", 5, { "", "a", "b", "c", "" },
"a b_c-d~e f", " _~-", 6, { "a", "b", "c", "d", "e f" },
"~a-b c d ", " _~-", 6, { "", "a", "b", "c", "d " },
"", " ", 0, { "" },
" ", " ", 2, { "", "" },
"x", " ", 1, { "x" },
"xy", " ", 1, { "xy" },
"x y", " ", 2, { "x", "y" },
"abc def g ", " ", 4, { "abc", "def", "g", "" },
" a bcd", " ", 3, { "", "a", "bcd" },
"a b c d e f", " ", 6, { "a", "b", "c", "d", "e f" },
" a b c d ", " ", 6, { "", "a", "b", "c", "d " },
"", "", 0, { "" },
" ", "", 0, { "" },
"x", "", 1, { "x" },
"xy", "", 1, { "xy" },
"x y", "", 2, { "x", "y" },
"abc def g ", "", 3, { "abc", "def", "g" },
"\t a bcd", "", 2, { "a", "bcd" },
" a \tb\t c ", "", 3, { "a", "b", "c" },
"a b c d e ", "", 5, { "a", "b", "c", "d", "e" },
"a b\tc d e f", "", 6, { "a", "b", "c", "d", "e f" },
" a b c d e f ", "", 6, { "a", "b", "c", "d", "e f " },
NULL, NULL, 0, { NULL },
};
void
regress(void)
{
char buf[512];
int n;
char *fields[RNF+1];
int nf;
int i;
int printit;
char *f;
for (n = 0; tests[n].str != NULL; n++) {
(void) strcpy(buf, tests[n].str);
fields[RNF] = NULL;
nf = split(buf, fields, RNF, tests[n].seps);
printit = 0;
if (nf != tests[n].nf) {
printf("split `%s' by `%s' gave %d fields, not %d\n",
tests[n].str, tests[n].seps, nf, tests[n].nf);
printit = 1;
} else if (fields[RNF] != NULL) {
printf("split() went beyond array end\n");
printit = 1;
} else {
for (i = 0; i < nf && i < RNF; i++) {
f = fields[i];
if (f == NULL)
f = "(NULL)";
if (strcmp(f, tests[n].fi[i]) != 0) {
printf("split `%s' by `%s' field %d is `%s', not `%s'\n",
tests[n].str, tests[n].seps,
i, fields[i], tests[n].fi[i]);
printit = 1;
}
}
}
if (printit)
print(nf, RNF, fields);
}
}
#endif
diff --git a/lib/libc/regex/regcomp.c b/lib/libc/regex/regcomp.c
index 42fa1b99e58e..55f96a2ccbd2 100644
--- a/lib/libc/regex/regcomp.c
+++ b/lib/libc/regex/regcomp.c
@@ -1,2234 +1,2233 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)regcomp.c 8.5 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)regcomp.c 8.5 (Berkeley) 3/20/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <stdlib.h>
#include <regex.h>
#include <stdbool.h>
#include <wchar.h>
#include <wctype.h>
#ifndef LIBREGEX
#include "collate.h"
#endif
#include "utils.h"
#include "regex2.h"
#include "cname.h"
/*
* Branching context, used to keep track of branch state for all of the branch-
* aware functions. In addition to keeping track of branch positions for the
* p_branch_* functions, we use this to simplify some clumsiness in BREs for
* detection of whether ^ is acting as an anchor or being used erroneously and
* also for whether we're in a sub-expression or not.
*/
struct branchc {
sopno start;
sopno back;
sopno fwd;
int nbranch;
int nchain;
bool outer;
bool terminate;
};
/*
* parse structure, passed up and down to avoid global variables and
* other clumsinesses
*/
struct parse {
const char *next; /* next character in RE */
const char *end; /* end of string (-> NUL normally) */
int error; /* has an error been seen? */
int gnuext;
sop *strip; /* malloced strip */
sopno ssize; /* malloced strip size (allocated) */
sopno slen; /* malloced strip length (used) */
int ncsalloc; /* number of csets allocated */
struct re_guts *g;
# define NPAREN 10 /* we need to remember () 1-9 for back refs */
sopno pbegin[NPAREN]; /* -> ( ([0] unused) */
sopno pend[NPAREN]; /* -> ) ([0] unused) */
bool allowbranch; /* can this expression branch? */
bool bre; /* convenience; is this a BRE? */
int pflags; /* other parsing flags -- legacy escapes? */
bool (*parse_expr)(struct parse *, struct branchc *);
void (*pre_parse)(struct parse *, struct branchc *);
void (*post_parse)(struct parse *, struct branchc *);
};
#define PFLAG_LEGACY_ESC 0x00000001
/* ========= begin header generated by ./mkh ========= */
#ifdef __cplusplus
extern "C" {
#endif
/* === regcomp.c === */
static bool p_ere_exp(struct parse *p, struct branchc *bc);
static void p_str(struct parse *p);
static int p_branch_eat_delim(struct parse *p, struct branchc *bc);
static void p_branch_ins_offset(struct parse *p, struct branchc *bc);
static void p_branch_fix_tail(struct parse *p, struct branchc *bc);
static bool p_branch_empty(struct parse *p, struct branchc *bc);
static bool p_branch_do(struct parse *p, struct branchc *bc);
static void p_bre_pre_parse(struct parse *p, struct branchc *bc);
static void p_bre_post_parse(struct parse *p, struct branchc *bc);
static void p_re(struct parse *p, int end1, int end2);
static bool p_simp_re(struct parse *p, struct branchc *bc);
static int p_count(struct parse *p);
static void p_bracket(struct parse *p);
static int p_range_cmp(wchar_t c1, wchar_t c2);
static void p_b_term(struct parse *p, cset *cs);
static int p_b_pseudoclass(struct parse *p, char c);
static void p_b_cclass(struct parse *p, cset *cs);
static void p_b_cclass_named(struct parse *p, cset *cs, const char[]);
static void p_b_eclass(struct parse *p, cset *cs);
static wint_t p_b_symbol(struct parse *p);
static wint_t p_b_coll_elem(struct parse *p, wint_t endc);
static bool may_escape(struct parse *p, const wint_t ch);
static wint_t othercase(wint_t ch);
static void bothcases(struct parse *p, wint_t ch);
static void ordinary(struct parse *p, wint_t ch);
static void nonnewline(struct parse *p);
static void repeat(struct parse *p, sopno start, int from, int to);
static int seterr(struct parse *p, int e);
static cset *allocset(struct parse *p);
static void freeset(struct parse *p, cset *cs);
static void CHadd(struct parse *p, cset *cs, wint_t ch);
static void CHaddrange(struct parse *p, cset *cs, wint_t min, wint_t max);
static void CHaddtype(struct parse *p, cset *cs, wctype_t wct);
static wint_t singleton(cset *cs);
static sopno dupl(struct parse *p, sopno start, sopno finish);
static void doemit(struct parse *p, sop op, size_t opnd);
static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos);
static void dofwd(struct parse *p, sopno pos, sop value);
static int enlarge(struct parse *p, sopno size);
static void stripsnug(struct parse *p, struct re_guts *g);
static void findmust(struct parse *p, struct re_guts *g);
static int altoffset(sop *scan, int offset);
static void computejumps(struct parse *p, struct re_guts *g);
static void computematchjumps(struct parse *p, struct re_guts *g);
static sopno pluscount(struct parse *p, struct re_guts *g);
static wint_t wgetnext(struct parse *p);
#ifdef __cplusplus
}
#endif
/* ========= end header generated by ./mkh ========= */
static char nuls[10]; /* place to point scanner in event of error */
/*
* macros for use with parse structure
* BEWARE: these know that the parse structure is named `p' !!!
*/
#define PEEK() (*p->next)
#define PEEK2() (*(p->next+1))
#define MORE() (p->end - p->next > 0)
#define MORE2() (p->end - p->next > 1)
#define SEE(c) (MORE() && PEEK() == (c))
#define SEETWO(a, b) (MORE2() && PEEK() == (a) && PEEK2() == (b))
#define SEESPEC(a) (p->bre ? SEETWO('\\', a) : SEE(a))
#define EAT(c) ((SEE(c)) ? (NEXT(), 1) : 0)
#define EATTWO(a, b) ((SEETWO(a, b)) ? (NEXT2(), 1) : 0)
#define EATSPEC(a) (p->bre ? EATTWO('\\', a) : EAT(a))
#define NEXT() (p->next++)
#define NEXT2() (p->next += 2)
#define NEXTn(n) (p->next += (n))
#define GETNEXT() (*p->next++)
#define WGETNEXT() wgetnext(p)
#define SETERROR(e) seterr(p, (e))
#define REQUIRE(co, e) ((co) || SETERROR(e))
#define MUSTSEE(c, e) (REQUIRE(MORE() && PEEK() == (c), e))
#define MUSTEAT(c, e) (REQUIRE(MORE() && GETNEXT() == (c), e))
#define MUSTNOTSEE(c, e) (REQUIRE(!MORE() || PEEK() != (c), e))
#define EMIT(op, sopnd) doemit(p, (sop)(op), (size_t)(sopnd))
#define INSERT(op, pos) doinsert(p, (sop)(op), HERE()-(pos)+1, pos)
#define AHEAD(pos) dofwd(p, pos, HERE()-(pos))
#define ASTERN(sop, pos) EMIT(sop, HERE()-pos)
#define HERE() (p->slen)
#define THERE() (p->slen - 1)
#define THERETHERE() (p->slen - 2)
#define DROP(n) (p->slen -= (n))
/* Macro used by computejump()/computematchjump() */
#define MIN(a,b) ((a)<(b)?(a):(b))
static int /* 0 success, otherwise REG_something */
regcomp_internal(regex_t * __restrict preg,
const char * __restrict pattern,
int cflags, int pflags)
{
struct parse pa;
struct re_guts *g;
struct parse *p = &pa;
int i;
size_t len;
size_t maxlen;
#ifdef REDEBUG
# define GOODFLAGS(f) (f)
#else
# define GOODFLAGS(f) ((f)&~REG_DUMP)
#endif
cflags = GOODFLAGS(cflags);
if ((cflags&REG_EXTENDED) && (cflags&REG_NOSPEC))
return(REG_INVARG);
if (cflags&REG_PEND) {
if (preg->re_endp < pattern)
return(REG_INVARG);
len = preg->re_endp - pattern;
} else
len = strlen(pattern);
/* do the mallocs early so failure handling is easy */
g = (struct re_guts *)malloc(sizeof(struct re_guts));
if (g == NULL)
return(REG_ESPACE);
/*
* Limit the pattern space to avoid a 32-bit overflow on buffer
* extension. Also avoid any signed overflow in case of conversion
* so make the real limit based on a 31-bit overflow.
*
* Likely not applicable on 64-bit systems but handle the case
* generically (who are we to stop people from using ~715MB+
* patterns?).
*/
maxlen = ((size_t)-1 >> 1) / sizeof(sop) * 2 / 3;
if (len >= maxlen) {
free((char *)g);
return(REG_ESPACE);
}
p->ssize = len/(size_t)2*(size_t)3 + (size_t)1; /* ugh */
assert(p->ssize >= len);
p->strip = (sop *)malloc(p->ssize * sizeof(sop));
p->slen = 0;
if (p->strip == NULL) {
free((char *)g);
return(REG_ESPACE);
}
/* set things up */
p->g = g;
p->next = pattern; /* convenience; we do not modify it */
p->end = p->next + len;
p->error = 0;
p->ncsalloc = 0;
p->pflags = pflags;
for (i = 0; i < NPAREN; i++) {
p->pbegin[i] = 0;
p->pend[i] = 0;
}
#ifdef LIBREGEX
if (cflags&REG_POSIX) {
p->gnuext = false;
p->allowbranch = (cflags & REG_EXTENDED) != 0;
} else
p->gnuext = p->allowbranch = true;
#else
p->gnuext = false;
p->allowbranch = (cflags & REG_EXTENDED) != 0;
#endif
if (cflags & REG_EXTENDED) {
p->bre = false;
p->parse_expr = p_ere_exp;
p->pre_parse = NULL;
p->post_parse = NULL;
} else {
p->bre = true;
p->parse_expr = p_simp_re;
p->pre_parse = p_bre_pre_parse;
p->post_parse = p_bre_post_parse;
}
g->sets = NULL;
g->ncsets = 0;
g->cflags = cflags;
g->iflags = 0;
g->nbol = 0;
g->neol = 0;
g->must = NULL;
g->moffset = -1;
g->charjump = NULL;
g->matchjump = NULL;
g->mlen = 0;
g->nsub = 0;
g->backrefs = 0;
/* do it */
EMIT(OEND, 0);
g->firststate = THERE();
if (cflags & REG_NOSPEC)
p_str(p);
else
p_re(p, OUT, OUT);
EMIT(OEND, 0);
g->laststate = THERE();
/* tidy up loose ends and fill things in */
stripsnug(p, g);
findmust(p, g);
/* only use Boyer-Moore algorithm if the pattern is bigger
* than three characters
*/
if(g->mlen > 3) {
computejumps(p, g);
computematchjumps(p, g);
if(g->matchjump == NULL && g->charjump != NULL) {
free(g->charjump);
g->charjump = NULL;
}
}
g->nplus = pluscount(p, g);
g->magic = MAGIC2;
preg->re_nsub = g->nsub;
preg->re_g = g;
preg->re_magic = MAGIC1;
#ifndef REDEBUG
/* not debugging, so can't rely on the assert() in regexec() */
if (g->iflags&BAD)
SETERROR(REG_ASSERT);
#endif
/* win or lose, we're done */
if (p->error != 0) /* lose */
regfree(preg);
return(p->error);
}
/*
- regcomp - interface for parser and compilation
= extern int regcomp(regex_t *, const char *, int);
= #define REG_BASIC 0000
= #define REG_EXTENDED 0001
= #define REG_ICASE 0002
= #define REG_NOSUB 0004
= #define REG_NEWLINE 0010
= #define REG_NOSPEC 0020
= #define REG_PEND 0040
= #define REG_DUMP 0200
*/
int /* 0 success, otherwise REG_something */
regcomp(regex_t * __restrict preg,
const char * __restrict pattern,
int cflags)
{
return (regcomp_internal(preg, pattern, cflags, 0));
}
#ifndef LIBREGEX
/*
* Legacy interface that requires more lax escaping behavior.
*/
int
freebsd12_regcomp(regex_t * __restrict preg,
const char * __restrict pattern,
int cflags, int pflags)
{
return (regcomp_internal(preg, pattern, cflags, PFLAG_LEGACY_ESC));
}
__sym_compat(regcomp, freebsd12_regcomp, FBSD_1.0);
#endif /* !LIBREGEX */
/*
- p_ere_exp - parse one subERE, an atom possibly followed by a repetition op,
- return whether we should terminate or not
== static bool p_ere_exp(struct parse *p);
*/
static bool
p_ere_exp(struct parse *p, struct branchc *bc)
{
char c;
wint_t wc;
sopno pos;
int count;
int count2;
#ifdef LIBREGEX
int i;
int handled;
#endif
sopno subno;
int wascaret = 0;
(void)bc;
assert(MORE()); /* caller should have ensured this */
c = GETNEXT();
#ifdef LIBREGEX
handled = 0;
#endif
pos = HERE();
switch (c) {
case '(':
(void)REQUIRE(MORE(), REG_EPAREN);
p->g->nsub++;
subno = p->g->nsub;
if (subno < NPAREN)
p->pbegin[subno] = HERE();
EMIT(OLPAREN, subno);
if (!SEE(')'))
p_re(p, ')', IGN);
if (subno < NPAREN) {
p->pend[subno] = HERE();
assert(p->pend[subno] != 0);
}
EMIT(ORPAREN, subno);
(void)MUSTEAT(')', REG_EPAREN);
break;
#ifndef POSIX_MISTAKE
case ')': /* happens only if no current unmatched ( */
/*
* You may ask, why the ifndef? Because I didn't notice
* this until slightly too late for 1003.2, and none of the
* other 1003.2 regular-expression reviewers noticed it at
* all. So an unmatched ) is legal POSIX, at least until
* we can get it fixed.
*/
SETERROR(REG_EPAREN);
break;
#endif
case '^':
EMIT(OBOL, 0);
p->g->iflags |= USEBOL;
p->g->nbol++;
wascaret = 1;
break;
case '$':
EMIT(OEOL, 0);
p->g->iflags |= USEEOL;
p->g->neol++;
break;
case '|':
SETERROR(REG_EMPTY);
break;
case '*':
case '+':
case '?':
case '{':
SETERROR(REG_BADRPT);
break;
case '.':
if (p->g->cflags&REG_NEWLINE)
nonnewline(p);
else
EMIT(OANY, 0);
break;
case '[':
p_bracket(p);
break;
case '\\':
(void)REQUIRE(MORE(), REG_EESCAPE);
wc = WGETNEXT();
#ifdef LIBREGEX
if (p->gnuext) {
handled = 1;
switch (wc) {
case '`':
EMIT(OBOS, 0);
break;
case '\'':
EMIT(OEOS, 0);
break;
case 'B':
EMIT(ONWBND, 0);
break;
case 'b':
EMIT(OWBND, 0);
break;
case 'W':
case 'w':
case 'S':
case 's':
p_b_pseudoclass(p, wc);
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
i = wc - '0';
assert(i < NPAREN);
if (p->pend[i] != 0) {
assert(i <= p->g->nsub);
EMIT(OBACK_, i);
assert(p->pbegin[i] != 0);
assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
assert(OP(p->strip[p->pend[i]]) == ORPAREN);
(void) dupl(p, p->pbegin[i]+1, p->pend[i]);
EMIT(O_BACK, i);
} else
SETERROR(REG_ESUBREG);
p->g->backrefs = 1;
break;
default:
handled = 0;
}
/* Don't proceed to the POSIX bits if we've already handled it */
if (handled)
break;
}
#endif
switch (wc) {
case '<':
EMIT(OBOW, 0);
break;
case '>':
EMIT(OEOW, 0);
break;
default:
if (may_escape(p, wc))
ordinary(p, wc);
else
SETERROR(REG_EESCAPE);
break;
}
break;
default:
if (p->error != 0)
return (false);
p->next--;
wc = WGETNEXT();
ordinary(p, wc);
break;
}
if (!MORE())
return (false);
c = PEEK();
/* we call { a repetition if followed by a digit */
if (!( c == '*' || c == '+' || c == '?' || c == '{'))
return (false); /* no repetition, we're done */
else if (c == '{')
(void)REQUIRE(MORE2() && \
(isdigit((uch)PEEK2()) || PEEK2() == ','), REG_BADRPT);
NEXT();
(void)REQUIRE(!wascaret, REG_BADRPT);
switch (c) {
case '*': /* implemented as +? */
/* this case does not require the (y|) trick, noKLUDGE */
INSERT(OPLUS_, pos);
ASTERN(O_PLUS, pos);
INSERT(OQUEST_, pos);
ASTERN(O_QUEST, pos);
break;
case '+':
INSERT(OPLUS_, pos);
ASTERN(O_PLUS, pos);
break;
case '?':
/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
INSERT(OCH_, pos); /* offset slightly wrong */
ASTERN(OOR1, pos); /* this one's right */
AHEAD(pos); /* fix the OCH_ */
EMIT(OOR2, 0); /* offset very wrong... */
AHEAD(THERE()); /* ...so fix it */
ASTERN(O_CH, THERETHERE());
break;
case '{':
count = p_count(p);
if (EAT(',')) {
if (isdigit((uch)PEEK())) {
count2 = p_count(p);
(void)REQUIRE(count <= count2, REG_BADBR);
} else /* single number with comma */
count2 = INFINITY;
} else /* just a single number */
count2 = count;
repeat(p, pos, count, count2);
if (!EAT('}')) { /* error heuristics */
while (MORE() && PEEK() != '}')
NEXT();
(void)REQUIRE(MORE(), REG_EBRACE);
SETERROR(REG_BADBR);
}
break;
}
if (!MORE())
return (false);
c = PEEK();
if (!( c == '*' || c == '+' || c == '?' ||
(c == '{' && MORE2() && isdigit((uch)PEEK2())) ) )
return (false);
SETERROR(REG_BADRPT);
return (false);
}
/*
- p_str - string (no metacharacters) "parser"
== static void p_str(struct parse *p);
*/
static void
p_str(struct parse *p)
{
(void)REQUIRE(MORE(), REG_EMPTY);
while (MORE())
ordinary(p, WGETNEXT());
}
/*
* Eat consecutive branch delimiters for the kind of expression that we are
* parsing, return the number of delimiters that we ate.
*/
static int
p_branch_eat_delim(struct parse *p, struct branchc *bc)
{
int nskip;
(void)bc;
nskip = 0;
while (EATSPEC('|'))
++nskip;
return (nskip);
}
/*
* Insert necessary branch book-keeping operations. This emits a
* bogus 'next' offset, since we still have more to parse
*/
static void
p_branch_ins_offset(struct parse *p, struct branchc *bc)
{
if (bc->nbranch == 0) {
INSERT(OCH_, bc->start); /* offset is wrong */
bc->fwd = bc->start;
bc->back = bc->start;
}
ASTERN(OOR1, bc->back);
bc->back = THERE();
AHEAD(bc->fwd); /* fix previous offset */
bc->fwd = HERE();
EMIT(OOR2, 0); /* offset is very wrong */
++bc->nbranch;
}
/*
* Fix the offset of the tail branch, if we actually had any branches.
* This is to correct the bogus placeholder offset that we use.
*/
static void
p_branch_fix_tail(struct parse *p, struct branchc *bc)
{
/* Fix bogus offset at the tail if we actually have branches */
if (bc->nbranch > 0) {
AHEAD(bc->fwd);
ASTERN(O_CH, bc->back);
}
}
/*
* Signal to the parser that an empty branch has been encountered; this will,
* in the future, be used to allow for more permissive behavior with empty
* branches. The return value should indicate whether parsing may continue
* or not.
*/
static bool
p_branch_empty(struct parse *p, struct branchc *bc)
{
(void)bc;
SETERROR(REG_EMPTY);
return (false);
}
/*
* Take care of any branching requirements. This includes inserting the
* appropriate branching instructions as well as eating all of the branch
* delimiters until we either run out of pattern or need to parse more pattern.
*/
static bool
p_branch_do(struct parse *p, struct branchc *bc)
{
int ate = 0;
ate = p_branch_eat_delim(p, bc);
if (ate == 0)
return (false);
else if ((ate > 1 || (bc->outer && !MORE())) && !p_branch_empty(p, bc))
/*
* Halt parsing only if we have an empty branch and p_branch_empty
* indicates that we must not continue. In the future, this will not
* necessarily be an error.
*/
return (false);
p_branch_ins_offset(p, bc);
return (true);
}
static void
p_bre_pre_parse(struct parse *p, struct branchc *bc)
{
(void) bc;
/*
* Does not move cleanly into expression parser because of
* ordinary interpration of * at the beginning position of
* an expression.
*/
if (EAT('^')) {
EMIT(OBOL, 0);
p->g->iflags |= USEBOL;
p->g->nbol++;
}
}
static void
p_bre_post_parse(struct parse *p, struct branchc *bc)
{
/* Expression is terminating due to EOL token */
if (bc->terminate) {
DROP(1);
EMIT(OEOL, 0);
p->g->iflags |= USEEOL;
p->g->neol++;
}
}
/*
- p_re - Top level parser, concatenation and BRE anchoring
== static void p_re(struct parse *p, int end1, int end2);
* Giving end1 as OUT essentially eliminates the end1/end2 check.
*
* This implementation is a bit of a kludge, in that a trailing $ is first
* taken as an ordinary character and then revised to be an anchor.
* The amount of lookahead needed to avoid this kludge is excessive.
*/
static void
p_re(struct parse *p,
int end1, /* first terminating character */
int end2) /* second terminating character; ignored for EREs */
{
struct branchc bc;
bc.nbranch = 0;
if (end1 == OUT && end2 == OUT)
bc.outer = true;
else
bc.outer = false;
#define SEEEND() (!p->bre ? SEE(end1) : SEETWO(end1, end2))
for (;;) {
bc.start = HERE();
bc.nchain = 0;
bc.terminate = false;
if (p->pre_parse != NULL)
p->pre_parse(p, &bc);
while (MORE() && (!p->allowbranch || !SEESPEC('|')) && !SEEEND()) {
bc.terminate = p->parse_expr(p, &bc);
++bc.nchain;
}
if (p->post_parse != NULL)
p->post_parse(p, &bc);
(void) REQUIRE(p->gnuext || HERE() != bc.start, REG_EMPTY);
#ifdef LIBREGEX
if (HERE() == bc.start && !p_branch_empty(p, &bc))
break;
#endif
if (!p->allowbranch)
break;
/*
* p_branch_do's return value indicates whether we should
* continue parsing or not. This is both for correctness and
* a slight optimization, because it will check if we've
* encountered an empty branch or the end of the string
* immediately following a branch delimiter.
*/
if (!p_branch_do(p, &bc))
break;
}
#undef SEE_END
if (p->allowbranch)
p_branch_fix_tail(p, &bc);
assert(!MORE() || SEE(end1));
}
/*
- p_simp_re - parse a simple RE, an atom possibly followed by a repetition
== static bool p_simp_re(struct parse *p, struct branchc *bc);
*/
static bool /* was the simple RE an unbackslashed $? */
p_simp_re(struct parse *p, struct branchc *bc)
{
int c;
int cc; /* convenient/control character */
int count;
int count2;
sopno pos;
bool handled;
int i;
wint_t wc;
sopno subno;
# define BACKSL (1<<CHAR_BIT)
pos = HERE(); /* repetition op, if any, covers from here */
handled = false;
assert(MORE()); /* caller should have ensured this */
c = (uch)GETNEXT();
if (c == '\\') {
(void)REQUIRE(MORE(), REG_EESCAPE);
cc = (uch)GETNEXT();
c = BACKSL | cc;
#ifdef LIBREGEX
if (p->gnuext) {
handled = true;
switch (c) {
case BACKSL|'`':
EMIT(OBOS, 0);
break;
case BACKSL|'\'':
EMIT(OEOS, 0);
break;
case BACKSL|'B':
EMIT(ONWBND, 0);
break;
case BACKSL|'b':
EMIT(OWBND, 0);
break;
case BACKSL|'W':
case BACKSL|'w':
case BACKSL|'S':
case BACKSL|'s':
p_b_pseudoclass(p, cc);
break;
default:
handled = false;
}
}
#endif
}
if (!handled) {
switch (c) {
case '.':
if (p->g->cflags&REG_NEWLINE)
nonnewline(p);
else
EMIT(OANY, 0);
break;
case '[':
p_bracket(p);
break;
case BACKSL|'<':
EMIT(OBOW, 0);
break;
case BACKSL|'>':
EMIT(OEOW, 0);
break;
case BACKSL|'{':
SETERROR(REG_BADRPT);
break;
case BACKSL|'(':
p->g->nsub++;
subno = p->g->nsub;
if (subno < NPAREN)
p->pbegin[subno] = HERE();
EMIT(OLPAREN, subno);
/* the MORE here is an error heuristic */
if (MORE() && !SEETWO('\\', ')'))
p_re(p, '\\', ')');
if (subno < NPAREN) {
p->pend[subno] = HERE();
assert(p->pend[subno] != 0);
}
EMIT(ORPAREN, subno);
(void)REQUIRE(EATTWO('\\', ')'), REG_EPAREN);
break;
case BACKSL|')': /* should not get here -- must be user */
SETERROR(REG_EPAREN);
break;
case BACKSL|'1':
case BACKSL|'2':
case BACKSL|'3':
case BACKSL|'4':
case BACKSL|'5':
case BACKSL|'6':
case BACKSL|'7':
case BACKSL|'8':
case BACKSL|'9':
i = (c&~BACKSL) - '0';
assert(i < NPAREN);
if (p->pend[i] != 0) {
assert(i <= p->g->nsub);
EMIT(OBACK_, i);
assert(p->pbegin[i] != 0);
assert(OP(p->strip[p->pbegin[i]]) == OLPAREN);
assert(OP(p->strip[p->pend[i]]) == ORPAREN);
(void) dupl(p, p->pbegin[i]+1, p->pend[i]);
EMIT(O_BACK, i);
} else
SETERROR(REG_ESUBREG);
p->g->backrefs = 1;
break;
case '*':
/*
* Ordinary if used as the first character beyond BOL anchor of
* a (sub-)expression, counts as a bad repetition operator if it
* appears otherwise.
*/
(void)REQUIRE(bc->nchain == 0, REG_BADRPT);
/* FALLTHROUGH */
default:
if (p->error != 0)
return (false); /* Definitely not $... */
p->next--;
wc = WGETNEXT();
if ((c & BACKSL) == 0 || may_escape(p, wc))
ordinary(p, wc);
else
SETERROR(REG_EESCAPE);
break;
}
}
if (EAT('*')) { /* implemented as +? */
/* this case does not require the (y|) trick, noKLUDGE */
INSERT(OPLUS_, pos);
ASTERN(O_PLUS, pos);
INSERT(OQUEST_, pos);
ASTERN(O_QUEST, pos);
#ifdef LIBREGEX
} else if (p->gnuext && EATTWO('\\', '?')) {
INSERT(OQUEST_, pos);
ASTERN(O_QUEST, pos);
} else if (p->gnuext && EATTWO('\\', '+')) {
INSERT(OPLUS_, pos);
ASTERN(O_PLUS, pos);
#endif
} else if (EATTWO('\\', '{')) {
count = p_count(p);
if (EAT(',')) {
if (MORE() && isdigit((uch)PEEK())) {
count2 = p_count(p);
(void)REQUIRE(count <= count2, REG_BADBR);
} else /* single number with comma */
count2 = INFINITY;
} else /* just a single number */
count2 = count;
repeat(p, pos, count, count2);
if (!EATTWO('\\', '}')) { /* error heuristics */
while (MORE() && !SEETWO('\\', '}'))
NEXT();
(void)REQUIRE(MORE(), REG_EBRACE);
SETERROR(REG_BADBR);
}
} else if (c == '$') /* $ (but not \$) ends it */
return (true);
return (false);
}
/*
- p_count - parse a repetition count
== static int p_count(struct parse *p);
*/
static int /* the value */
p_count(struct parse *p)
{
int count = 0;
int ndigits = 0;
while (MORE() && isdigit((uch)PEEK()) && count <= DUPMAX) {
count = count*10 + ((uch)GETNEXT() - '0');
ndigits++;
}
(void)REQUIRE(ndigits > 0 && count <= DUPMAX, REG_BADBR);
return(count);
}
/*
- p_bracket - parse a bracketed character list
== static void p_bracket(struct parse *p);
*/
static void
p_bracket(struct parse *p)
{
cset *cs;
wint_t ch;
/* Dept of Truly Sickening Special-Case Kludges */
if (p->end - p->next > 5) {
if (strncmp(p->next, "[:<:]]", 6) == 0) {
EMIT(OBOW, 0);
NEXTn(6);
return;
}
if (strncmp(p->next, "[:>:]]", 6) == 0) {
EMIT(OEOW, 0);
NEXTn(6);
return;
}
}
if ((cs = allocset(p)) == NULL)
return;
if (p->g->cflags&REG_ICASE)
cs->icase = 1;
if (EAT('^'))
cs->invert = 1;
if (EAT(']'))
CHadd(p, cs, ']');
else if (EAT('-'))
CHadd(p, cs, '-');
while (MORE() && PEEK() != ']' && !SEETWO('-', ']'))
p_b_term(p, cs);
if (EAT('-'))
CHadd(p, cs, '-');
(void)MUSTEAT(']', REG_EBRACK);
if (p->error != 0) /* don't mess things up further */
return;
if (cs->invert && p->g->cflags&REG_NEWLINE)
cs->bmp['\n' >> 3] |= 1 << ('\n' & 7);
if ((ch = singleton(cs)) != OUT) { /* optimize singleton sets */
ordinary(p, ch);
freeset(p, cs);
} else
EMIT(OANYOF, (int)(cs - p->g->sets));
}
static int
p_range_cmp(wchar_t c1, wchar_t c2)
{
#ifndef LIBREGEX
return __wcollate_range_cmp(c1, c2);
#else
/* Copied from libc/collate __wcollate_range_cmp */
wchar_t s1[2], s2[2];
s1[0] = c1;
s1[1] = L'\0';
s2[0] = c2;
s2[1] = L'\0';
return (wcscoll(s1, s2));
#endif
}
/*
- p_b_term - parse one term of a bracketed character list
== static void p_b_term(struct parse *p, cset *cs);
*/
static void
p_b_term(struct parse *p, cset *cs)
{
char c;
wint_t start, finish;
wint_t i;
#ifndef LIBREGEX
struct xlocale_collate *table =
(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
#endif
/* classify what we've got */
switch ((MORE()) ? PEEK() : '\0') {
case '[':
c = (MORE2()) ? PEEK2() : '\0';
break;
case '-':
SETERROR(REG_ERANGE);
return; /* NOTE RETURN */
default:
c = '\0';
break;
}
switch (c) {
case ':': /* character class */
NEXT2();
(void)REQUIRE(MORE(), REG_EBRACK);
c = PEEK();
(void)REQUIRE(c != '-' && c != ']', REG_ECTYPE);
p_b_cclass(p, cs);
(void)REQUIRE(MORE(), REG_EBRACK);
(void)REQUIRE(EATTWO(':', ']'), REG_ECTYPE);
break;
case '=': /* equivalence class */
NEXT2();
(void)REQUIRE(MORE(), REG_EBRACK);
c = PEEK();
(void)REQUIRE(c != '-' && c != ']', REG_ECOLLATE);
p_b_eclass(p, cs);
(void)REQUIRE(MORE(), REG_EBRACK);
(void)REQUIRE(EATTWO('=', ']'), REG_ECOLLATE);
break;
default: /* symbol, ordinary character, or range */
start = p_b_symbol(p);
if (SEE('-') && MORE2() && PEEK2() != ']') {
/* range */
NEXT();
if (EAT('-'))
finish = '-';
else
finish = p_b_symbol(p);
} else
finish = start;
if (start == finish)
CHadd(p, cs, start);
else {
#ifndef LIBREGEX
if (table->__collate_load_error || MB_CUR_MAX > 1) {
#else
if (MB_CUR_MAX > 1) {
#endif
(void)REQUIRE(start <= finish, REG_ERANGE);
CHaddrange(p, cs, start, finish);
} else {
(void)REQUIRE(p_range_cmp(start, finish) <= 0, REG_ERANGE);
for (i = 0; i <= UCHAR_MAX; i++) {
if (p_range_cmp(start, i) <= 0 &&
p_range_cmp(i, finish) <= 0 )
CHadd(p, cs, i);
}
}
}
break;
}
}
/*
- p_b_pseudoclass - parse a pseudo-class (\w, \W, \s, \S)
== static int p_b_pseudoclass(struct parse *p, char c)
*/
static int
p_b_pseudoclass(struct parse *p, char c) {
cset *cs;
if ((cs = allocset(p)) == NULL)
return(0);
if (p->g->cflags&REG_ICASE)
cs->icase = 1;
switch (c) {
case 'W':
cs->invert = 1;
/* PASSTHROUGH */
case 'w':
p_b_cclass_named(p, cs, "alnum");
break;
case 'S':
cs->invert = 1;
/* PASSTHROUGH */
case 's':
p_b_cclass_named(p, cs, "space");
break;
default:
return(0);
}
EMIT(OANYOF, (int)(cs - p->g->sets));
return(1);
}
/*
- p_b_cclass - parse a character-class name and deal with it
== static void p_b_cclass(struct parse *p, cset *cs);
*/
static void
p_b_cclass(struct parse *p, cset *cs)
{
const char *sp = p->next;
size_t len;
char clname[16];
while (MORE() && isalpha((uch)PEEK()))
NEXT();
len = p->next - sp;
if (len >= sizeof(clname) - 1) {
SETERROR(REG_ECTYPE);
return;
}
memcpy(clname, sp, len);
clname[len] = '\0';
p_b_cclass_named(p, cs, clname);
}
/*
- p_b_cclass_named - deal with a named character class
== static void p_b_cclass_named(struct parse *p, cset *cs, const char []);
*/
static void
p_b_cclass_named(struct parse *p, cset *cs, const char clname[]) {
wctype_t wct;
if ((wct = wctype(clname)) == 0) {
SETERROR(REG_ECTYPE);
return;
}
CHaddtype(p, cs, wct);
}
/*
- p_b_eclass - parse an equivalence-class name and deal with it
== static void p_b_eclass(struct parse *p, cset *cs);
*
* This implementation is incomplete. xxx
*/
static void
p_b_eclass(struct parse *p, cset *cs)
{
wint_t c;
c = p_b_coll_elem(p, '=');
CHadd(p, cs, c);
}
/*
- p_b_symbol - parse a character or [..]ed multicharacter collating symbol
== static wint_t p_b_symbol(struct parse *p);
*/
static wint_t /* value of symbol */
p_b_symbol(struct parse *p)
{
wint_t value;
(void)REQUIRE(MORE(), REG_EBRACK);
if (!EATTWO('[', '.'))
return(WGETNEXT());
/* collating symbol */
value = p_b_coll_elem(p, '.');
(void)REQUIRE(EATTWO('.', ']'), REG_ECOLLATE);
return(value);
}
/*
- p_b_coll_elem - parse a collating-element name and look it up
== static wint_t p_b_coll_elem(struct parse *p, wint_t endc);
*/
static wint_t /* value of collating element */
p_b_coll_elem(struct parse *p,
wint_t endc) /* name ended by endc,']' */
{
const char *sp = p->next;
struct cname *cp;
mbstate_t mbs;
wchar_t wc;
size_t clen, len;
while (MORE() && !SEETWO(endc, ']'))
NEXT();
if (!MORE()) {
SETERROR(REG_EBRACK);
return(0);
}
len = p->next - sp;
for (cp = cnames; cp->name != NULL; cp++)
if (strncmp(cp->name, sp, len) == 0 && strlen(cp->name) == len)
return(cp->code); /* known name */
memset(&mbs, 0, sizeof(mbs));
if ((clen = mbrtowc(&wc, sp, len, &mbs)) == len)
return (wc); /* single character */
else if (clen == (size_t)-1 || clen == (size_t)-2)
SETERROR(REG_ILLSEQ);
else
SETERROR(REG_ECOLLATE); /* neither */
return(0);
}
/*
- may_escape - determine whether 'ch' is escape-able in the current context
== static int may_escape(struct parse *p, const wint_t ch)
*/
static bool
may_escape(struct parse *p, const wint_t ch)
{
if ((p->pflags & PFLAG_LEGACY_ESC) != 0)
return (true);
if (iswalpha(ch) || ch == '\'' || ch == '`')
return (false);
return (true);
#ifdef NOTYET
/*
* Build a whitelist of characters that may be escaped to produce an
* ordinary in the current context. This assumes that these have not
* been otherwise interpreted as a special character. Escaping an
* ordinary character yields undefined results according to
* IEEE 1003.1-2008. Some extensions (notably, some GNU extensions) take
* advantage of this and use escaped ordinary characters to provide
* special meaning, e.g. \b, \B, \w, \W, \s, \S.
*/
switch(ch) {
case '|':
case '+':
case '?':
/* The above characters may not be escaped in BREs */
if (!(p->g->cflags&REG_EXTENDED))
return (false);
/* Fallthrough */
case '(':
case ')':
case '{':
case '}':
case '.':
case '[':
case ']':
case '\\':
case '*':
case '^':
case '$':
return (true);
default:
return (false);
}
#endif
}
/*
- othercase - return the case counterpart of an alphabetic
== static wint_t othercase(wint_t ch);
*/
static wint_t /* if no counterpart, return ch */
othercase(wint_t ch)
{
assert(iswalpha(ch));
if (iswupper(ch))
return(towlower(ch));
else if (iswlower(ch))
return(towupper(ch));
else /* peculiar, but could happen */
return(ch);
}
/*
- bothcases - emit a dualcase version of a two-case character
== static void bothcases(struct parse *p, wint_t ch);
*
* Boy, is this implementation ever a kludge...
*/
static void
bothcases(struct parse *p, wint_t ch)
{
const char *oldnext = p->next;
const char *oldend = p->end;
char bracket[3 + MB_LEN_MAX];
size_t n;
mbstate_t mbs;
assert(othercase(ch) != ch); /* p_bracket() would recurse */
p->next = bracket;
memset(&mbs, 0, sizeof(mbs));
n = wcrtomb(bracket, ch, &mbs);
assert(n != (size_t)-1);
bracket[n] = ']';
bracket[n + 1] = '\0';
p->end = bracket+n+1;
p_bracket(p);
assert(p->next == p->end);
p->next = oldnext;
p->end = oldend;
}
/*
- ordinary - emit an ordinary character
== static void ordinary(struct parse *p, wint_t ch);
*/
static void
ordinary(struct parse *p, wint_t ch)
{
cset *cs;
if ((p->g->cflags&REG_ICASE) && iswalpha(ch) && othercase(ch) != ch)
bothcases(p, ch);
else if ((ch & OPDMASK) == ch)
EMIT(OCHAR, ch);
else {
/*
* Kludge: character is too big to fit into an OCHAR operand.
* Emit a singleton set.
*/
if ((cs = allocset(p)) == NULL)
return;
CHadd(p, cs, ch);
EMIT(OANYOF, (int)(cs - p->g->sets));
}
}
/*
- nonnewline - emit REG_NEWLINE version of OANY
== static void nonnewline(struct parse *p);
*
* Boy, is this implementation ever a kludge...
*/
static void
nonnewline(struct parse *p)
{
const char *oldnext = p->next;
const char *oldend = p->end;
char bracket[4];
p->next = bracket;
p->end = bracket+3;
bracket[0] = '^';
bracket[1] = '\n';
bracket[2] = ']';
bracket[3] = '\0';
p_bracket(p);
assert(p->next == bracket+3);
p->next = oldnext;
p->end = oldend;
}
/*
- repeat - generate code for a bounded repetition, recursively if needed
== static void repeat(struct parse *p, sopno start, int from, int to);
*/
static void
repeat(struct parse *p,
sopno start, /* operand from here to end of strip */
int from, /* repeated from this number */
int to) /* to this number of times (maybe INFINITY) */
{
sopno finish = HERE();
# define N 2
# define INF 3
# define REP(f, t) ((f)*8 + (t))
# define MAP(n) (((n) <= 1) ? (n) : ((n) == INFINITY) ? INF : N)
sopno copy;
if (p->error != 0) /* head off possible runaway recursion */
return;
assert(from <= to);
switch (REP(MAP(from), MAP(to))) {
case REP(0, 0): /* must be user doing this */
DROP(finish-start); /* drop the operand */
break;
case REP(0, 1): /* as x{1,1}? */
case REP(0, N): /* as x{1,n}? */
case REP(0, INF): /* as x{1,}? */
/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
INSERT(OCH_, start); /* offset is wrong... */
repeat(p, start+1, 1, to);
ASTERN(OOR1, start);
AHEAD(start); /* ... fix it */
EMIT(OOR2, 0);
AHEAD(THERE());
ASTERN(O_CH, THERETHERE());
break;
case REP(1, 1): /* trivial case */
/* done */
break;
case REP(1, N): /* as x?x{1,n-1} */
/* KLUDGE: emit y? as (y|) until subtle bug gets fixed */
INSERT(OCH_, start);
ASTERN(OOR1, start);
AHEAD(start);
EMIT(OOR2, 0); /* offset very wrong... */
AHEAD(THERE()); /* ...so fix it */
ASTERN(O_CH, THERETHERE());
copy = dupl(p, start+1, finish+1);
assert(copy == finish+4);
repeat(p, copy, 1, to-1);
break;
case REP(1, INF): /* as x+ */
INSERT(OPLUS_, start);
ASTERN(O_PLUS, start);
break;
case REP(N, N): /* as xx{m-1,n-1} */
copy = dupl(p, start, finish);
repeat(p, copy, from-1, to-1);
break;
case REP(N, INF): /* as xx{n-1,INF} */
copy = dupl(p, start, finish);
repeat(p, copy, from-1, to);
break;
default: /* "can't happen" */
SETERROR(REG_ASSERT); /* just in case */
break;
}
}
/*
- wgetnext - helper function for WGETNEXT() macro. Gets the next wide
- character from the parse struct, signals a REG_ILLSEQ error if the
- character can't be converted. Returns the number of bytes consumed.
*/
static wint_t
wgetnext(struct parse *p)
{
mbstate_t mbs;
wchar_t wc;
size_t n;
memset(&mbs, 0, sizeof(mbs));
n = mbrtowc(&wc, p->next, p->end - p->next, &mbs);
if (n == (size_t)-1 || n == (size_t)-2) {
SETERROR(REG_ILLSEQ);
return (0);
}
if (n == 0)
n = 1;
p->next += n;
return (wc);
}
/*
- seterr - set an error condition
== static int seterr(struct parse *p, int e);
*/
static int /* useless but makes type checking happy */
seterr(struct parse *p, int e)
{
if (p->error == 0) /* keep earliest error condition */
p->error = e;
p->next = nuls; /* try to bring things to a halt */
p->end = nuls;
return(0); /* make the return value well-defined */
}
/*
- allocset - allocate a set of characters for []
== static cset *allocset(struct parse *p);
*/
static cset *
allocset(struct parse *p)
{
cset *cs, *ncs;
ncs = reallocarray(p->g->sets, p->g->ncsets + 1, sizeof(*ncs));
if (ncs == NULL) {
SETERROR(REG_ESPACE);
return (NULL);
}
p->g->sets = ncs;
cs = &p->g->sets[p->g->ncsets++];
memset(cs, 0, sizeof(*cs));
return(cs);
}
/*
- freeset - free a now-unused set
== static void freeset(struct parse *p, cset *cs);
*/
static void
freeset(struct parse *p, cset *cs)
{
cset *top = &p->g->sets[p->g->ncsets];
free(cs->wides);
free(cs->ranges);
free(cs->types);
memset(cs, 0, sizeof(*cs));
if (cs == top-1) /* recover only the easy case */
p->g->ncsets--;
}
/*
- singleton - Determine whether a set contains only one character,
- returning it if so, otherwise returning OUT.
*/
static wint_t
singleton(cset *cs)
{
wint_t i, s, n;
for (i = n = 0; i < NC; i++)
if (CHIN(cs, i)) {
n++;
s = i;
}
if (n == 1)
return (s);
if (cs->nwides == 1 && cs->nranges == 0 && cs->ntypes == 0 &&
cs->icase == 0)
return (cs->wides[0]);
/* Don't bother handling the other cases. */
return (OUT);
}
/*
- CHadd - add character to character set.
*/
static void
CHadd(struct parse *p, cset *cs, wint_t ch)
{
wint_t nch, *newwides;
assert(ch >= 0);
if (ch < NC)
cs->bmp[ch >> 3] |= 1 << (ch & 7);
else {
newwides = reallocarray(cs->wides, cs->nwides + 1,
sizeof(*cs->wides));
if (newwides == NULL) {
SETERROR(REG_ESPACE);
return;
}
cs->wides = newwides;
cs->wides[cs->nwides++] = ch;
}
if (cs->icase) {
if ((nch = towlower(ch)) < NC)
cs->bmp[nch >> 3] |= 1 << (nch & 7);
if ((nch = towupper(ch)) < NC)
cs->bmp[nch >> 3] |= 1 << (nch & 7);
}
}
/*
- CHaddrange - add all characters in the range [min,max] to a character set.
*/
static void
CHaddrange(struct parse *p, cset *cs, wint_t min, wint_t max)
{
crange *newranges;
for (; min < NC && min <= max; min++)
CHadd(p, cs, min);
if (min >= max)
return;
newranges = reallocarray(cs->ranges, cs->nranges + 1,
sizeof(*cs->ranges));
if (newranges == NULL) {
SETERROR(REG_ESPACE);
return;
}
cs->ranges = newranges;
cs->ranges[cs->nranges].min = min;
cs->ranges[cs->nranges].max = max;
cs->nranges++;
}
/*
- CHaddtype - add all characters of a certain type to a character set.
*/
static void
CHaddtype(struct parse *p, cset *cs, wctype_t wct)
{
wint_t i;
wctype_t *newtypes;
for (i = 0; i < NC; i++)
if (iswctype(i, wct))
CHadd(p, cs, i);
newtypes = reallocarray(cs->types, cs->ntypes + 1,
sizeof(*cs->types));
if (newtypes == NULL) {
SETERROR(REG_ESPACE);
return;
}
cs->types = newtypes;
cs->types[cs->ntypes++] = wct;
}
/*
- dupl - emit a duplicate of a bunch of sops
== static sopno dupl(struct parse *p, sopno start, sopno finish);
*/
static sopno /* start of duplicate */
dupl(struct parse *p,
sopno start, /* from here */
sopno finish) /* to this less one */
{
sopno ret = HERE();
sopno len = finish - start;
assert(finish >= start);
if (len == 0)
return(ret);
if (!enlarge(p, p->ssize + len)) /* this many unexpected additions */
return(ret);
(void) memcpy((char *)(p->strip + p->slen),
(char *)(p->strip + start), (size_t)len*sizeof(sop));
p->slen += len;
return(ret);
}
/*
- doemit - emit a strip operator
== static void doemit(struct parse *p, sop op, size_t opnd);
*
* It might seem better to implement this as a macro with a function as
* hard-case backup, but it's just too big and messy unless there are
* some changes to the data structures. Maybe later.
*/
static void
doemit(struct parse *p, sop op, size_t opnd)
{
/* avoid making error situations worse */
if (p->error != 0)
return;
/* deal with oversize operands ("can't happen", more or less) */
assert(opnd < 1<<OPSHIFT);
/* deal with undersized strip */
if (p->slen >= p->ssize)
if (!enlarge(p, (p->ssize+1) / 2 * 3)) /* +50% */
return;
/* finally, it's all reduced to the easy case */
p->strip[p->slen++] = SOP(op, opnd);
}
/*
- doinsert - insert a sop into the strip
== static void doinsert(struct parse *p, sop op, size_t opnd, sopno pos);
*/
static void
doinsert(struct parse *p, sop op, size_t opnd, sopno pos)
{
sopno sn;
sop s;
int i;
/* avoid making error situations worse */
if (p->error != 0)
return;
sn = HERE();
EMIT(op, opnd); /* do checks, ensure space */
assert(HERE() == sn+1);
s = p->strip[sn];
/* adjust paren pointers */
assert(pos > 0);
for (i = 1; i < NPAREN; i++) {
if (p->pbegin[i] >= pos) {
p->pbegin[i]++;
}
if (p->pend[i] >= pos) {
p->pend[i]++;
}
}
memmove((char *)&p->strip[pos+1], (char *)&p->strip[pos],
(HERE()-pos-1)*sizeof(sop));
p->strip[pos] = s;
}
/*
- dofwd - complete a forward reference
== static void dofwd(struct parse *p, sopno pos, sop value);
*/
static void
dofwd(struct parse *p, sopno pos, sop value)
{
/* avoid making error situations worse */
if (p->error != 0)
return;
assert(value < 1<<OPSHIFT);
p->strip[pos] = OP(p->strip[pos]) | value;
}
/*
- enlarge - enlarge the strip
== static int enlarge(struct parse *p, sopno size);
*/
static int
enlarge(struct parse *p, sopno size)
{
sop *sp;
if (p->ssize >= size)
return 1;
sp = reallocarray(p->strip, size, sizeof(sop));
if (sp == NULL) {
SETERROR(REG_ESPACE);
return 0;
}
p->strip = sp;
p->ssize = size;
return 1;
}
/*
- stripsnug - compact the strip
== static void stripsnug(struct parse *p, struct re_guts *g);
*/
static void
stripsnug(struct parse *p, struct re_guts *g)
{
g->nstates = p->slen;
g->strip = reallocarray((char *)p->strip, p->slen, sizeof(sop));
if (g->strip == NULL) {
SETERROR(REG_ESPACE);
g->strip = p->strip;
}
}
/*
- findmust - fill in must and mlen with longest mandatory literal string
== static void findmust(struct parse *p, struct re_guts *g);
*
* This algorithm could do fancy things like analyzing the operands of |
* for common subsequences. Someday. This code is simple and finds most
* of the interesting cases.
*
* Note that must and mlen got initialized during setup.
*/
static void
findmust(struct parse *p, struct re_guts *g)
{
sop *scan;
sop *start = NULL;
sop *newstart = NULL;
sopno newlen;
sop s;
char *cp;
int offset;
char buf[MB_LEN_MAX];
size_t clen;
mbstate_t mbs;
/* avoid making error situations worse */
if (p->error != 0)
return;
/*
* It's not generally safe to do a ``char'' substring search on
* multibyte character strings, but it's safe for at least
* UTF-8 (see RFC 3629).
*/
if (MB_CUR_MAX > 1 &&
strcmp(_CurrentRuneLocale->__encoding, "UTF-8") != 0)
return;
/* find the longest OCHAR sequence in strip */
newlen = 0;
offset = 0;
g->moffset = 0;
scan = g->strip + 1;
do {
s = *scan++;
switch (OP(s)) {
case OCHAR: /* sequence member */
if (newlen == 0) { /* new sequence */
memset(&mbs, 0, sizeof(mbs));
newstart = scan - 1;
}
clen = wcrtomb(buf, OPND(s), &mbs);
if (clen == (size_t)-1)
goto toohard;
newlen += clen;
break;
case OPLUS_: /* things that don't break one */
case OLPAREN:
case ORPAREN:
break;
case OQUEST_: /* things that must be skipped */
case OCH_:
offset = altoffset(scan, offset);
scan--;
do {
scan += OPND(s);
s = *scan;
/* assert() interferes w debug printouts */
if (OP(s) != (sop)O_QUEST &&
OP(s) != (sop)O_CH && OP(s) != (sop)OOR2) {
g->iflags |= BAD;
return;
}
} while (OP(s) != (sop)O_QUEST && OP(s) != (sop)O_CH);
/* FALLTHROUGH */
case OBOW: /* things that break a sequence */
case OEOW:
case OBOL:
case OEOL:
case OBOS:
case OEOS:
case OWBND:
case ONWBND:
case O_QUEST:
case O_CH:
case OEND:
if (newlen > (sopno)g->mlen) { /* ends one */
start = newstart;
g->mlen = newlen;
if (offset > -1) {
g->moffset += offset;
offset = newlen;
} else
g->moffset = offset;
} else {
if (offset > -1)
offset += newlen;
}
newlen = 0;
break;
case OANY:
if (newlen > (sopno)g->mlen) { /* ends one */
start = newstart;
g->mlen = newlen;
if (offset > -1) {
g->moffset += offset;
offset = newlen;
} else
g->moffset = offset;
} else {
if (offset > -1)
offset += newlen;
}
if (offset > -1)
offset++;
newlen = 0;
break;
case OANYOF: /* may or may not invalidate offset */
/* First, everything as OANY */
if (newlen > (sopno)g->mlen) { /* ends one */
start = newstart;
g->mlen = newlen;
if (offset > -1) {
g->moffset += offset;
offset = newlen;
} else
g->moffset = offset;
} else {
if (offset > -1)
offset += newlen;
}
if (offset > -1)
offset++;
newlen = 0;
break;
toohard:
default:
/* Anything here makes it impossible or too hard
* to calculate the offset -- so we give up;
* save the last known good offset, in case the
* must sequence doesn't occur later.
*/
if (newlen > (sopno)g->mlen) { /* ends one */
start = newstart;
g->mlen = newlen;
if (offset > -1)
g->moffset += offset;
else
g->moffset = offset;
}
offset = -1;
newlen = 0;
break;
}
} while (OP(s) != OEND);
if (g->mlen == 0) { /* there isn't one */
g->moffset = -1;
return;
}
/* turn it into a character string */
g->must = malloc((size_t)g->mlen + 1);
if (g->must == NULL) { /* argh; just forget it */
g->mlen = 0;
g->moffset = -1;
return;
}
cp = g->must;
scan = start;
memset(&mbs, 0, sizeof(mbs));
while (cp < g->must + g->mlen) {
while (OP(s = *scan++) != OCHAR)
continue;
clen = wcrtomb(cp, OPND(s), &mbs);
assert(clen != (size_t)-1);
cp += clen;
}
assert(cp == g->must + g->mlen);
*cp++ = '\0'; /* just on general principles */
}
/*
- altoffset - choose biggest offset among multiple choices
== static int altoffset(sop *scan, int offset);
*
* Compute, recursively if necessary, the largest offset among multiple
* re paths.
*/
static int
altoffset(sop *scan, int offset)
{
int largest;
int try;
sop s;
/* If we gave up already on offsets, return */
if (offset == -1)
return -1;
largest = 0;
try = 0;
s = *scan++;
while (OP(s) != (sop)O_QUEST && OP(s) != (sop)O_CH) {
switch (OP(s)) {
case OOR1:
if (try > largest)
largest = try;
try = 0;
break;
case OQUEST_:
case OCH_:
try = altoffset(scan, try);
if (try == -1)
return -1;
scan--;
do {
scan += OPND(s);
s = *scan;
if (OP(s) != (sop)O_QUEST &&
OP(s) != (sop)O_CH && OP(s) != (sop)OOR2)
return -1;
} while (OP(s) != (sop)O_QUEST && OP(s) != (sop)O_CH);
/* We must skip to the next position, or we'll
* leave altoffset() too early.
*/
scan++;
break;
case OANYOF:
case OCHAR:
case OANY:
try++;
case OBOW:
case OEOW:
case OWBND:
case ONWBND:
case OLPAREN:
case ORPAREN:
case OOR2:
break;
default:
try = -1;
break;
}
if (try == -1)
return -1;
s = *scan++;
}
if (try > largest)
largest = try;
return largest+offset;
}
/*
- computejumps - compute char jumps for BM scan
== static void computejumps(struct parse *p, struct re_guts *g);
*
* This algorithm assumes g->must exists and is has size greater than
* zero. It's based on the algorithm found on Computer Algorithms by
* Sara Baase.
*
* A char jump is the number of characters one needs to jump based on
* the value of the character from the text that was mismatched.
*/
static void
computejumps(struct parse *p, struct re_guts *g)
{
int ch;
int mindex;
/* Avoid making errors worse */
if (p->error != 0)
return;
g->charjump = (int *)malloc((NC_MAX + 1) * sizeof(int));
if (g->charjump == NULL) /* Not a fatal error */
return;
/* Adjust for signed chars, if necessary */
g->charjump = &g->charjump[-(CHAR_MIN)];
/* If the character does not exist in the pattern, the jump
* is equal to the number of characters in the pattern.
*/
for (ch = CHAR_MIN; ch < (CHAR_MAX + 1); ch++)
g->charjump[ch] = g->mlen;
/* If the character does exist, compute the jump that would
* take us to the last character in the pattern equal to it
* (notice that we match right to left, so that last character
* is the first one that would be matched).
*/
for (mindex = 0; mindex < g->mlen; mindex++)
g->charjump[(int)g->must[mindex]] = g->mlen - mindex - 1;
}
/*
- computematchjumps - compute match jumps for BM scan
== static void computematchjumps(struct parse *p, struct re_guts *g);
*
* This algorithm assumes g->must exists and is has size greater than
* zero. It's based on the algorithm found on Computer Algorithms by
* Sara Baase.
*
* A match jump is the number of characters one needs to advance based
* on the already-matched suffix.
* Notice that all values here are minus (g->mlen-1), because of the way
* the search algorithm works.
*/
static void
computematchjumps(struct parse *p, struct re_guts *g)
{
int mindex; /* General "must" iterator */
int suffix; /* Keeps track of matching suffix */
int ssuffix; /* Keeps track of suffixes' suffix */
int* pmatches; /* pmatches[k] points to the next i
* such that i+1...mlen is a substring
* of k+1...k+mlen-i-1
*/
/* Avoid making errors worse */
if (p->error != 0)
return;
pmatches = (int*) malloc(g->mlen * sizeof(int));
if (pmatches == NULL) {
g->matchjump = NULL;
return;
}
g->matchjump = (int*) malloc(g->mlen * sizeof(int));
if (g->matchjump == NULL) { /* Not a fatal error */
free(pmatches);
return;
}
/* Set maximum possible jump for each character in the pattern */
for (mindex = 0; mindex < g->mlen; mindex++)
g->matchjump[mindex] = 2*g->mlen - mindex - 1;
/* Compute pmatches[] */
for (mindex = g->mlen - 1, suffix = g->mlen; mindex >= 0;
mindex--, suffix--) {
pmatches[mindex] = suffix;
/* If a mismatch is found, interrupting the substring,
* compute the matchjump for that position. If no
* mismatch is found, then a text substring mismatched
* against the suffix will also mismatch against the
* substring.
*/
while (suffix < g->mlen
&& g->must[mindex] != g->must[suffix]) {
g->matchjump[suffix] = MIN(g->matchjump[suffix],
g->mlen - mindex - 1);
suffix = pmatches[suffix];
}
}
/* Compute the matchjump up to the last substring found to jump
* to the beginning of the largest must pattern prefix matching
* it's own suffix.
*/
for (mindex = 0; mindex <= suffix; mindex++)
g->matchjump[mindex] = MIN(g->matchjump[mindex],
g->mlen + suffix - mindex);
ssuffix = pmatches[suffix];
while (suffix < g->mlen) {
while (suffix <= ssuffix && suffix < g->mlen) {
g->matchjump[suffix] = MIN(g->matchjump[suffix],
g->mlen + ssuffix - suffix);
suffix++;
}
if (suffix < g->mlen)
ssuffix = pmatches[ssuffix];
}
free(pmatches);
}
/*
- pluscount - count + nesting
== static sopno pluscount(struct parse *p, struct re_guts *g);
*/
static sopno /* nesting depth */
pluscount(struct parse *p, struct re_guts *g)
{
sop *scan;
sop s;
sopno plusnest = 0;
sopno maxnest = 0;
if (p->error != 0)
return(0); /* there may not be an OEND */
scan = g->strip + 1;
do {
s = *scan++;
switch (OP(s)) {
case OPLUS_:
plusnest++;
break;
case O_PLUS:
if (plusnest > maxnest)
maxnest = plusnest;
plusnest--;
break;
}
} while (OP(s) != OEND);
if (plusnest != 0)
g->iflags |= BAD;
return(maxnest);
}
diff --git a/lib/libc/regex/regerror.c b/lib/libc/regex/regerror.c
index 7e9631796a9f..6cdb7d02b0fb 100644
--- a/lib/libc/regex/regerror.c
+++ b/lib/libc/regex/regerror.c
@@ -1,174 +1,173 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)regerror.c 8.4 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)regerror.c 8.4 (Berkeley) 3/20/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <limits.h>
#include <stdlib.h>
#include <regex.h>
#include "utils.h"
/* ========= begin header generated by ./mkh ========= */
#ifdef __cplusplus
extern "C" {
#endif
/* === regerror.c === */
static const char *regatoi(const regex_t *preg, char *localbuf);
#ifdef __cplusplus
}
#endif
/* ========= end header generated by ./mkh ========= */
/*
= #define REG_NOMATCH 1
= #define REG_BADPAT 2
= #define REG_ECOLLATE 3
= #define REG_ECTYPE 4
= #define REG_EESCAPE 5
= #define REG_ESUBREG 6
= #define REG_EBRACK 7
= #define REG_EPAREN 8
= #define REG_EBRACE 9
= #define REG_BADBR 10
= #define REG_ERANGE 11
= #define REG_ESPACE 12
= #define REG_BADRPT 13
= #define REG_EMPTY 14
= #define REG_ASSERT 15
= #define REG_INVARG 16
= #define REG_ILLSEQ 17
= #define REG_ATOI 255 // convert name to number (!)
= #define REG_ITOA 0400 // convert number to name (!)
*/
static struct rerr {
int code;
const char *name;
const char *explain;
} rerrs[] = {
{REG_NOMATCH, "REG_NOMATCH", "regexec() failed to match"},
{REG_BADPAT, "REG_BADPAT", "invalid regular expression"},
{REG_ECOLLATE, "REG_ECOLLATE", "invalid collating element"},
{REG_ECTYPE, "REG_ECTYPE", "invalid character class"},
{REG_EESCAPE, "REG_EESCAPE", "trailing backslash (\\)"},
{REG_ESUBREG, "REG_ESUBREG", "invalid backreference number"},
{REG_EBRACK, "REG_EBRACK", "brackets ([ ]) not balanced"},
{REG_EPAREN, "REG_EPAREN", "parentheses not balanced"},
{REG_EBRACE, "REG_EBRACE", "braces not balanced"},
{REG_BADBR, "REG_BADBR", "invalid repetition count(s)"},
{REG_ERANGE, "REG_ERANGE", "invalid character range"},
{REG_ESPACE, "REG_ESPACE", "out of memory"},
{REG_BADRPT, "REG_BADRPT", "repetition-operator operand invalid"},
{REG_EMPTY, "REG_EMPTY", "empty (sub)expression"},
{REG_ASSERT, "REG_ASSERT", "\"can't happen\" -- you found a bug"},
{REG_INVARG, "REG_INVARG", "invalid argument to regex routine"},
{REG_ILLSEQ, "REG_ILLSEQ", "illegal byte sequence"},
{0, "", "*** unknown regexp error code ***"}
};
/*
- regerror - the interface to error numbers
= extern size_t regerror(int, const regex_t *, char *, size_t);
*/
/* ARGSUSED */
size_t
regerror(int errcode,
const regex_t * __restrict preg,
char * __restrict errbuf,
size_t errbuf_size)
{
struct rerr *r;
size_t len;
int target = errcode &~ REG_ITOA;
const char *s;
char convbuf[50];
if (errcode == REG_ATOI)
s = regatoi(preg, convbuf);
else {
for (r = rerrs; r->code != 0; r++)
if (r->code == target)
break;
if (errcode&REG_ITOA) {
if (r->code != 0)
(void) strcpy(convbuf, r->name);
else
sprintf(convbuf, "REG_0x%x", target);
assert(strlen(convbuf) < sizeof(convbuf));
s = convbuf;
} else
s = r->explain;
}
len = strlen(s) + 1;
if (errbuf_size > 0) {
if (errbuf_size > len)
(void) strcpy(errbuf, s);
else {
(void) strncpy(errbuf, s, errbuf_size-1);
errbuf[errbuf_size-1] = '\0';
}
}
return(len);
}
/*
- regatoi - internal routine to implement REG_ATOI
== static char *regatoi(const regex_t *preg, char *localbuf);
*/
static const char *
regatoi(const regex_t *preg, char *localbuf)
{
struct rerr *r;
for (r = rerrs; r->code != 0; r++)
if (strcmp(r->name, preg->re_endp) == 0)
break;
if (r->code == 0)
return("0");
sprintf(localbuf, "%d", r->code);
return(localbuf);
}
diff --git a/lib/libc/regex/regexec.c b/lib/libc/regex/regexec.c
index 7c50bcad444a..7d3cec49ba5e 100644
--- a/lib/libc/regex/regexec.c
+++ b/lib/libc/regex/regexec.c
@@ -1,233 +1,232 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)regexec.c 8.3 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)regexec.c 8.3 (Berkeley) 3/20/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* the outer shell of regexec()
*
* This file includes engine.c three times, after muchos fiddling with the
* macros that code uses. This lets the same code operate on two different
* representations for state sets and characters.
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <ctype.h>
#include <regex.h>
#include <wchar.h>
#include <wctype.h>
#include "utils.h"
#include "regex2.h"
static int nope __unused = 0; /* for use in asserts; shuts lint up */
static __inline size_t
xmbrtowc(wint_t *wi, const char *s, size_t n, mbstate_t *mbs, wint_t dummy)
{
size_t nr;
wchar_t wc;
nr = mbrtowc(&wc, s, n, mbs);
if (wi != NULL)
*wi = wc;
if (nr == 0)
return (1);
else if (nr == (size_t)-1 || nr == (size_t)-2) {
memset(mbs, 0, sizeof(*mbs));
if (wi != NULL)
*wi = dummy;
return (1);
} else
return (nr);
}
static __inline size_t
xmbrtowc_dummy(wint_t *wi,
const char *s,
size_t n __unused,
mbstate_t *mbs __unused,
wint_t dummy __unused)
{
if (wi != NULL)
*wi = (unsigned char)*s;
return (1);
}
/* macros for manipulating states, small version */
#define states1 long /* for later use in regexec() decision */
#define states states1
#define CLEAR(v) ((v) = 0)
#define SET0(v, n) ((v) &= ~((unsigned long)1 << (n)))
#define SET1(v, n) ((v) |= (unsigned long)1 << (n))
#define ISSET(v, n) (((v) & ((unsigned long)1 << (n))) != 0)
#define ASSIGN(d, s) ((d) = (s))
#define EQ(a, b) ((a) == (b))
#define STATEVARS long dummy /* dummy version */
#define STATESETUP(m, n) /* nothing */
#define STATETEARDOWN(m) /* nothing */
#define SETUP(v) ((v) = 0)
#define onestate long
#define INIT(o, n) ((o) = (unsigned long)1 << (n))
#define INC(o) ((o) <<= 1)
#define ISSTATEIN(v, o) (((v) & (o)) != 0)
/* some abbreviations; note that some of these know variable names! */
/* do "if I'm here, I can also be there" etc without branches */
#define FWD(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) << (n))
#define BACK(dst, src, n) ((dst) |= ((unsigned long)(src)&(here)) >> (n))
#define ISSETBACK(v, n) (((v) & ((unsigned long)here >> (n))) != 0)
/* no multibyte support */
#define XMBRTOWC xmbrtowc_dummy
#define ZAPSTATE(mbs) ((void)(mbs))
/* function names */
#define SNAMES /* engine.c looks after details */
#include "engine.c"
/* now undo things */
#undef states
#undef CLEAR
#undef SET0
#undef SET1
#undef ISSET
#undef ASSIGN
#undef EQ
#undef STATEVARS
#undef STATESETUP
#undef STATETEARDOWN
#undef SETUP
#undef onestate
#undef INIT
#undef INC
#undef ISSTATEIN
#undef FWD
#undef BACK
#undef ISSETBACK
#undef SNAMES
#undef XMBRTOWC
#undef ZAPSTATE
/* macros for manipulating states, large version */
#define states char *
#define CLEAR(v) memset(v, 0, m->g->nstates)
#define SET0(v, n) ((v)[n] = 0)
#define SET1(v, n) ((v)[n] = 1)
#define ISSET(v, n) ((v)[n])
#define ASSIGN(d, s) memcpy(d, s, m->g->nstates)
#define EQ(a, b) (memcmp(a, b, m->g->nstates) == 0)
#define STATEVARS long vn; char *space
#define STATESETUP(m, nv) { (m)->space = malloc((nv)*(m)->g->nstates); \
if ((m)->space == NULL) return(REG_ESPACE); \
(m)->vn = 0; }
#define STATETEARDOWN(m) { free((m)->space); }
#define SETUP(v) ((v) = &m->space[m->vn++ * m->g->nstates])
#define onestate long
#define INIT(o, n) ((o) = (n))
#define INC(o) ((o)++)
#define ISSTATEIN(v, o) ((v)[o])
/* some abbreviations; note that some of these know variable names! */
/* do "if I'm here, I can also be there" etc without branches */
#define FWD(dst, src, n) ((dst)[here+(n)] |= (src)[here])
#define BACK(dst, src, n) ((dst)[here-(n)] |= (src)[here])
#define ISSETBACK(v, n) ((v)[here - (n)])
/* no multibyte support */
#define XMBRTOWC xmbrtowc_dummy
#define ZAPSTATE(mbs) ((void)(mbs))
/* function names */
#define LNAMES /* flag */
#include "engine.c"
/* multibyte character & large states version */
#undef LNAMES
#undef XMBRTOWC
#undef ZAPSTATE
#define XMBRTOWC xmbrtowc
#define ZAPSTATE(mbs) memset((mbs), 0, sizeof(*(mbs)))
#define MNAMES
#include "engine.c"
/*
- regexec - interface for matching
= extern int regexec(const regex_t *, const char *, size_t, \
= regmatch_t [], int);
= #define REG_NOTBOL 00001
= #define REG_NOTEOL 00002
= #define REG_STARTEND 00004
= #define REG_TRACE 00400 // tracing of execution
= #define REG_LARGE 01000 // force large representation
= #define REG_BACKR 02000 // force use of backref code
*
* We put this here so we can exploit knowledge of the state representation
* when choosing which matcher to call. Also, by this point the matchers
* have been prototyped.
*/
int /* 0 success, REG_NOMATCH failure */
regexec(const regex_t * __restrict preg,
const char * __restrict string,
size_t nmatch,
regmatch_t pmatch[__restrict],
int eflags)
{
struct re_guts *g = preg->re_g;
#ifdef REDEBUG
# define GOODFLAGS(f) (f)
#else
# define GOODFLAGS(f) ((f)&(REG_NOTBOL|REG_NOTEOL|REG_STARTEND))
#endif
if (preg->re_magic != MAGIC1 || g->magic != MAGIC2)
return(REG_BADPAT);
assert(!(g->iflags&BAD));
if (g->iflags&BAD) /* backstop for no-debug case */
return(REG_BADPAT);
eflags = GOODFLAGS(eflags);
if (MB_CUR_MAX > 1)
return(mmatcher(g, string, nmatch, pmatch, eflags));
else if (g->nstates <= CHAR_BIT*sizeof(states1) && !(eflags&REG_LARGE))
return(smatcher(g, string, nmatch, pmatch, eflags));
else
return(lmatcher(g, string, nmatch, pmatch, eflags));
}
diff --git a/lib/libc/regex/regfree.c b/lib/libc/regex/regfree.c
index dc73c4b8ef21..c5b4e3af3510 100644
--- a/lib/libc/regex/regfree.c
+++ b/lib/libc/regex/regfree.c
@@ -1,89 +1,88 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993, 1994 Henry Spencer.
* Copyright (c) 1992, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Henry Spencer.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)regfree.c 8.3 (Berkeley) 3/20/94
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)regfree.c 8.3 (Berkeley) 3/20/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <regex.h>
#include <wchar.h>
#include <wctype.h>
#include "utils.h"
#include "regex2.h"
/*
- regfree - free everything
= extern void regfree(regex_t *);
*/
void
regfree(regex_t *preg)
{
struct re_guts *g;
unsigned int i;
if (preg->re_magic != MAGIC1) /* oops */
return; /* nice to complain, but hard */
g = preg->re_g;
if (g == NULL || g->magic != MAGIC2) /* oops again */
return;
preg->re_magic = 0; /* mark it invalid */
g->magic = 0; /* mark it invalid */
if (g->strip != NULL)
free((char *)g->strip);
if (g->sets != NULL) {
for (i = 0; i < g->ncsets; i++) {
free(g->sets[i].ranges);
free(g->sets[i].wides);
free(g->sets[i].types);
}
free((char *)g->sets);
}
if (g->must != NULL)
free(g->must);
if (g->charjump != NULL)
free(&g->charjump[CHAR_MIN]);
if (g->matchjump != NULL)
free(g->matchjump);
free((char *)g);
}
diff --git a/lib/libc/resolv/herror.c b/lib/libc/resolv/herror.c
index f222497db0ee..79edc3549c8e 100644
--- a/lib/libc/resolv/herror.c
+++ b/lib/libc/resolv/herror.c
@@ -1,125 +1,124 @@
/*-
* SPDX-License-Identifier: (BSD-3-Clause AND ISC)
*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: herror.c,v 1.4 2005/04/27 04:56:41 sra Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include "namespace.h"
#include <sys/param.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "port_after.h"
const char *h_errlist[] = {
"Resolver Error 0 (no error)",
"Unknown host", /*%< 1 HOST_NOT_FOUND */
"Host name lookup failure", /*%< 2 TRY_AGAIN */
"Unknown server error", /*%< 3 NO_RECOVERY */
"No address associated with name", /*%< 4 NO_ADDRESS */
};
const int h_nerr = { nitems(h_errlist) };
#undef h_errno
int h_errno;
/*%
* herror --
* print the error indicated by the h_errno value.
*/
void
herror(const char *s) {
struct iovec iov[4], *v = iov;
char *t;
if (s != NULL && *s != '\0') {
DE_CONST(s, t);
v->iov_base = t;
v->iov_len = strlen(t);
v++;
DE_CONST(": ", t);
v->iov_base = t;
v->iov_len = 2;
v++;
}
DE_CONST(hstrerror(*__h_errno()), t);
v->iov_base = t;
v->iov_len = strlen(v->iov_base);
v++;
DE_CONST("\n", t);
v->iov_base = t;
v->iov_len = 1;
_writev(STDERR_FILENO, iov, (v - iov) + 1);
}
/*%
* hstrerror --
* return the string associated with a given "host" errno value.
*/
const char *
hstrerror(int err) {
if (err < 0)
return ("Resolver internal error");
else if (err < h_nerr)
return (h_errlist[err]);
return ("Unknown resolver error");
}
/*! \file */
diff --git a/lib/libc/resolv/mtctxres.c b/lib/libc/resolv/mtctxres.c
index e754ab0c5209..beb2b6b3f5dd 100644
--- a/lib/libc/resolv/mtctxres.c
+++ b/lib/libc/resolv/mtctxres.c
@@ -1,136 +1,135 @@
-#include <sys/cdefs.h>
#include <port_before.h>
#ifdef DO_PTHREADS
#include <pthread.h>
#ifdef _LIBC
#include <pthread_np.h>
#endif
#endif
#include <errno.h>
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
#include <resolv_mt.h>
#include <port_after.h>
#ifdef DO_PTHREADS
static pthread_key_t key;
static int mt_key_initialized = 0;
static int __res_init_ctx(void);
static void __res_destroy_ctx(void *);
#if defined(sun) && !defined(__GNUC__)
#pragma init (_mtctxres_init)
#endif
#endif
static mtctxres_t sharedctx;
#ifdef DO_PTHREADS
/*
* Initialize the TSD key. By doing this at library load time, we're
* implicitly running without interference from other threads, so there's
* no need for locking.
*/
static void
_mtctxres_init(void) {
int pthread_keycreate_ret;
pthread_keycreate_ret = pthread_key_create(&key, __res_destroy_ctx);
if (pthread_keycreate_ret == 0)
mt_key_initialized = 1;
}
#endif
#ifndef _LIBC
/*
* To support binaries that used the private MT-safe interface in
* Solaris 8, we still need to provide the __res_enable_mt()
* and __res_disable_mt() entry points. They're do-nothing routines.
*/
int
__res_enable_mt(void) {
return (-1);
}
int
__res_disable_mt(void) {
return (0);
}
#endif
#ifdef DO_PTHREADS
static int
__res_init_ctx(void) {
mtctxres_t *mt;
int ret;
if (pthread_getspecific(key) != 0) {
/* Already exists */
return (0);
}
if ((mt = malloc(sizeof(mtctxres_t))) == NULL) {
errno = ENOMEM;
return (-1);
}
memset(mt, 0, sizeof (mtctxres_t));
if ((ret = pthread_setspecific(key, mt)) != 0) {
free(mt);
errno = ret;
return (-1);
}
return (0);
}
static void
__res_destroy_ctx(void *value) {
free(value);
}
#endif
mtctxres_t *
___mtctxres(void) {
#ifdef DO_PTHREADS
mtctxres_t *mt;
#ifdef _LIBC
if (pthread_main_np() != 0)
return (&sharedctx);
#endif
/*
* This if clause should only be executed if we are linking
* statically. When linked dynamically _mtctxres_init() should
* be called at binding time due the #pragma above.
*/
if (!mt_key_initialized) {
static pthread_mutex_t keylock = PTHREAD_MUTEX_INITIALIZER;
if (pthread_mutex_lock(&keylock) == 0) {
_mtctxres_init();
(void) pthread_mutex_unlock(&keylock);
}
}
/*
* If we have already been called in this thread return the existing
* context. Otherwise recreat a new context and return it. If
* that fails return a global context.
*/
if (mt_key_initialized) {
if (((mt = pthread_getspecific(key)) != NULL) ||
(__res_init_ctx() == 0 &&
(mt = pthread_getspecific(key)) != NULL)) {
return (mt);
}
}
#endif
return (&sharedctx);
}
diff --git a/lib/libc/resolv/res_comp.c b/lib/libc/resolv/res_comp.c
index 0709b7f2eaab..c60e81473ce8 100644
--- a/lib/libc/resolv/res_comp.c
+++ b/lib/libc/resolv/res_comp.c
@@ -1,276 +1,275 @@
/*-
* SPDX-License-Identifier: (BSD-3-Clause AND ISC)
*
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
*/
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_comp.c,v 1.5 2005/07/28 06:51:50 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <resolv.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "port_after.h"
/*%
* Expand compressed domain name 'src' to full domain name.
*
* \li 'msg' is a pointer to the beginning of the message,
* \li 'eom' points to the first location after the message,
* \li 'dst' is a pointer to a buffer of size 'dstsiz' for the result.
* \li Return size of compressed name or -1 if there was an error.
*/
int
dn_expand(const u_char *msg, const u_char *eom, const u_char *src,
char *dst, int dstsiz)
{
int n = ns_name_uncompress(msg, eom, src, dst, (size_t)dstsiz);
if (n > 0 && dst[0] == '.')
dst[0] = '\0';
return (n);
}
/*%
* Pack domain name 'exp_dn' in presentation form into 'comp_dn'.
*
* \li Return the size of the compressed name or -1.
* \li 'length' is the size of the array pointed to by 'comp_dn'.
*/
int
dn_comp(const char *src, u_char *dst, int dstsiz,
u_char **dnptrs, u_char **lastdnptr)
{
return (ns_name_compress(src, dst, (size_t)dstsiz,
(const u_char **)dnptrs,
(const u_char **)lastdnptr));
}
/*%
* Skip over a compressed domain name. Return the size or -1.
*/
int
dn_skipname(const u_char *ptr, const u_char *eom) {
const u_char *saveptr = ptr;
if (ns_name_skip(&ptr, eom) == -1)
return (-1);
return (ptr - saveptr);
}
/*%
* Verify that a domain name uses an acceptable character set.
*
* Note the conspicuous absence of ctype macros in these definitions. On
* non-ASCII hosts, we can't depend on string literals or ctype macros to
* tell us anything about network-format data. The rest of the BIND system
* is not careful about this, but for some reason, we're doing it right here.
*/
#define PERIOD 0x2e
#define hyphenchar(c) ((c) == 0x2d)
#define bslashchar(c) ((c) == 0x5c)
#define underscorechar(c) ((c) == 0x5f)
#define periodchar(c) ((c) == PERIOD)
#define asterchar(c) ((c) == 0x2a)
#define alphachar(c) (((c) >= 0x41 && (c) <= 0x5a) \
|| ((c) >= 0x61 && (c) <= 0x7a))
#define digitchar(c) ((c) >= 0x30 && (c) <= 0x39)
#ifdef RES_ENFORCE_RFC1034
#define borderchar(c) (alphachar(c) || digitchar(c))
#else
#define borderchar(c) (alphachar(c) || digitchar(c) || underscorechar(c))
#endif
#define middlechar(c) (borderchar(c) || hyphenchar(c))
#define domainchar(c) ((c) > 0x20 && (c) < 0x7f)
int
res_hnok(const char *dn) {
int pch = PERIOD, ch = *dn++;
while (ch != '\0') {
int nch = *dn++;
if (periodchar(ch)) {
(void)NULL;
} else if (periodchar(pch)) {
if (!borderchar(ch))
return (0);
} else if (periodchar(nch) || nch == '\0') {
if (!borderchar(ch))
return (0);
} else {
if (!middlechar(ch))
return (0);
}
pch = ch, ch = nch;
}
return (1);
}
/*%
* hostname-like (A, MX, WKS) owners can have "*" as their first label
* but must otherwise be as a host name.
*/
int
res_ownok(const char *dn) {
if (asterchar(dn[0])) {
if (periodchar(dn[1]))
return (res_hnok(dn+2));
if (dn[1] == '\0')
return (1);
}
return (res_hnok(dn));
}
/*%
* SOA RNAMEs and RP RNAMEs can have any printable character in their first
* label, but the rest of the name has to look like a host name.
*/
int
res_mailok(const char *dn) {
int ch, escaped = 0;
/* "." is a valid missing representation */
if (*dn == '\0')
return (1);
/* otherwise <label>.<hostname> */
while ((ch = *dn++) != '\0') {
if (!domainchar(ch))
return (0);
if (!escaped && periodchar(ch))
break;
if (escaped)
escaped = 0;
else if (bslashchar(ch))
escaped = 1;
}
if (periodchar(ch))
return (res_hnok(dn));
return (0);
}
/*%
* This function is quite liberal, since RFC1034's character sets are only
* recommendations.
*/
int
res_dnok(const char *dn) {
int ch;
while ((ch = *dn++) != '\0')
if (!domainchar(ch))
return (0);
return (1);
}
#ifdef BIND_4_COMPAT
/*%
* This module must export the following externally-visible symbols:
* ___putlong
* ___putshort
* __getlong
* __getshort
* Note that one _ comes from C and the others come from us.
*/
#ifdef SOLARIS2
#ifdef __putlong
#undef __putlong
#endif
#ifdef __putshort
#undef __putshort
#endif
#pragma weak putlong = __putlong
#pragma weak putshort = __putshort
#endif /* SOLARIS2 */
void __putlong(u_int32_t src, u_char *dst) { ns_put32(src, dst); }
void __putshort(u_int16_t src, u_char *dst) { ns_put16(src, dst); }
#ifndef __ultrix__
u_int32_t _getlong(const u_char *src) { return (ns_get32(src)); }
u_int16_t _getshort(const u_char *src) { return (ns_get16(src)); }
#endif /*__ultrix__*/
#endif /*BIND_4_COMPAT*/
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <resolv.h>.
*/
#undef dn_comp
__weak_reference(__dn_comp, dn_comp);
#undef dn_expand
__weak_reference(__dn_expand, dn_expand);
/*! \file */
diff --git a/lib/libc/resolv/res_data.c b/lib/libc/resolv/res_data.c
index 71b4b9279b4c..d6f68e29ddc1 100644
--- a/lib/libc/resolv/res_data.c
+++ b/lib/libc/resolv/res_data.c
@@ -1,335 +1,334 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1995-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char rcsid[] = "$Id: res_data.c,v 1.7 2008/12/11 09:59:00 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <netdb.h>
#include <resolv.h>
#include <res_update.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "port_after.h"
const char *_res_opcodes[] = {
"QUERY",
"IQUERY",
"CQUERYM",
"CQUERYU", /*%< experimental */
"NOTIFY", /*%< experimental */
"UPDATE",
"6",
"7",
"8",
"9",
"10",
"11",
"12",
"13",
"ZONEINIT",
"ZONEREF",
};
#ifdef BIND_UPDATE
const char *_res_sectioncodes[] = {
"ZONE",
"PREREQUISITES",
"UPDATE",
"ADDITIONAL",
};
#endif
#ifndef __BIND_NOSTATIC
/* Proto. */
int res_ourserver_p(const res_state, const struct sockaddr_in *);
__noinline int
res_init(void) {
extern int __res_vinit(res_state, int);
res_state statp = &_res;
/*
* These three fields used to be statically initialized. This made
* it hard to use this code in a shared library. It is necessary,
* now that we're doing dynamic initialization here, that we preserve
* the old semantics: if an application modifies one of these three
* fields of _res before res_init() is called, res_init() will not
* alter them. Of course, if an application is setting them to
* _zero_ before calling res_init(), hoping to override what used
* to be the static default, we can't detect it and unexpected results
* will follow. Zero for any of these fields would make no sense,
* so one can safely assume that the applications were already getting
* unexpected results.
*
* _res.options is tricky since some apps were known to diddle the bits
* before res_init() was first called. We can't replicate that semantic
* with dynamic initialization (they may have turned bits off that are
* set in RES_DEFAULT). Our solution is to declare such applications
* "broken". They could fool us by setting RES_INIT but none do (yet).
*/
if (!statp->retrans)
statp->retrans = RES_TIMEOUT;
if (!statp->retry)
statp->retry = RES_DFLRETRY;
if (!(statp->options & RES_INIT))
statp->options = RES_DEFAULT;
return (__res_vinit(statp, 1));
}
void
p_query(const u_char *msg) {
fp_query(msg, stdout);
}
void
fp_query(const u_char *msg, FILE *file) {
fp_nquery(msg, PACKETSZ, file);
}
void
fp_nquery(const u_char *msg, int len, FILE *file) {
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1)
return;
res_pquery(statp, msg, len, file);
}
int
res_mkquery(int op, /*!< opcode of query */
const char *dname, /*!< domain name */
int class, int type, /*!< class and type of query */
const u_char *data, /*!< resource record data */
int datalen, /*!< length of data */
const u_char *newrr_in, /*!< new rr for modify or append */
u_char *buf, /*!< buffer to put query */
int buflen) /*!< size of buffer */
{
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (res_nmkquery(statp, op, dname, class, type,
data, datalen,
newrr_in, buf, buflen));
}
int
res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (res_nmkupdate(statp, rrecp_in, buf, buflen));
}
int
res_query(const char *name, /*!< domain name */
int class, int type, /*!< class and type of query */
u_char *answer, /*!< buffer to put answer */
int anslen) /*!< size of answer buffer */
{
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (res_nquery(statp, name, class, type, answer, anslen));
}
#ifndef _LIBC
void
res_send_setqhook(res_send_qhook hook) {
_res.qhook = hook;
}
void
res_send_setrhook(res_send_rhook hook) {
_res.rhook = hook;
}
#endif
int
res_isourserver(const struct sockaddr_in *inp) {
return (res_ourserver_p(&_res, inp));
}
int
res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
/* errno should have been set by res_init() in this case. */
return (-1);
}
return (res_nsend(statp, buf, buflen, ans, anssiz));
}
#ifndef _LIBC
int
res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
u_char *ans, int anssiz)
{
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
/* errno should have been set by res_init() in this case. */
return (-1);
}
return (res_nsendsigned(statp, buf, buflen, key, ans, anssiz));
}
#endif
void
res_close(void) {
res_nclose(&_res);
}
int
res_update(ns_updrec *rrecp_in) {
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (res_nupdate(statp, rrecp_in, NULL));
}
int
res_search(const char *name, /*!< domain name */
int class, int type, /*!< class and type of query */
u_char *answer, /*!< buffer to put answer */
int anslen) /*!< size of answer */
{
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (res_nsearch(statp, name, class, type, answer, anslen));
}
int
res_querydomain(const char *name,
const char *domain,
int class, int type, /*!< class and type of query */
u_char *answer, /*!< buffer to put answer */
int anslen) /*!< size of answer */
{
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (res_nquerydomain(statp, name, domain,
class, type,
answer, anslen));
}
u_int
res_randomid(void) {
res_state statp = &_res;
if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
return (-1);
}
return (res_nrandomid(statp));
}
int
res_opt(int n0, u_char *buf, int buflen, int anslen)
{
return (res_nopt(&_res, n0, buf, buflen, anslen));
}
const char *
hostalias(const char *name) {
static char abuf[MAXDNAME];
return (res_hostalias(&_res, name, abuf, sizeof abuf));
}
#ifdef ultrix
int
local_hostname_length(const char *hostname) {
int len_host, len_domain;
res_state statp;
statp = &_res;
if (!*statp->defdname)
res_init();
len_host = strlen(hostname);
len_domain = strlen(statp->defdname);
if (len_host > len_domain &&
!strcasecmp(hostname + len_host - len_domain, statp->defdname) &&
hostname[len_host - len_domain - 1] == '.')
return (len_host - len_domain - 1);
return (0);
}
#endif /*ultrix*/
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <resolv.h>.
*/
#undef res_init
__weak_reference(__res_init, res_init);
#undef p_query
__weak_reference(__p_query, p_query);
#undef res_mkquery
__weak_reference(__res_mkquery, res_mkquery);
#undef res_query
__weak_reference(__res_query, res_query);
#undef res_send
__weak_reference(__res_send, res_send);
#undef res_close
__weak_reference(__res_close, _res_close);
#undef res_search
__weak_reference(__res_search, res_search);
#undef res_querydomain
__weak_reference(__res_querydomain, res_querydomain);
#endif
/*! \file */
diff --git a/lib/libc/resolv/res_debug.c b/lib/libc/resolv/res_debug.c
index 7dd902af1b69..254f17202264 100644
--- a/lib/libc/resolv/res_debug.c
+++ b/lib/libc/resolv/res_debug.c
@@ -1,1239 +1,1238 @@
/*-
* SPDX-License-Identifier: (ISC AND BSD-3-Clause)
*
* Portions Copyright (C) 2004, 2005, 2008, 2009 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 1996-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/*-
* Copyright (c) 1985
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
*/
/*
* Portions Copyright (c) 1995 by International Business Machines, Inc.
*
* International Business Machines, Inc. (hereinafter called IBM) grants
* permission under its copyrights to use, copy, modify, and distribute this
* Software with or without fee, provided that the above copyright notice and
* all paragraphs of this notice appear in all copies, and that the name of IBM
* not be used in connection with the marketing of any product incorporating
* the Software or modifications thereof, without specific, written prior
* permission.
*
* To the extent it has a right to do so, IBM grants an immunity from suit
* under its patents, if any, for the use, sale or manufacture of products to
* the extent that such products are used for performing Domain Name System
* dynamic updates in TCP/IP networks by means of the Software. No immunity is
* granted for any product per se or for any other function of any product.
*
* THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
* INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
* DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_debug.c,v 1.19 2009/02/26 11:20:20 tbox Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <errno.h>
#include <math.h>
#include <netdb.h>
#include <resolv.h>
#include <resolv_mt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "port_after.h"
#ifdef SPRINTF_CHAR
# define SPRINTF(x) strlen(sprintf/**/x)
#else
# define SPRINTF(x) sprintf x
#endif
extern const char *_res_opcodes[];
extern const char *_res_sectioncodes[];
/*%
* Print the current options.
*/
void
fp_resstat(const res_state statp, FILE *file) {
u_long mask;
fprintf(file, ";; res options:");
for (mask = 1; mask != 0U; mask <<= 1)
if (statp->options & mask)
fprintf(file, " %s", p_option(mask));
putc('\n', file);
}
static void
do_section(const res_state statp,
ns_msg *handle, ns_sect section,
int pflag, FILE *file)
{
int n, sflag, rrnum;
static int buflen = 2048;
char *buf;
ns_opcode opcode;
ns_rr rr;
/*
* Print answer records.
*/
sflag = (statp->pfcode & pflag);
if (statp->pfcode && !sflag)
return;
buf = malloc(buflen);
if (buf == NULL) {
fprintf(file, ";; memory allocation failure\n");
return;
}
opcode = (ns_opcode) ns_msg_getflag(*handle, ns_f_opcode);
rrnum = 0;
for (;;) {
if (ns_parserr(handle, section, rrnum, &rr)) {
if (errno != ENODEV)
fprintf(file, ";; ns_parserr: %s\n",
strerror(errno));
else if (rrnum > 0 && sflag != 0 &&
(statp->pfcode & RES_PRF_HEAD1))
putc('\n', file);
goto cleanup;
}
if (rrnum == 0 && sflag != 0 && (statp->pfcode & RES_PRF_HEAD1))
fprintf(file, ";; %s SECTION:\n",
p_section(section, opcode));
if (section == ns_s_qd)
fprintf(file, ";;\t%s, type = %s, class = %s\n",
ns_rr_name(rr),
p_type(ns_rr_type(rr)),
p_class(ns_rr_class(rr)));
else if (section == ns_s_ar && ns_rr_type(rr) == ns_t_opt) {
u_int16_t optcode, optlen, rdatalen = ns_rr_rdlen(rr);
u_int32_t ttl = ns_rr_ttl(rr);
fprintf(file,
"; EDNS: version: %u, udp=%u, flags=%04x\n",
(ttl>>16)&0xff, ns_rr_class(rr), ttl&0xffff);
while (rdatalen >= 4) {
const u_char *cp = ns_rr_rdata(rr);
int i;
GETSHORT(optcode, cp);
GETSHORT(optlen, cp);
if (optcode == NS_OPT_NSID) {
fputs("; NSID: ", file);
if (optlen == 0) {
fputs("; NSID\n", file);
} else {
fputs("; NSID: ", file);
for (i = 0; i < optlen; i++)
fprintf(file, "%02x ",
cp[i]);
fputs(" (",file);
for (i = 0; i < optlen; i++)
fprintf(file, "%c",
isprint(cp[i])?
cp[i] : '.');
fputs(")\n", file);
}
} else {
if (optlen == 0) {
fprintf(file, "; OPT=%u\n",
optcode);
} else {
fprintf(file, "; OPT=%u: ",
optcode);
for (i = 0; i < optlen; i++)
fprintf(file, "%02x ",
cp[i]);
fputs(" (",file);
for (i = 0; i < optlen; i++)
fprintf(file, "%c",
isprint(cp[i]) ?
cp[i] : '.');
fputs(")\n", file);
}
}
rdatalen -= 4 + optlen;
}
} else {
n = ns_sprintrr(handle, &rr, NULL, NULL,
buf, buflen);
if (n < 0) {
if (errno == ENOSPC) {
free(buf);
buf = NULL;
if (buflen < 131072)
buf = malloc(buflen += 1024);
if (buf == NULL) {
fprintf(file,
";; memory allocation failure\n");
return;
}
continue;
}
fprintf(file, ";; ns_sprintrr: %s\n",
strerror(errno));
goto cleanup;
}
fputs(buf, file);
fputc('\n', file);
}
rrnum++;
}
cleanup:
if (buf != NULL)
free(buf);
}
/*%
* Print the contents of a query.
* This is intended to be primarily a debugging routine.
*/
void
res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
ns_msg handle;
int qdcount, ancount, nscount, arcount;
u_int opcode, rcode, id;
if (ns_initparse(msg, len, &handle) < 0) {
fprintf(file, ";; ns_initparse: %s\n", strerror(errno));
return;
}
opcode = ns_msg_getflag(handle, ns_f_opcode);
rcode = ns_msg_getflag(handle, ns_f_rcode);
id = ns_msg_id(handle);
qdcount = ns_msg_count(handle, ns_s_qd);
ancount = ns_msg_count(handle, ns_s_an);
nscount = ns_msg_count(handle, ns_s_ns);
arcount = ns_msg_count(handle, ns_s_ar);
/*
* Print header fields.
*/
if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX) || rcode)
fprintf(file,
";; ->>HEADER<<- opcode: %s, status: %s, id: %d\n",
_res_opcodes[opcode], p_rcode(rcode), id);
if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEADX))
putc(';', file);
if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD2)) {
fprintf(file, "; flags:");
if (ns_msg_getflag(handle, ns_f_qr))
fprintf(file, " qr");
if (ns_msg_getflag(handle, ns_f_aa))
fprintf(file, " aa");
if (ns_msg_getflag(handle, ns_f_tc))
fprintf(file, " tc");
if (ns_msg_getflag(handle, ns_f_rd))
fprintf(file, " rd");
if (ns_msg_getflag(handle, ns_f_ra))
fprintf(file, " ra");
if (ns_msg_getflag(handle, ns_f_z))
fprintf(file, " ??");
if (ns_msg_getflag(handle, ns_f_ad))
fprintf(file, " ad");
if (ns_msg_getflag(handle, ns_f_cd))
fprintf(file, " cd");
}
if ((!statp->pfcode) || (statp->pfcode & RES_PRF_HEAD1)) {
fprintf(file, "; %s: %d",
p_section(ns_s_qd, opcode), qdcount);
fprintf(file, ", %s: %d",
p_section(ns_s_an, opcode), ancount);
fprintf(file, ", %s: %d",
p_section(ns_s_ns, opcode), nscount);
fprintf(file, ", %s: %d",
p_section(ns_s_ar, opcode), arcount);
}
if ((!statp->pfcode) || (statp->pfcode &
(RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
putc('\n',file);
}
/*
* Print the various sections.
*/
do_section(statp, &handle, ns_s_qd, RES_PRF_QUES, file);
do_section(statp, &handle, ns_s_an, RES_PRF_ANS, file);
do_section(statp, &handle, ns_s_ns, RES_PRF_AUTH, file);
do_section(statp, &handle, ns_s_ar, RES_PRF_ADD, file);
if (qdcount == 0 && ancount == 0 &&
nscount == 0 && arcount == 0)
putc('\n', file);
}
const u_char *
p_cdnname(const u_char *cp, const u_char *msg, int len, FILE *file) {
char name[MAXDNAME];
int n;
if ((n = dn_expand(msg, msg + len, cp, name, sizeof name)) < 0)
return (NULL);
if (name[0] == '\0')
putc('.', file);
else
fputs(name, file);
return (cp + n);
}
const u_char *
p_cdname(const u_char *cp, const u_char *msg, FILE *file) {
return (p_cdnname(cp, msg, PACKETSZ, file));
}
/*%
* Return a fully-qualified domain name from a compressed name (with
length supplied). */
const u_char *
p_fqnname(const u_char *cp, const u_char *msg, int msglen, char *name,
int namelen)
{
int n, newlen;
if ((n = dn_expand(msg, cp + msglen, cp, name, namelen)) < 0)
return (NULL);
newlen = strlen(name);
if (newlen == 0 || name[newlen - 1] != '.') {
if (newlen + 1 >= namelen) /*%< Lack space for final dot */
return (NULL);
else
strcpy(name + newlen, ".");
}
return (cp + n);
}
/* XXX: the rest of these functions need to become length-limited, too. */
const u_char *
p_fqname(const u_char *cp, const u_char *msg, FILE *file) {
char name[MAXDNAME];
const u_char *n;
n = p_fqnname(cp, msg, MAXCDNAME, name, sizeof name);
if (n == NULL)
return (NULL);
fputs(name, file);
return (n);
}
/*%
* Names of RR classes and qclasses. Classes and qclasses are the same, except
* that C_ANY is a qclass but not a class. (You can ask for records of class
* C_ANY, but you can't have any records of that class in the database.)
*/
const struct res_sym __p_class_syms[] = {
{C_IN, "IN", (char *)0},
{C_CHAOS, "CH", (char *)0},
{C_CHAOS, "CHAOS", (char *)0},
{C_HS, "HS", (char *)0},
{C_HS, "HESIOD", (char *)0},
{C_ANY, "ANY", (char *)0},
{C_NONE, "NONE", (char *)0},
{C_IN, (char *)0, (char *)0}
};
/*%
* Names of message sections.
*/
static const struct res_sym __p_default_section_syms[] = {
{ns_s_qd, "QUERY", (char *)0},
{ns_s_an, "ANSWER", (char *)0},
{ns_s_ns, "AUTHORITY", (char *)0},
{ns_s_ar, "ADDITIONAL", (char *)0},
{0, (char *)0, (char *)0}
};
static const struct res_sym __p_update_section_syms[] = {
{S_ZONE, "ZONE", (char *)0},
{S_PREREQ, "PREREQUISITE", (char *)0},
{S_UPDATE, "UPDATE", (char *)0},
{S_ADDT, "ADDITIONAL", (char *)0},
{0, (char *)0, (char *)0}
};
const struct res_sym __p_key_syms[] = {
{NS_ALG_MD5RSA, "RSA", "RSA KEY with MD5 hash"},
{NS_ALG_DH, "DH", "Diffie Hellman"},
{NS_ALG_DSA, "DSA", "Digital Signature Algorithm"},
{NS_ALG_EXPIRE_ONLY, "EXPIREONLY", "No algorithm"},
{NS_ALG_PRIVATE_OID, "PRIVATE", "Algorithm obtained from OID"},
{0, NULL, NULL}
};
const struct res_sym __p_cert_syms[] = {
{cert_t_pkix, "PKIX", "PKIX (X.509v3) Certificate"},
{cert_t_spki, "SPKI", "SPKI certificate"},
{cert_t_pgp, "PGP", "PGP certificate"},
{cert_t_url, "URL", "URL Private"},
{cert_t_oid, "OID", "OID Private"},
{0, NULL, NULL}
};
/*%
* Names of RR types and qtypes. Types and qtypes are the same, except
* that T_ANY is a qtype but not a type. (You can ask for records of type
* T_ANY, but you can't have any records of that type in the database.)
*/
const struct res_sym __p_type_syms[] = {
{ns_t_a, "A", "address"},
{ns_t_ns, "NS", "name server"},
{ns_t_md, "MD", "mail destination (deprecated)"},
{ns_t_mf, "MF", "mail forwarder (deprecated)"},
{ns_t_cname, "CNAME", "canonical name"},
{ns_t_soa, "SOA", "start of authority"},
{ns_t_mb, "MB", "mailbox"},
{ns_t_mg, "MG", "mail group member"},
{ns_t_mr, "MR", "mail rename"},
{ns_t_null, "NULL", "null"},
{ns_t_wks, "WKS", "well-known service (deprecated)"},
{ns_t_ptr, "PTR", "domain name pointer"},
{ns_t_hinfo, "HINFO", "host information"},
{ns_t_minfo, "MINFO", "mailbox information"},
{ns_t_mx, "MX", "mail exchanger"},
{ns_t_txt, "TXT", "text"},
{ns_t_rp, "RP", "responsible person"},
{ns_t_afsdb, "AFSDB", "DCE or AFS server"},
{ns_t_x25, "X25", "X25 address"},
{ns_t_isdn, "ISDN", "ISDN address"},
{ns_t_rt, "RT", "router"},
{ns_t_nsap, "NSAP", "nsap address"},
{ns_t_nsap_ptr, "NSAP_PTR", "domain name pointer"},
{ns_t_sig, "SIG", "signature"},
{ns_t_key, "KEY", "key"},
{ns_t_px, "PX", "mapping information"},
{ns_t_gpos, "GPOS", "geographical position (withdrawn)"},
{ns_t_aaaa, "AAAA", "IPv6 address"},
{ns_t_loc, "LOC", "location"},
{ns_t_nxt, "NXT", "next valid name (unimplemented)"},
{ns_t_eid, "EID", "endpoint identifier (unimplemented)"},
{ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"},
{ns_t_srv, "SRV", "server selection"},
{ns_t_atma, "ATMA", "ATM address (unimplemented)"},
{ns_t_naptr, "NAPTR", "naptr"},
{ns_t_kx, "KX", "key exchange"},
{ns_t_cert, "CERT", "certificate"},
{ns_t_a6, "A", "IPv6 address (experminental)"},
{ns_t_dname, "DNAME", "non-terminal redirection"},
{ns_t_opt, "OPT", "opt"},
{ns_t_apl, "apl", "apl"},
{ns_t_ds, "DS", "delegation signer"},
{ns_t_sshfp, "SSFP", "SSH fingerprint"},
{ns_t_ipseckey, "IPSECKEY", "IPSEC key"},
{ns_t_rrsig, "RRSIG", "rrsig"},
{ns_t_nsec, "NSEC", "nsec"},
{ns_t_dnskey, "DNSKEY", "DNS key"},
{ns_t_dhcid, "DHCID", "dynamic host configuration identifier"},
{ns_t_nsec3, "NSEC3", "nsec3"},
{ns_t_nsec3param, "NSEC3PARAM", "NSEC3 parameters"},
{ns_t_hip, "HIP", "host identity protocol"},
{ns_t_spf, "SPF", "sender policy framework"},
{ns_t_tkey, "TKEY", "tkey"},
{ns_t_tsig, "TSIG", "transaction signature"},
{ns_t_ixfr, "IXFR", "incremental zone transfer"},
{ns_t_axfr, "AXFR", "zone transfer"},
{ns_t_zxfr, "ZXFR", "compressed zone transfer"},
{ns_t_mailb, "MAILB", "mailbox-related data (deprecated)"},
{ns_t_maila, "MAILA", "mail agent (deprecated)"},
{ns_t_naptr, "NAPTR", "URN Naming Authority"},
{ns_t_kx, "KX", "Key Exchange"},
{ns_t_cert, "CERT", "Certificate"},
{ns_t_a6, "A6", "IPv6 Address"},
{ns_t_dname, "DNAME", "dname"},
{ns_t_sink, "SINK", "Kitchen Sink (experimental)"},
{ns_t_opt, "OPT", "EDNS Options"},
{ns_t_any, "ANY", "\"any\""},
{ns_t_dlv, "DLV", "DNSSEC look-aside validation"},
{0, NULL, NULL}
};
/*%
* Names of DNS rcodes.
*/
const struct res_sym __p_rcode_syms[] = {
{ns_r_noerror, "NOERROR", "no error"},
{ns_r_formerr, "FORMERR", "format error"},
{ns_r_servfail, "SERVFAIL", "server failed"},
{ns_r_nxdomain, "NXDOMAIN", "no such domain name"},
{ns_r_notimpl, "NOTIMP", "not implemented"},
{ns_r_refused, "REFUSED", "refused"},
{ns_r_yxdomain, "YXDOMAIN", "domain name exists"},
{ns_r_yxrrset, "YXRRSET", "rrset exists"},
{ns_r_nxrrset, "NXRRSET", "rrset doesn't exist"},
{ns_r_notauth, "NOTAUTH", "not authoritative"},
{ns_r_notzone, "NOTZONE", "Not in zone"},
{ns_r_max, "", ""},
{ns_r_badsig, "BADSIG", "bad signature"},
{ns_r_badkey, "BADKEY", "bad key"},
{ns_r_badtime, "BADTIME", "bad time"},
{0, NULL, NULL}
};
int
sym_ston(const struct res_sym *syms, const char *name, int *success) {
for ((void)NULL; syms->name != 0; syms++) {
if (strcasecmp (name, syms->name) == 0) {
if (success)
*success = 1;
return (syms->number);
}
}
if (success)
*success = 0;
return (syms->number); /*%< The default value. */
}
const char *
sym_ntos(const struct res_sym *syms, int number, int *success) {
char *unname = sym_ntos_unname;
for ((void)NULL; syms->name != 0; syms++) {
if (number == syms->number) {
if (success)
*success = 1;
return (syms->name);
}
}
sprintf(unname, "%d", number); /*%< XXX nonreentrant */
if (success)
*success = 0;
return (unname);
}
const char *
sym_ntop(const struct res_sym *syms, int number, int *success) {
char *unname = sym_ntop_unname;
for ((void)NULL; syms->name != 0; syms++) {
if (number == syms->number) {
if (success)
*success = 1;
return (syms->humanname);
}
}
sprintf(unname, "%d", number); /*%< XXX nonreentrant */
if (success)
*success = 0;
return (unname);
}
/*%
* Return a string for the type.
*/
const char *
p_type(int type) {
int success;
const char *result;
static char typebuf[20];
result = sym_ntos(__p_type_syms, type, &success);
if (success)
return (result);
if (type < 0 || type > 0xffff)
return ("BADTYPE");
sprintf(typebuf, "TYPE%d", type);
return (typebuf);
}
/*%
* Return a string for the type.
*/
const char *
p_section(int section, int opcode) {
const struct res_sym *symbols;
switch (opcode) {
case ns_o_update:
symbols = __p_update_section_syms;
break;
default:
symbols = __p_default_section_syms;
break;
}
return (sym_ntos(symbols, section, (int *)0));
}
/*%
* Return a mnemonic for class.
*/
const char *
p_class(int class) {
int success;
const char *result;
static char classbuf[20];
result = sym_ntos(__p_class_syms, class, &success);
if (success)
return (result);
if (class < 0 || class > 0xffff)
return ("BADCLASS");
sprintf(classbuf, "CLASS%d", class);
return (classbuf);
}
/*%
* Return a mnemonic for an option
*/
const char *
p_option(u_long option) {
char *nbuf = p_option_nbuf;
switch (option) {
case RES_INIT: return "init";
case RES_DEBUG: return "debug";
case RES_AAONLY: return "aaonly(unimpl)";
case RES_USEVC: return "usevc";
case RES_PRIMARY: return "primry(unimpl)";
case RES_IGNTC: return "igntc";
case RES_RECURSE: return "recurs";
case RES_DEFNAMES: return "defnam";
case RES_STAYOPEN: return "styopn";
case RES_DNSRCH: return "dnsrch";
case RES_INSECURE1: return "insecure1";
case RES_INSECURE2: return "insecure2";
case RES_NOALIASES: return "noaliases";
case RES_USE_INET6: return "inet6";
#ifdef RES_USE_EDNS0 /*%< KAME extension */
case RES_USE_EDNS0: return "edns0";
case RES_NSID: return "nsid";
#endif
#ifdef RES_USE_DNAME
case RES_USE_DNAME: return "dname";
#endif
#ifdef RES_USE_DNSSEC
case RES_USE_DNSSEC: return "dnssec";
#endif
#ifdef RES_NOTLDQUERY
case RES_NOTLDQUERY: return "no-tld-query";
#endif
#ifdef RES_NO_NIBBLE2
case RES_NO_NIBBLE2: return "no-nibble2";
#endif
/* XXX nonreentrant */
default: sprintf(nbuf, "?0x%lx?", (u_long)option);
return (nbuf);
}
}
/*%
* Return a mnemonic for a time to live.
*/
const char *
p_time(u_int32_t value) {
char *nbuf = p_time_nbuf;
if (ns_format_ttl(value, nbuf, sizeof nbuf) < 0)
sprintf(nbuf, "%u", value);
return (nbuf);
}
/*%
* Return a string for the rcode.
*/
const char *
p_rcode(int rcode) {
return (sym_ntos(__p_rcode_syms, rcode, (int *)0));
}
/*%
* Return a string for a res_sockaddr_union.
*/
const char *
p_sockun(union res_sockaddr_union u, char *buf, size_t size) {
char ret[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:123.123.123.123"];
switch (u.sin.sin_family) {
case AF_INET:
inet_ntop(AF_INET, &u.sin.sin_addr, ret, sizeof ret);
break;
#ifdef HAS_INET6_STRUCTS
case AF_INET6:
inet_ntop(AF_INET6, &u.sin6.sin6_addr, ret, sizeof ret);
break;
#endif
default:
sprintf(ret, "[af%d]", u.sin.sin_family);
break;
}
if (size > 0U) {
strncpy(buf, ret, size - 1);
buf[size - 1] = '0';
}
return (buf);
}
/*%
* routines to convert between on-the-wire RR format and zone file format.
* Does not contain conversion to/from decimal degrees; divide or multiply
* by 60*60*1000 for that.
*/
static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
1000000,10000000,100000000,1000000000};
/*% takes an XeY precision/size value, returns a string representation. */
static const char *
precsize_ntoa(u_int8_t prec)
{
char *retbuf = precsize_ntoa_retbuf;
unsigned long val;
int mantissa, exponent;
mantissa = (int)((prec >> 4) & 0x0f) % 10;
exponent = (int)((prec >> 0) & 0x0f) % 10;
val = mantissa * poweroften[exponent];
(void) sprintf(retbuf, "%lu.%.2lu", val/100, val%100);
return (retbuf);
}
/*% converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer. */
static u_int8_t
precsize_aton(const char **strptr) {
unsigned int mval = 0, cmval = 0;
u_int8_t retval = 0;
const char *cp;
int exponent;
int mantissa;
cp = *strptr;
while (isdigit((unsigned char)*cp))
mval = mval * 10 + (*cp++ - '0');
if (*cp == '.') { /*%< centimeters */
cp++;
if (isdigit((unsigned char)*cp)) {
cmval = (*cp++ - '0') * 10;
if (isdigit((unsigned char)*cp)) {
cmval += (*cp++ - '0');
}
}
}
cmval = (mval * 100) + cmval;
for (exponent = 0; exponent < 9; exponent++)
if (cmval < poweroften[exponent+1])
break;
mantissa = cmval / poweroften[exponent];
if (mantissa > 9)
mantissa = 9;
retval = (mantissa << 4) | exponent;
*strptr = cp;
return (retval);
}
/*% converts ascii lat/lon to unsigned encoded 32-bit number. moves pointer. */
static u_int32_t
latlon2ul(const char **latlonstrptr, int *which) {
const char *cp;
u_int32_t retval;
int deg = 0, min = 0, secs = 0, secsfrac = 0;
cp = *latlonstrptr;
while (isdigit((unsigned char)*cp))
deg = deg * 10 + (*cp++ - '0');
while (isspace((unsigned char)*cp))
cp++;
if (!(isdigit((unsigned char)*cp)))
goto fndhemi;
while (isdigit((unsigned char)*cp))
min = min * 10 + (*cp++ - '0');
while (isspace((unsigned char)*cp))
cp++;
if (!(isdigit((unsigned char)*cp)))
goto fndhemi;
while (isdigit((unsigned char)*cp))
secs = secs * 10 + (*cp++ - '0');
if (*cp == '.') { /*%< decimal seconds */
cp++;
if (isdigit((unsigned char)*cp)) {
secsfrac = (*cp++ - '0') * 100;
if (isdigit((unsigned char)*cp)) {
secsfrac += (*cp++ - '0') * 10;
if (isdigit((unsigned char)*cp)) {
secsfrac += (*cp++ - '0');
}
}
}
}
while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
cp++;
while (isspace((unsigned char)*cp))
cp++;
fndhemi:
switch (*cp) {
case 'N': case 'n':
case 'E': case 'e':
retval = ((unsigned)1<<31)
+ (((((deg * 60) + min) * 60) + secs) * 1000)
+ secsfrac;
break;
case 'S': case 's':
case 'W': case 'w':
retval = ((unsigned)1<<31)
- (((((deg * 60) + min) * 60) + secs) * 1000)
- secsfrac;
break;
default:
retval = 0; /*%< invalid value -- indicates error */
break;
}
switch (*cp) {
case 'N': case 'n':
case 'S': case 's':
*which = 1; /*%< latitude */
break;
case 'E': case 'e':
case 'W': case 'w':
*which = 2; /*%< longitude */
break;
default:
*which = 0; /*%< error */
break;
}
cp++; /*%< skip the hemisphere */
while (!isspace((unsigned char)*cp)) /*%< if any trailing garbage */
cp++;
while (isspace((unsigned char)*cp)) /*%< move to next field */
cp++;
*latlonstrptr = cp;
return (retval);
}
/*%
* converts a zone file representation in a string to an RDATA on-the-wire
* representation. */
int
loc_aton(const char *ascii, u_char *binary)
{
const char *cp, *maxcp;
u_char *bcp;
u_int32_t latit = 0, longit = 0, alt = 0;
u_int32_t lltemp1 = 0, lltemp2 = 0;
int altmeters = 0, altfrac = 0, altsign = 1;
u_int8_t hp = 0x16; /*%< default = 1e6 cm = 10000.00m = 10km */
u_int8_t vp = 0x13; /*%< default = 1e3 cm = 10.00m */
u_int8_t siz = 0x12; /*%< default = 1e2 cm = 1.00m */
int which1 = 0, which2 = 0;
cp = ascii;
maxcp = cp + strlen(ascii);
lltemp1 = latlon2ul(&cp, &which1);
lltemp2 = latlon2ul(&cp, &which2);
switch (which1 + which2) {
case 3: /*%< 1 + 2, the only valid combination */
if ((which1 == 1) && (which2 == 2)) { /*%< normal case */
latit = lltemp1;
longit = lltemp2;
} else if ((which1 == 2) && (which2 == 1)) { /*%< reversed */
longit = lltemp1;
latit = lltemp2;
} else { /*%< some kind of brokenness */
return (0);
}
break;
default: /*%< we didn't get one of each */
return (0);
}
/* altitude */
if (*cp == '-') {
altsign = -1;
cp++;
}
if (*cp == '+')
cp++;
while (isdigit((unsigned char)*cp))
altmeters = altmeters * 10 + (*cp++ - '0');
if (*cp == '.') { /*%< decimal meters */
cp++;
if (isdigit((unsigned char)*cp)) {
altfrac = (*cp++ - '0') * 10;
if (isdigit((unsigned char)*cp)) {
altfrac += (*cp++ - '0');
}
}
}
alt = (10000000 + (altsign * (altmeters * 100 + altfrac)));
while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
cp++;
while (isspace((unsigned char)*cp) && (cp < maxcp))
cp++;
if (cp >= maxcp)
goto defaults;
siz = precsize_aton(&cp);
while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
cp++;
while (isspace((unsigned char)*cp) && (cp < maxcp))
cp++;
if (cp >= maxcp)
goto defaults;
hp = precsize_aton(&cp);
while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
cp++;
while (isspace((unsigned char)*cp) && (cp < maxcp))
cp++;
if (cp >= maxcp)
goto defaults;
vp = precsize_aton(&cp);
defaults:
bcp = binary;
*bcp++ = (u_int8_t) 0; /*%< version byte */
*bcp++ = siz;
*bcp++ = hp;
*bcp++ = vp;
PUTLONG(latit,bcp);
PUTLONG(longit,bcp);
PUTLONG(alt,bcp);
return (16); /*%< size of RR in octets */
}
/*% takes an on-the-wire LOC RR and formats it in a human readable format. */
const char *
loc_ntoa(const u_char *binary, char *ascii)
{
static const char *error = "?";
static char tmpbuf[sizeof
"1000 60 60.000 N 1000 60 60.000 W -12345678.00m 90000000.00m 90000000.00m 90000000.00m"];
const u_char *cp = binary;
int latdeg, latmin, latsec, latsecfrac;
int longdeg, longmin, longsec, longsecfrac;
char northsouth, eastwest;
const char *altsign;
int altmeters, altfrac;
const u_int32_t referencealt = 100000 * 100;
int32_t latval, longval, altval;
u_int32_t templ;
u_int8_t sizeval, hpval, vpval, versionval;
char *sizestr, *hpstr, *vpstr;
versionval = *cp++;
if (ascii == NULL)
ascii = tmpbuf;
if (versionval) {
(void) sprintf(ascii, "; error: unknown LOC RR version");
return (ascii);
}
sizeval = *cp++;
hpval = *cp++;
vpval = *cp++;
GETLONG(templ, cp);
latval = (templ - ((unsigned)1<<31));
GETLONG(templ, cp);
longval = (templ - ((unsigned)1<<31));
GETLONG(templ, cp);
if (templ < referencealt) { /*%< below WGS 84 spheroid */
altval = referencealt - templ;
altsign = "-";
} else {
altval = templ - referencealt;
altsign = "";
}
if (latval < 0) {
northsouth = 'S';
latval = -latval;
} else
northsouth = 'N';
latsecfrac = latval % 1000;
latval = latval / 1000;
latsec = latval % 60;
latval = latval / 60;
latmin = latval % 60;
latval = latval / 60;
latdeg = latval;
if (longval < 0) {
eastwest = 'W';
longval = -longval;
} else
eastwest = 'E';
longsecfrac = longval % 1000;
longval = longval / 1000;
longsec = longval % 60;
longval = longval / 60;
longmin = longval % 60;
longval = longval / 60;
longdeg = longval;
altfrac = altval % 100;
altmeters = (altval / 100);
sizestr = strdup(precsize_ntoa(sizeval));
hpstr = strdup(precsize_ntoa(hpval));
vpstr = strdup(precsize_ntoa(vpval));
sprintf(ascii,
"%d %.2d %.2d.%.3d %c %d %.2d %.2d.%.3d %c %s%d.%.2dm %sm %sm %sm",
latdeg, latmin, latsec, latsecfrac, northsouth,
longdeg, longmin, longsec, longsecfrac, eastwest,
altsign, altmeters, altfrac,
(sizestr != NULL) ? sizestr : error,
(hpstr != NULL) ? hpstr : error,
(vpstr != NULL) ? vpstr : error);
if (sizestr != NULL)
free(sizestr);
if (hpstr != NULL)
free(hpstr);
if (vpstr != NULL)
free(vpstr);
return (ascii);
}
/*% Return the number of DNS hierarchy levels in the name. */
int
dn_count_labels(const char *name) {
int i, len, count;
len = strlen(name);
for (i = 0, count = 0; i < len; i++) {
/* XXX need to check for \. or use named's nlabels(). */
if (name[i] == '.')
count++;
}
/* don't count initial wildcard */
if (name[0] == '*')
if (count)
count--;
/* don't count the null label for root. */
/* if terminating '.' not found, must adjust */
/* count to include last label */
if (len > 0 && name[len-1] != '.')
count++;
return (count);
}
/*%
* Make dates expressed in seconds-since-Jan-1-1970 easy to read.
* SIG records are required to be printed like this, by the Secure DNS RFC.
*/
char *
p_secstodate (u_long secs) {
char *output = p_secstodate_output;
time_t clock = secs;
struct tm *time;
#ifdef HAVE_TIME_R
struct tm res;
time = gmtime_r(&clock, &res);
#else
time = gmtime(&clock);
#endif
time->tm_year += 1900;
time->tm_mon += 1;
sprintf(output, "%04d%02d%02d%02d%02d%02d",
time->tm_year, time->tm_mon, time->tm_mday,
time->tm_hour, time->tm_min, time->tm_sec);
return (output);
}
u_int16_t
res_nametoclass(const char *buf, int *successp) {
unsigned long result;
char *endptr;
int success;
result = sym_ston(__p_class_syms, buf, &success);
if (success)
goto done;
if (strncasecmp(buf, "CLASS", 5) != 0 ||
!isdigit((unsigned char)buf[5]))
goto done;
errno = 0;
result = strtoul(buf + 5, &endptr, 10);
if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
success = 1;
done:
if (successp)
*successp = success;
return (result);
}
u_int16_t
res_nametotype(const char *buf, int *successp) {
unsigned long result;
char *endptr;
int success;
result = sym_ston(__p_type_syms, buf, &success);
if (success)
goto done;
if (strncasecmp(buf, "type", 4) != 0 ||
!isdigit((unsigned char)buf[4]))
goto done;
errno = 0;
result = strtoul(buf + 4, &endptr, 10);
if (errno == 0 && *endptr == '\0' && result <= 0xffffU)
success = 1;
done:
if (successp)
*successp = success;
return (result);
}
/*
* Weak aliases for applications that use certain private entry points,
* and fail to include <resolv.h>.
*/
#undef fp_resstat
__weak_reference(__fp_resstat, fp_resstat);
#undef p_fqnname
__weak_reference(__p_fqnname, p_fqnname);
#undef sym_ston
__weak_reference(__sym_ston, sym_ston);
#undef sym_ntos
__weak_reference(__sym_ntos, sym_ntos);
#undef sym_ntop
__weak_reference(__sym_ntop, sym_ntop);
#undef dn_count_labels
__weak_reference(__dn_count_labels, dn_count_labels);
#undef p_secstodate
__weak_reference(__p_secstodate, p_secstodate);
/*! \file */
diff --git a/lib/libc/resolv/res_findzonecut.c b/lib/libc/resolv/res_findzonecut.c
index f1caaa76505f..812fad3cfb64 100644
--- a/lib/libc/resolv/res_findzonecut.c
+++ b/lib/libc/resolv/res_findzonecut.c
@@ -1,727 +1,726 @@
#if !defined(lint) && !defined(SABER)
static const char rcsid[] = "$Id: res_findzonecut.c,v 1.10 2005/10/11 00:10:16 marka Exp $";
#endif /* not lint */
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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 <sys/cdefs.h>
/* Import. */
#include "port_before.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <isc/list.h>
#include "port_after.h"
#include <resolv.h>
/* Data structures. */
typedef struct rr_a {
LINK(struct rr_a) link;
union res_sockaddr_union addr;
} rr_a;
typedef LIST(rr_a) rrset_a;
typedef struct rr_ns {
LINK(struct rr_ns) link;
const char * name;
unsigned int flags;
rrset_a addrs;
} rr_ns;
typedef LIST(rr_ns) rrset_ns;
#define RR_NS_HAVE_V4 0x01
#define RR_NS_HAVE_V6 0x02
/* Forward. */
static int satisfy(res_state, const char *, rrset_ns *,
union res_sockaddr_union *, int);
static int add_addrs(res_state, rr_ns *,
union res_sockaddr_union *, int);
static int get_soa(res_state, const char *, ns_class, int,
char *, size_t, char *, size_t,
rrset_ns *);
static int get_ns(res_state, const char *, ns_class, int, rrset_ns *);
static int get_glue(res_state, ns_class, int, rrset_ns *);
static int save_ns(res_state, ns_msg *, ns_sect,
const char *, ns_class, int, rrset_ns *);
static int save_a(res_state, ns_msg *, ns_sect,
const char *, ns_class, int, rr_ns *);
static void free_nsrrset(rrset_ns *);
static void free_nsrr(rrset_ns *, rr_ns *);
static rr_ns * find_ns(rrset_ns *, const char *);
static int do_query(res_state, const char *, ns_class, ns_type,
u_char *, ns_msg *);
static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
/* Macros. */
#define DPRINTF(x) do {\
int save_errno = errno; \
if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
errno = save_errno; \
} while (0)
/* Public. */
/*%
* find enclosing zone for a <dname,class>, and some server addresses
*
* parameters:
*\li res - resolver context to work within (is modified)
*\li dname - domain name whose enclosing zone is desired
*\li class - class of dname (and its enclosing zone)
*\li zname - found zone name
*\li zsize - allocated size of zname
*\li addrs - found server addresses
*\li naddrs - max number of addrs
*
* return values:
*\li < 0 - an error occurred (check errno)
*\li = 0 - zname is now valid, but addrs[] wasn't changed
*\li > 0 - zname is now valid, and return value is number of addrs[] found
*
* notes:
*\li this function calls res_nsend() which means it depends on correctly
* functioning recursive nameservers (usually defined in /etc/resolv.conf
* or its local equivalent).
*
*\li we start by asking for an SOA<dname,class>. if we get one as an
* answer, that just means <dname,class> is a zone top, which is fine.
* more than likely we'll be told to go pound sand, in the form of a
* negative answer.
*
*\li note that we are not prepared to deal with referrals since that would
* only come from authority servers and our correctly functioning local
* recursive server would have followed the referral and got us something
* more definite.
*
*\li if the authority section contains an SOA, this SOA should also be the
* closest enclosing zone, since any intermediary zone cuts would've been
* returned as referrals and dealt with by our correctly functioning local
* recursive name server. but an SOA in the authority section should NOT
* match our dname (since that would have been returned in the answer
* section). an authority section SOA has to be "above" our dname.
*
*\li however, since authority section SOA's were once optional, it's
* possible that we'll have to go hunting for the enclosing SOA by
* ripping labels off the front of our dname -- this is known as "doing
* it the hard way."
*
*\li ultimately we want some server addresses, which are ideally the ones
* pertaining to the SOA.MNAME, but only if there is a matching NS RR.
* so the second phase (after we find an SOA) is to go looking for the
* NS RRset for that SOA's zone.
*
*\li no answer section processed by this code is allowed to contain CNAME
* or DNAME RR's. for the SOA query this means we strip a label and
* keep going. for the NS and A queries this means we just give up.
*/
#ifndef _LIBC
int
res_findzonecut(res_state statp, const char *dname, ns_class class, int opts,
char *zname, size_t zsize, struct in_addr *addrs, int naddrs)
{
int result, i;
union res_sockaddr_union *u;
opts |= RES_IPV4ONLY;
opts &= ~RES_IPV6ONLY;
u = calloc(naddrs, sizeof(*u));
if (u == NULL)
return(-1);
result = res_findzonecut2(statp, dname, class, opts, zname, zsize,
u, naddrs);
for (i = 0; i < result; i++) {
addrs[i] = u[i].sin.sin_addr;
}
free(u);
return (result);
}
#endif
int
res_findzonecut2(res_state statp, const char *dname, ns_class class, int opts,
char *zname, size_t zsize, union res_sockaddr_union *addrs,
int naddrs)
{
char mname[NS_MAXDNAME];
u_long save_pfcode;
rrset_ns nsrrs;
int n;
DPRINTF(("START dname='%s' class=%s, zsize=%ld, naddrs=%d",
dname, p_class(class), (long)zsize, naddrs));
save_pfcode = statp->pfcode;
statp->pfcode |= RES_PRF_HEAD2 | RES_PRF_HEAD1 | RES_PRF_HEADX |
RES_PRF_QUES | RES_PRF_ANS |
RES_PRF_AUTH | RES_PRF_ADD;
INIT_LIST(nsrrs);
DPRINTF(("get the soa, and see if it has enough glue"));
if ((n = get_soa(statp, dname, class, opts, zname, zsize,
mname, sizeof mname, &nsrrs)) < 0 ||
((opts & RES_EXHAUSTIVE) == 0 &&
(n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
goto done;
DPRINTF(("get the ns rrset and see if it has enough glue"));
if ((n = get_ns(statp, zname, class, opts, &nsrrs)) < 0 ||
((opts & RES_EXHAUSTIVE) == 0 &&
(n = satisfy(statp, mname, &nsrrs, addrs, naddrs)) > 0))
goto done;
DPRINTF(("get the missing glue and see if it's finally enough"));
if ((n = get_glue(statp, class, opts, &nsrrs)) >= 0)
n = satisfy(statp, mname, &nsrrs, addrs, naddrs);
done:
DPRINTF(("FINISH n=%d (%s)", n, (n < 0) ? strerror(errno) : "OK"));
free_nsrrset(&nsrrs);
statp->pfcode = save_pfcode;
return (n);
}
/* Private. */
static int
satisfy(res_state statp, const char *mname, rrset_ns *nsrrsp,
union res_sockaddr_union *addrs, int naddrs)
{
rr_ns *nsrr;
int n, x;
n = 0;
nsrr = find_ns(nsrrsp, mname);
if (nsrr != NULL) {
x = add_addrs(statp, nsrr, addrs, naddrs);
addrs += x;
naddrs -= x;
n += x;
}
for (nsrr = HEAD(*nsrrsp);
nsrr != NULL && naddrs > 0;
nsrr = NEXT(nsrr, link))
if (ns_samename(nsrr->name, mname) != 1) {
x = add_addrs(statp, nsrr, addrs, naddrs);
addrs += x;
naddrs -= x;
n += x;
}
DPRINTF(("satisfy(%s): %d", mname, n));
return (n);
}
static int
add_addrs(res_state statp, rr_ns *nsrr,
union res_sockaddr_union *addrs, int naddrs)
{
rr_a *arr;
int n = 0;
for (arr = HEAD(nsrr->addrs); arr != NULL; arr = NEXT(arr, link)) {
if (naddrs <= 0)
return (0);
*addrs++ = arr->addr;
naddrs--;
n++;
}
DPRINTF(("add_addrs: %d", n));
return (n);
}
static int
get_soa(res_state statp, const char *dname, ns_class class, int opts,
char *zname, size_t zsize, char *mname, size_t msize,
rrset_ns *nsrrsp)
{
char tname[NS_MAXDNAME];
u_char *resp = NULL;
int n, i, ancount, nscount;
ns_sect sect;
ns_msg msg;
u_int rcode;
/*
* Find closest enclosing SOA, even if it's for the root zone.
*/
/* First canonicalize dname (exactly one unescaped trailing "."). */
if (ns_makecanon(dname, tname, sizeof tname) < 0)
goto cleanup;
dname = tname;
resp = malloc(NS_MAXMSG);
if (resp == NULL)
goto cleanup;
/* Now grovel the subdomains, hunting for an SOA answer or auth. */
for (;;) {
/* Leading or inter-label '.' are skipped here. */
while (*dname == '.')
dname++;
/* Is there an SOA? */
n = do_query(statp, dname, class, ns_t_soa, resp, &msg);
if (n < 0) {
DPRINTF(("get_soa: do_query('%s', %s) failed (%d)",
dname, p_class(class), n));
goto cleanup;
}
if (n > 0) {
DPRINTF(("get_soa: CNAME or DNAME found"));
sect = ns_s_max, n = 0;
} else {
rcode = ns_msg_getflag(msg, ns_f_rcode);
ancount = ns_msg_count(msg, ns_s_an);
nscount = ns_msg_count(msg, ns_s_ns);
if (ancount > 0 && rcode == ns_r_noerror)
sect = ns_s_an, n = ancount;
else if (nscount > 0)
sect = ns_s_ns, n = nscount;
else
sect = ns_s_max, n = 0;
}
for (i = 0; i < n; i++) {
const char *t;
const u_char *rdata;
ns_rr rr;
if (ns_parserr(&msg, sect, i, &rr) < 0) {
DPRINTF(("get_soa: ns_parserr(%s, %d) failed",
p_section(sect, ns_o_query), i));
goto cleanup;
}
if (ns_rr_type(rr) == ns_t_cname ||
ns_rr_type(rr) == ns_t_dname)
break;
if (ns_rr_type(rr) != ns_t_soa ||
ns_rr_class(rr) != class)
continue;
t = ns_rr_name(rr);
switch (sect) {
case ns_s_an:
if (ns_samedomain(dname, t) == 0) {
DPRINTF(
("get_soa: ns_samedomain('%s', '%s') == 0",
dname, t)
);
errno = EPROTOTYPE;
goto cleanup;
}
break;
case ns_s_ns:
if (ns_samename(dname, t) == 1 ||
ns_samedomain(dname, t) == 0) {
DPRINTF(
("get_soa: ns_samename() || !ns_samedomain('%s', '%s')",
dname, t)
);
errno = EPROTOTYPE;
goto cleanup;
}
break;
default:
abort();
}
if (strlen(t) + 1 > zsize) {
DPRINTF(("get_soa: zname(%lu) too small (%lu)",
(unsigned long)zsize,
(unsigned long)strlen(t) + 1));
errno = EMSGSIZE;
goto cleanup;
}
strcpy(zname, t);
rdata = ns_rr_rdata(rr);
if (ns_name_uncompress(resp, ns_msg_end(msg), rdata,
mname, msize) < 0) {
DPRINTF(("get_soa: ns_name_uncompress failed")
);
goto cleanup;
}
if (save_ns(statp, &msg, ns_s_ns,
zname, class, opts, nsrrsp) < 0) {
DPRINTF(("get_soa: save_ns failed"));
goto cleanup;
}
free(resp);
return (0);
}
/* If we're out of labels, then not even "." has an SOA! */
if (*dname == '\0')
break;
/* Find label-terminating "."; top of loop will skip it. */
while (*dname != '.') {
if (*dname == '\\')
if (*++dname == '\0') {
errno = EMSGSIZE;
goto cleanup;
}
dname++;
}
}
DPRINTF(("get_soa: out of labels"));
errno = EDESTADDRREQ;
cleanup:
if (resp != NULL)
free(resp);
return (-1);
}
static int
get_ns(res_state statp, const char *zname, ns_class class, int opts,
rrset_ns *nsrrsp)
{
u_char *resp;
ns_msg msg;
int n;
resp = malloc(NS_MAXMSG);
if (resp == NULL)
return (-1);
/* Go and get the NS RRs for this zone. */
n = do_query(statp, zname, class, ns_t_ns, resp, &msg);
if (n != 0) {
DPRINTF(("get_ns: do_query('%s', %s) failed (%d)",
zname, p_class(class), n));
free(resp);
return (-1);
}
/* Remember the NS RRs and associated A RRs that came back. */
if (save_ns(statp, &msg, ns_s_an, zname, class, opts, nsrrsp) < 0) {
DPRINTF(("get_ns save_ns('%s', %s) failed",
zname, p_class(class)));
free(resp);
return (-1);
}
free(resp);
return (0);
}
static int
get_glue(res_state statp, ns_class class, int opts, rrset_ns *nsrrsp) {
rr_ns *nsrr, *nsrr_n;
u_char *resp;
resp = malloc(NS_MAXMSG);
if (resp == NULL)
return(-1);
/* Go and get the A RRs for each empty NS RR on our list. */
for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = nsrr_n) {
ns_msg msg;
int n;
nsrr_n = NEXT(nsrr, link);
if ((nsrr->flags & RR_NS_HAVE_V4) == 0) {
n = do_query(statp, nsrr->name, class, ns_t_a,
resp, &msg);
if (n < 0) {
DPRINTF(
("get_glue: do_query('%s', %s') failed",
nsrr->name, p_class(class)));
goto cleanup;
}
if (n > 0) {
DPRINTF((
"get_glue: do_query('%s', %s') CNAME or DNAME found",
nsrr->name, p_class(class)));
}
if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
opts, nsrr) < 0) {
DPRINTF(("get_glue: save_r('%s', %s) failed",
nsrr->name, p_class(class)));
goto cleanup;
}
}
if ((nsrr->flags & RR_NS_HAVE_V6) == 0) {
n = do_query(statp, nsrr->name, class, ns_t_aaaa,
resp, &msg);
if (n < 0) {
DPRINTF(
("get_glue: do_query('%s', %s') failed",
nsrr->name, p_class(class)));
goto cleanup;
}
if (n > 0) {
DPRINTF((
"get_glue: do_query('%s', %s') CNAME or DNAME found",
nsrr->name, p_class(class)));
}
if (save_a(statp, &msg, ns_s_an, nsrr->name, class,
opts, nsrr) < 0) {
DPRINTF(("get_glue: save_r('%s', %s) failed",
nsrr->name, p_class(class)));
goto cleanup;
}
}
/* If it's still empty, it's just chaff. */
if (EMPTY(nsrr->addrs)) {
DPRINTF(("get_glue: removing empty '%s' NS",
nsrr->name));
free_nsrr(nsrrsp, nsrr);
}
}
free(resp);
return (0);
cleanup:
free(resp);
return (-1);
}
static int
save_ns(res_state statp, ns_msg *msg, ns_sect sect,
const char *owner, ns_class class, int opts,
rrset_ns *nsrrsp)
{
int i;
for (i = 0; i < ns_msg_count(*msg, sect); i++) {
char tname[MAXDNAME];
const u_char *rdata;
rr_ns *nsrr;
ns_rr rr;
if (ns_parserr(msg, sect, i, &rr) < 0) {
DPRINTF(("save_ns: ns_parserr(%s, %d) failed",
p_section(sect, ns_o_query), i));
return (-1);
}
if (ns_rr_type(rr) != ns_t_ns ||
ns_rr_class(rr) != class ||
ns_samename(ns_rr_name(rr), owner) != 1)
continue;
nsrr = find_ns(nsrrsp, ns_rr_name(rr));
if (nsrr == NULL) {
nsrr = malloc(sizeof *nsrr);
if (nsrr == NULL) {
DPRINTF(("save_ns: malloc failed"));
return (-1);
}
rdata = ns_rr_rdata(rr);
if (ns_name_uncompress(ns_msg_base(*msg),
ns_msg_end(*msg), rdata,
tname, sizeof tname) < 0) {
DPRINTF(("save_ns: ns_name_uncompress failed")
);
free(nsrr);
return (-1);
}
nsrr->name = strdup(tname);
if (nsrr->name == NULL) {
DPRINTF(("save_ns: strdup failed"));
free(nsrr);
return (-1);
}
INIT_LINK(nsrr, link);
INIT_LIST(nsrr->addrs);
nsrr->flags = 0;
APPEND(*nsrrsp, nsrr, link);
}
if (save_a(statp, msg, ns_s_ar,
nsrr->name, class, opts, nsrr) < 0) {
DPRINTF(("save_ns: save_r('%s', %s) failed",
nsrr->name, p_class(class)));
return (-1);
}
}
return (0);
}
static int
save_a(res_state statp, ns_msg *msg, ns_sect sect,
const char *owner, ns_class class, int opts,
rr_ns *nsrr)
{
int i;
for (i = 0; i < ns_msg_count(*msg, sect); i++) {
ns_rr rr;
rr_a *arr;
if (ns_parserr(msg, sect, i, &rr) < 0) {
DPRINTF(("save_a: ns_parserr(%s, %d) failed",
p_section(sect, ns_o_query), i));
return (-1);
}
if ((ns_rr_type(rr) != ns_t_a &&
ns_rr_type(rr) != ns_t_aaaa) ||
ns_rr_class(rr) != class ||
ns_samename(ns_rr_name(rr), owner) != 1 ||
ns_rr_rdlen(rr) != NS_INADDRSZ)
continue;
if ((opts & RES_IPV6ONLY) != 0 && ns_rr_type(rr) != ns_t_aaaa)
continue;
if ((opts & RES_IPV4ONLY) != 0 && ns_rr_type(rr) != ns_t_a)
continue;
arr = malloc(sizeof *arr);
if (arr == NULL) {
DPRINTF(("save_a: malloc failed"));
return (-1);
}
INIT_LINK(arr, link);
memset(&arr->addr, 0, sizeof(arr->addr));
switch (ns_rr_type(rr)) {
case ns_t_a:
arr->addr.sin.sin_family = AF_INET;
#ifdef HAVE_SA_LEN
arr->addr.sin.sin_len = sizeof(arr->addr.sin);
#endif
memcpy(&arr->addr.sin.sin_addr, ns_rr_rdata(rr),
NS_INADDRSZ);
arr->addr.sin.sin_port = htons(NAMESERVER_PORT);
nsrr->flags |= RR_NS_HAVE_V4;
break;
case ns_t_aaaa:
arr->addr.sin6.sin6_family = AF_INET6;
#ifdef HAVE_SA_LEN
arr->addr.sin6.sin6_len = sizeof(arr->addr.sin6);
#endif
memcpy(&arr->addr.sin6.sin6_addr, ns_rr_rdata(rr), 16);
arr->addr.sin6.sin6_port = htons(NAMESERVER_PORT);
nsrr->flags |= RR_NS_HAVE_V6;
break;
default:
abort();
}
APPEND(nsrr->addrs, arr, link);
}
return (0);
}
static void
free_nsrrset(rrset_ns *nsrrsp) {
rr_ns *nsrr;
while ((nsrr = HEAD(*nsrrsp)) != NULL)
free_nsrr(nsrrsp, nsrr);
}
static void
free_nsrr(rrset_ns *nsrrsp, rr_ns *nsrr) {
rr_a *arr;
char *tmp;
while ((arr = HEAD(nsrr->addrs)) != NULL) {
UNLINK(nsrr->addrs, arr, link);
free(arr);
}
DE_CONST(nsrr->name, tmp);
free(tmp);
UNLINK(*nsrrsp, nsrr, link);
free(nsrr);
}
static rr_ns *
find_ns(rrset_ns *nsrrsp, const char *dname) {
rr_ns *nsrr;
for (nsrr = HEAD(*nsrrsp); nsrr != NULL; nsrr = NEXT(nsrr, link))
if (ns_samename(nsrr->name, dname) == 1)
return (nsrr);
return (NULL);
}
static int
do_query(res_state statp, const char *dname, ns_class class, ns_type qtype,
u_char *resp, ns_msg *msg)
{
u_char req[NS_PACKETSZ];
int i, n;
n = res_nmkquery(statp, ns_o_query, dname, class, qtype,
NULL, 0, NULL, req, NS_PACKETSZ);
if (n < 0) {
DPRINTF(("do_query: res_nmkquery failed"));
return (-1);
}
n = res_nsend(statp, req, n, resp, NS_MAXMSG);
if (n < 0) {
DPRINTF(("do_query: res_nsend failed"));
return (-1);
}
if (n == 0) {
DPRINTF(("do_query: res_nsend returned 0"));
errno = EMSGSIZE;
return (-1);
}
if (ns_initparse(resp, n, msg) < 0) {
DPRINTF(("do_query: ns_initparse failed"));
return (-1);
}
n = 0;
for (i = 0; i < ns_msg_count(*msg, ns_s_an); i++) {
ns_rr rr;
if (ns_parserr(msg, ns_s_an, i, &rr) < 0) {
DPRINTF(("do_query: ns_parserr failed"));
return (-1);
}
n += (ns_rr_class(rr) == class &&
(ns_rr_type(rr) == ns_t_cname ||
ns_rr_type(rr) == ns_t_dname));
}
return (n);
}
static void
res_dprintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
fputs(";; res_findzonecut: ", stderr);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
}
/*! \file */
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index aede91e889c1..f221d75ce972 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -1,942 +1,941 @@
/*-
* SPDX-License-Identifier: (BSD-3-Clause AND ISC)
*
* Copyright (c) 1985, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
*/
/*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
static const char rcsid[] = "$Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include "namespace.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#ifndef HAVE_MD5
# include "../dst/md5.h"
#else
# ifdef SOLARIS2
# include <sys/md5.h>
# elif _LIBC
# include <md5.h>
# endif
#endif
#ifndef _MD5_H_
# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
#endif
#include "un-namespace.h"
#include "port_after.h"
/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */
#include <resolv.h>
#include "res_private.h"
/*% Options. Should all be left alone. */
#define RESOLVSORT
#ifndef DEBUG
#define DEBUG
#endif
#ifdef SOLARIS2
#include <sys/systeminfo.h>
#endif
static void res_setoptions(res_state, const char *, const char *);
#ifdef RESOLVSORT
static const char sort_mask[] = "/&";
#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL)
static u_int32_t net_mask(struct in_addr);
#endif
#if !defined(isascii) /*%< XXX - could be a function */
# define isascii(c) (!(c & 0200))
#endif
/*
* Resolver state default settings.
*/
/*%
* Set up default settings. If the configuration file exist, the values
* there will have precedence. Otherwise, the server address is set to
* INADDR_ANY and the default domain name comes from the gethostname().
*
* An interim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
* rather than INADDR_ANY ("0.0.0.0") as the default name server address
* since it was noted that INADDR_ANY actually meant ``the first interface
* you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
* it had to be "up" in order for you to reach your own name server. It
* was later decided that since the recommended practice is to always
* install local static routes through 127.0.0.1 for all your network
* interfaces, that we could solve this problem without a code change.
*
* The configuration file should always be used, since it is the only way
* to specify a default domain. If you are running a server on your local
* machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
* in the configuration file.
*
* Return 0 if completes successfully, -1 on error
*/
int
res_ninit(res_state statp) {
extern int __res_vinit(res_state, int);
return (__res_vinit(statp, 0));
}
/*% This function has to be reachable by res_data.c but not publicly. */
int
__res_vinit(res_state statp, int preinit) {
FILE *fp;
char *cp, **pp;
int n;
char buf[BUFSIZ];
int nserv = 0; /*%< number of nameserver records read from file */
int haveenv = 0;
int havesearch = 0;
#ifdef RESOLVSORT
int nsort = 0;
char *net;
#endif
int dots;
union res_sockaddr_union u[2];
int maxns = MAXNS;
RES_SET_H_ERRNO(statp, 0);
if (statp->_u._ext.ext != NULL)
res_ndestroy(statp);
if (!preinit) {
statp->retrans = RES_TIMEOUT;
statp->retry = RES_DFLRETRY;
statp->options = RES_DEFAULT;
}
statp->_rnd = malloc(16);
res_rndinit(statp);
statp->id = res_nrandomid(statp);
memset(u, 0, sizeof(u));
u[nserv].sin.sin_addr.s_addr = INADDR_ANY;
u[nserv].sin.sin_family = AF_INET;
u[nserv].sin.sin_port = htons(NAMESERVER_PORT);
#ifdef HAVE_SA_LEN
u[nserv].sin.sin_len = sizeof(struct sockaddr_in);
#endif
nserv++;
#ifdef HAS_INET6_STRUCTS
u[nserv].sin6.sin6_addr = in6addr_any;
u[nserv].sin6.sin6_family = AF_INET6;
u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT);
#ifdef HAVE_SA_LEN
u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6);
#endif
nserv++;
#endif
statp->nscount = 0;
statp->ndots = 1;
statp->pfcode = 0;
statp->_vcsock = -1;
statp->_flags = 0;
statp->qhook = NULL;
statp->rhook = NULL;
statp->_u._ext.nscount = 0;
statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext));
if (statp->_u._ext.ext != NULL) {
memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext));
statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr;
strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa");
strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int");
statp->_u._ext.ext->reload_period = 2;
} else {
/*
* Historically res_init() rarely, if at all, failed.
* Examples and applications exist which do not check
* our return code. Furthermore several applications
* simply call us to get the systems domainname. So
* rather then immediately fail here we store the
* failure, which is returned later, in h_errno. And
* prevent the collection of 'nameserver' information
* by setting maxns to 0. Thus applications that fail
* to check our return code wont be able to make
* queries anyhow.
*/
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
maxns = 0;
}
#ifdef RESOLVSORT
statp->nsort = 0;
#endif
res_setservers(statp, u, nserv);
#ifdef SOLARIS2
/*
* The old libresolv derived the defaultdomain from NIS/NIS+.
* We want to keep this behaviour
*/
{
char buf[sizeof(statp->defdname)], *cp;
int ret;
if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 &&
(unsigned int)ret <= sizeof(buf)) {
if (buf[0] == '+')
buf[0] = '.';
cp = strchr(buf, '.');
cp = (cp == NULL) ? buf : (cp + 1);
strncpy(statp->defdname, cp,
sizeof(statp->defdname) - 1);
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
}
}
#endif /* SOLARIS2 */
/* Allow user to override the local domain definition */
if ((cp = secure_getenv("LOCALDOMAIN")) != NULL) {
(void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
haveenv++;
/*
* Set search list to be blank-separated strings
* from rest of env value. Permits users of LOCALDOMAIN
* to still have a search list, and anyone to set the
* one that they want to use as an individual (even more
* important now that the rfc1535 stuff restricts searches)
*/
cp = statp->defdname;
pp = statp->dnsrch;
*pp++ = cp;
for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
if (*cp == '\n') /*%< silly backwards compat */
break;
else if (*cp == ' ' || *cp == '\t') {
*cp = 0;
n = 1;
} else if (n) {
*pp++ = cp;
n = 0;
havesearch = 1;
}
}
/* null terminate last domain if there are excess */
while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n')
cp++;
*cp = '\0';
*pp++ = NULL;
}
#define MATCH(line, name) \
(!strncmp(line, name, sizeof(name) - 1) && \
(line[sizeof(name) - 1] == ' ' || \
line[sizeof(name) - 1] == '\t'))
nserv = 0;
if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) {
struct stat sb;
struct timespec now;
if (statp->_u._ext.ext != NULL) {
if (_fstat(fileno(fp), &sb) == 0) {
statp->_u._ext.ext->conf_mtim = sb.st_mtim;
if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) {
statp->_u._ext.ext->conf_stat = now.tv_sec;
}
}
}
/* read the config file */
while (fgets(buf, sizeof(buf), fp) != NULL) {
/* skip comments */
if (*buf == ';' || *buf == '#')
continue;
/* read default domain name */
if (MATCH(buf, "domain")) {
if (haveenv) /*%< skip if have from environ */
continue;
cp = buf + sizeof("domain") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL)
*cp = '\0';
havesearch = 0;
continue;
}
/* set search list */
if (MATCH(buf, "search")) {
if (haveenv) /*%< skip if have from environ */
continue;
cp = buf + sizeof("search") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
if ((*cp == '\0') || (*cp == '\n'))
continue;
strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1);
statp->defdname[sizeof(statp->defdname) - 1] = '\0';
if ((cp = strchr(statp->defdname, '\n')) != NULL)
*cp = '\0';
/*
* Set search list to be blank-separated strings
* on rest of line.
*/
cp = statp->defdname;
pp = statp->dnsrch;
*pp++ = cp;
for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) {
if (*cp == ' ' || *cp == '\t') {
*cp = 0;
n = 1;
} else if (n) {
*pp++ = cp;
n = 0;
}
}
/* null terminate last domain if there are excess */
while (*cp != '\0' && *cp != ' ' && *cp != '\t')
cp++;
*cp = '\0';
*pp++ = NULL;
havesearch = 1;
continue;
}
/* read nameservers to query */
if (MATCH(buf, "nameserver") && nserv < maxns) {
struct addrinfo hints, *ai;
char sbuf[NI_MAXSERV];
const size_t minsiz =
sizeof(statp->_u._ext.ext->nsaddrs[0]);
cp = buf + sizeof("nameserver") - 1;
while (*cp == ' ' || *cp == '\t')
cp++;
cp[strcspn(cp, ";# \t\n")] = '\0';
if ((*cp != '\0') && (*cp != '\n')) {
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM; /*dummy*/
hints.ai_flags = AI_NUMERICHOST;
sprintf(sbuf, "%u", NAMESERVER_PORT);
if (getaddrinfo(cp, sbuf, &hints, &ai) == 0) {
if (ai->ai_addrlen <= minsiz) {
if (statp->_u._ext.ext != NULL) {
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
ai->ai_addr, ai->ai_addrlen);
}
if (ai->ai_addrlen <=
sizeof(statp->nsaddr_list[nserv])) {
memcpy(&statp->nsaddr_list[nserv],
ai->ai_addr, ai->ai_addrlen);
} else
statp->nsaddr_list[nserv].sin_family = 0;
nserv++;
}
freeaddrinfo(ai);
}
}
continue;
}
#ifdef RESOLVSORT
if (MATCH(buf, "sortlist")) {
struct in_addr a;
struct in6_addr a6;
int m, i;
u_char *u;
struct __res_state_ext *ext = statp->_u._ext.ext;
cp = buf + sizeof("sortlist") - 1;
while (nsort < MAXRESOLVSORT) {
while (*cp == ' ' || *cp == '\t')
cp++;
if (*cp == '\0' || *cp == '\n' || *cp == ';')
break;
net = cp;
while (*cp && !ISSORTMASK(*cp) && *cp != ';' &&
isascii(*cp) && !isspace((unsigned char)*cp))
cp++;
n = *cp;
*cp = 0;
if (inet_aton(net, &a)) {
statp->sort_list[nsort].addr = a;
if (ISSORTMASK(n)) {
*cp++ = n;
net = cp;
while (*cp && *cp != ';' &&
isascii(*cp) &&
!isspace((unsigned char)*cp))
cp++;
n = *cp;
*cp = 0;
if (inet_aton(net, &a)) {
statp->sort_list[nsort].mask = a.s_addr;
} else {
statp->sort_list[nsort].mask =
net_mask(statp->sort_list[nsort].addr);
}
} else {
statp->sort_list[nsort].mask =
net_mask(statp->sort_list[nsort].addr);
}
ext->sort_list[nsort].af = AF_INET;
ext->sort_list[nsort].addr.ina =
statp->sort_list[nsort].addr;
ext->sort_list[nsort].mask.ina.s_addr =
statp->sort_list[nsort].mask;
nsort++;
}
else if (inet_pton(AF_INET6, net, &a6) == 1) {
ext->sort_list[nsort].af = AF_INET6;
ext->sort_list[nsort].addr.in6a = a6;
u = (u_char *)&ext->sort_list[nsort].mask.in6a;
*cp++ = n;
net = cp;
while (*cp && *cp != ';' &&
isascii(*cp) && !isspace(*cp))
cp++;
m = n;
n = *cp;
*cp = 0;
switch (m) {
case '/':
m = atoi(net);
break;
case '&':
if (inet_pton(AF_INET6, net, u) == 1) {
m = -1;
break;
}
/*FALLTHROUGH*/
default:
m = sizeof(struct in6_addr) * CHAR_BIT;
break;
}
if (m >= 0) {
for (i = 0; i < sizeof(struct in6_addr); i++) {
if (m <= 0) {
*u = 0;
} else {
m -= CHAR_BIT;
*u = (u_char)~0;
if (m < 0)
*u <<= -m;
}
u++;
}
}
statp->sort_list[nsort].addr.s_addr =
(u_int32_t)0xffffffff;
statp->sort_list[nsort].mask =
(u_int32_t)0xffffffff;
nsort++;
}
*cp = n;
}
continue;
}
#endif
if (MATCH(buf, "options")) {
res_setoptions(statp, buf + sizeof("options") - 1, "conf");
continue;
}
}
if (nserv > 0)
statp->nscount = nserv;
#ifdef RESOLVSORT
statp->nsort = nsort;
#endif
(void) fclose(fp);
}
/*
* Last chance to get a nameserver. This should not normally
* be necessary
*/
#ifdef NO_RESOLV_CONF
if(nserv == 0)
nserv = get_nameservers(statp);
#endif
if (statp->defdname[0] == 0 &&
gethostname(buf, sizeof(statp->defdname) - 1) == 0 &&
(cp = strchr(buf, '.')) != NULL)
strcpy(statp->defdname, cp + 1);
/* find components of local domain that might be searched */
if (havesearch == 0) {
pp = statp->dnsrch;
*pp++ = statp->defdname;
*pp = NULL;
dots = 0;
for (cp = statp->defdname; *cp; cp++)
dots += (*cp == '.');
cp = statp->defdname;
while (pp < statp->dnsrch + MAXDFLSRCH) {
if (dots < LOCALDOMAINPARTS)
break;
cp = strchr(cp, '.') + 1; /*%< we know there is one */
*pp++ = cp;
dots--;
}
*pp = NULL;
#ifdef DEBUG
if (statp->options & RES_DEBUG) {
printf(";; res_init()... default dnsrch list:\n");
for (pp = statp->dnsrch; *pp; pp++)
printf(";;\t%s\n", *pp);
printf(";;\t..END..\n");
}
#endif
}
if (issetugid())
statp->options |= RES_NOALIASES;
else if ((cp = getenv("RES_OPTIONS")) != NULL)
res_setoptions(statp, cp, "env");
statp->options |= RES_INIT;
return (statp->res_h_errno);
}
static void
res_setoptions(res_state statp, const char *options, const char *source)
{
const char *cp = options;
int i;
struct __res_state_ext *ext = statp->_u._ext.ext;
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_setoptions(\"%s\", \"%s\")...\n",
options, source);
#endif
while (*cp) {
/* skip leading and inner runs of spaces */
while (*cp == ' ' || *cp == '\t')
cp++;
/* search for and process individual options */
if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) {
i = atoi(cp + sizeof("ndots:") - 1);
if (i <= RES_MAXNDOTS)
statp->ndots = i;
else
statp->ndots = RES_MAXNDOTS;
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";;\tndots=%d\n", statp->ndots);
#endif
} else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) {
i = atoi(cp + sizeof("timeout:") - 1);
if (i <= RES_MAXRETRANS)
statp->retrans = i;
else
statp->retrans = RES_MAXRETRANS;
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";;\ttimeout=%d\n", statp->retrans);
#endif
#ifdef SOLARIS2
} else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) {
/*
* For backward compatibility, 'retrans' is
* supported as an alias for 'timeout', though
* without an imposed maximum.
*/
statp->retrans = atoi(cp + sizeof("retrans:") - 1);
} else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){
/*
* For backward compatibility, 'retry' is
* supported as an alias for 'attempts', though
* without an imposed maximum.
*/
statp->retry = atoi(cp + sizeof("retry:") - 1);
#endif /* SOLARIS2 */
} else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){
i = atoi(cp + sizeof("attempts:") - 1);
if (i <= RES_MAXRETRY)
statp->retry = i;
else
statp->retry = RES_MAXRETRY;
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";;\tattempts=%d\n", statp->retry);
#endif
} else if (!strncmp(cp, "debug", sizeof("debug") - 1)) {
#ifdef DEBUG
if (!(statp->options & RES_DEBUG)) {
printf(";; res_setoptions(\"%s\", \"%s\")..\n",
options, source);
statp->options |= RES_DEBUG;
}
printf(";;\tdebug\n");
#endif
} else if (!strncmp(cp, "no_tld_query",
sizeof("no_tld_query") - 1) ||
!strncmp(cp, "no-tld-query",
sizeof("no-tld-query") - 1)) {
statp->options |= RES_NOTLDQUERY;
} else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) {
statp->options |= RES_USE_INET6;
} else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) {
statp->options |= RES_INSECURE1;
} else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) {
statp->options |= RES_INSECURE2;
} else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) {
statp->options |= RES_ROTATE;
} else if (!strncmp(cp, "usevc", sizeof("usevc") - 1)) {
statp->options |= RES_USEVC;
} else if (!strncmp(cp, "no-check-names",
sizeof("no-check-names") - 1)) {
statp->options |= RES_NOCHECKNAME;
} else if (!strncmp(cp, "reload-period:",
sizeof("reload-period:") - 1)) {
if (ext != NULL) {
ext->reload_period = (u_short)
atoi(cp + sizeof("reload-period:") - 1);
}
}
#ifdef RES_USE_EDNS0
else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) {
statp->options |= RES_USE_EDNS0;
}
#endif
#ifndef _LIBC
else if (!strncmp(cp, "dname", sizeof("dname") - 1)) {
statp->options |= RES_USE_DNAME;
}
else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) {
if (ext == NULL)
goto skip;
cp += sizeof("nibble:") - 1;
i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1);
strncpy(ext->nsuffix, cp, i);
ext->nsuffix[i] = '\0';
}
else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) {
if (ext == NULL)
goto skip;
cp += sizeof("nibble2:") - 1;
i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1);
strncpy(ext->nsuffix2, cp, i);
ext->nsuffix2[i] = '\0';
}
else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) {
cp += sizeof("v6revmode:") - 1;
/* "nibble" and "bitstring" used to be valid */
if (!strncmp(cp, "single", sizeof("single") - 1)) {
statp->options |= RES_NO_NIBBLE2;
} else if (!strncmp(cp, "both", sizeof("both") - 1)) {
statp->options &=
~RES_NO_NIBBLE2;
}
}
#endif
else {
/* XXX - print a warning here? */
}
#ifndef _LIBC
skip:
#endif
/* skip to next run of spaces */
while (*cp && *cp != ' ' && *cp != '\t')
cp++;
}
}
#ifdef RESOLVSORT
/* XXX - should really support CIDR which means explicit masks always. */
static u_int32_t
net_mask(struct in_addr in) /*!< XXX - should really use system's version of this */
{
u_int32_t i = ntohl(in.s_addr);
if (IN_CLASSA(i))
return (htonl(IN_CLASSA_NET));
else if (IN_CLASSB(i))
return (htonl(IN_CLASSB_NET));
return (htonl(IN_CLASSC_NET));
}
#endif
static u_char srnd[16];
void
res_rndinit(res_state statp)
{
struct timeval now;
u_int32_t u32;
u_int16_t u16;
u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
gettimeofday(&now, NULL);
u32 = now.tv_sec;
memcpy(rnd, &u32, 4);
u32 = now.tv_usec;
memcpy(rnd + 4, &u32, 4);
u32 += now.tv_sec;
memcpy(rnd + 8, &u32, 4);
u16 = getpid();
memcpy(rnd + 12, &u16, 2);
}
u_int
res_nrandomid(res_state statp) {
struct timeval now;
u_int16_t u16;
MD5_CTX ctx;
u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
gettimeofday(&now, NULL);
u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec);
memcpy(rnd + 14, &u16, 2);
#ifndef HAVE_MD5
MD5_Init(&ctx);
MD5_Update(&ctx, rnd, 16);
MD5_Final(rnd, &ctx);
#else
MD5Init(&ctx);
MD5Update(&ctx, rnd, 16);
MD5Final(rnd, &ctx);
#endif
memcpy(&u16, rnd + 14, 2);
return ((u_int) u16);
}
/*%
* This routine is for closing the socket if a virtual circuit is used and
* the program wants to close it. This provides support for endhostent()
* which expects to close the socket.
*
* This routine is not expected to be user visible.
*/
void
res_nclose(res_state statp) {
int ns;
if (statp->_vcsock >= 0) {
(void) _close(statp->_vcsock);
statp->_vcsock = -1;
statp->_flags &= ~(RES_F_VC | RES_F_CONN);
}
for (ns = 0; ns < statp->_u._ext.nscount; ns++) {
if (statp->_u._ext.nssocks[ns] != -1) {
(void) _close(statp->_u._ext.nssocks[ns]);
statp->_u._ext.nssocks[ns] = -1;
}
}
}
void
res_ndestroy(res_state statp) {
res_nclose(statp);
if (statp->_u._ext.ext != NULL) {
free(statp->_u._ext.ext);
statp->_u._ext.ext = NULL;
}
if (statp->_rnd != NULL) {
free(statp->_rnd);
statp->_rnd = NULL;
}
statp->options &= ~RES_INIT;
}
#ifndef _LIBC
const char *
res_get_nibblesuffix(res_state statp) {
if (statp->_u._ext.ext)
return (statp->_u._ext.ext->nsuffix);
return ("ip6.arpa");
}
const char *
res_get_nibblesuffix2(res_state statp) {
if (statp->_u._ext.ext)
return (statp->_u._ext.ext->nsuffix2);
return ("ip6.int");
}
#endif
void
res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) {
int i, nserv;
size_t size;
/* close open servers */
res_nclose(statp);
/* cause rtt times to be forgotten */
statp->_u._ext.nscount = 0;
nserv = 0;
for (i = 0; i < cnt && nserv < MAXNS; i++) {
switch (set->sin.sin_family) {
case AF_INET:
size = sizeof(set->sin);
if (statp->_u._ext.ext)
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
&set->sin, size);
if (size <= sizeof(statp->nsaddr_list[nserv]))
memcpy(&statp->nsaddr_list[nserv],
&set->sin, size);
else
statp->nsaddr_list[nserv].sin_family = 0;
nserv++;
break;
#ifdef HAS_INET6_STRUCTS
case AF_INET6:
size = sizeof(set->sin6);
if (statp->_u._ext.ext)
memcpy(&statp->_u._ext.ext->nsaddrs[nserv],
&set->sin6, size);
if (size <= sizeof(statp->nsaddr_list[nserv]))
memcpy(&statp->nsaddr_list[nserv],
&set->sin6, size);
else
statp->nsaddr_list[nserv].sin_family = 0;
nserv++;
break;
#endif
default:
break;
}
set++;
}
statp->nscount = nserv;
}
int
res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) {
int i;
size_t size;
u_int16_t family;
for (i = 0; i < statp->nscount && i < cnt; i++) {
if (statp->_u._ext.ext)
family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family;
else
family = statp->nsaddr_list[i].sin_family;
switch (family) {
case AF_INET:
size = sizeof(set->sin);
if (statp->_u._ext.ext)
memcpy(&set->sin,
&statp->_u._ext.ext->nsaddrs[i],
size);
else
memcpy(&set->sin, &statp->nsaddr_list[i],
size);
break;
#ifdef HAS_INET6_STRUCTS
case AF_INET6:
size = sizeof(set->sin6);
if (statp->_u._ext.ext)
memcpy(&set->sin6,
&statp->_u._ext.ext->nsaddrs[i],
size);
else
memcpy(&set->sin6, &statp->nsaddr_list[i],
size);
break;
#endif
default:
set->sin.sin_family = 0;
break;
}
set++;
}
return (statp->nscount);
}
/*! \file */
diff --git a/lib/libc/resolv/res_mkquery.c b/lib/libc/resolv/res_mkquery.c
index 40874e8d904b..a7acbd7334d3 100644
--- a/lib/libc/resolv/res_mkquery.c
+++ b/lib/libc/resolv/res_mkquery.c
@@ -1,305 +1,304 @@
/*-
* SPDX-License-Identifier: (ISC AND BSD-3-Clause)
*
* Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/*-
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_mkquery.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <string.h>
#include "port_after.h"
/* Options. Leave them on. */
#ifndef DEBUG
#define DEBUG
#endif
extern const char *_res_opcodes[];
/*%
* Form all types of queries.
* Returns the size of the result or -1.
*/
int
res_nmkquery(res_state statp,
int op, /*!< opcode of query */
const char *dname, /*!< domain name */
int class, int type, /*!< class and type of query */
const u_char *data, /*!< resource record data */
int datalen, /*!< length of data */
const u_char *newrr_in, /*!< new rr for modify or append */
u_char *buf, /*!< buffer to put query */
int buflen) /*!< size of buffer */
{
HEADER *hp;
u_char *cp, *ep;
int n;
u_char *dnptrs[20], **dpp, **lastdnptr;
UNUSED(newrr_in);
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_nmkquery(%s, %s, %s, %s)\n",
_res_opcodes[op], dname, p_class(class), p_type(type));
#endif
/*
* Initialize header fields.
*/
if ((buf == NULL) || (buflen < HFIXEDSZ))
return (-1);
memset(buf, 0, HFIXEDSZ);
hp = (HEADER *) buf;
statp->id = res_nrandomid(statp);
hp->id = htons(statp->id);
hp->opcode = op;
hp->rd = (statp->options & RES_RECURSE) != 0U;
hp->rcode = NOERROR;
cp = buf + HFIXEDSZ;
ep = buf + buflen;
dpp = dnptrs;
*dpp++ = buf;
*dpp++ = NULL;
lastdnptr = dnptrs + nitems(dnptrs);
/*
* perform opcode specific processing
*/
switch (op) {
case QUERY: /*FALLTHROUGH*/
case NS_NOTIFY_OP:
if (ep - cp < QFIXEDSZ)
return (-1);
if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs,
lastdnptr)) < 0)
return (-1);
cp += n;
ns_put16(type, cp);
cp += INT16SZ;
ns_put16(class, cp);
cp += INT16SZ;
hp->qdcount = htons(1);
if (op == QUERY || data == NULL)
break;
/*
* Make an additional record for completion domain.
*/
if ((ep - cp) < RRFIXEDSZ)
return (-1);
n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
dnptrs, lastdnptr);
if (n < 0)
return (-1);
cp += n;
ns_put16(T_NULL, cp);
cp += INT16SZ;
ns_put16(class, cp);
cp += INT16SZ;
ns_put32(0, cp);
cp += INT32SZ;
ns_put16(0, cp);
cp += INT16SZ;
hp->arcount = htons(1);
break;
case IQUERY:
/*
* Initialize answer section
*/
if (ep - cp < 1 + RRFIXEDSZ + datalen)
return (-1);
*cp++ = '\0'; /*%< no domain name */
ns_put16(type, cp);
cp += INT16SZ;
ns_put16(class, cp);
cp += INT16SZ;
ns_put32(0, cp);
cp += INT32SZ;
ns_put16(datalen, cp);
cp += INT16SZ;
if (datalen) {
memcpy(cp, data, datalen);
cp += datalen;
}
hp->ancount = htons(1);
break;
default:
return (-1);
}
return (cp - buf);
}
#ifdef RES_USE_EDNS0
/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
int
res_nopt(res_state statp,
int n0, /*%< current offset in buffer */
u_char *buf, /*%< buffer to put query */
int buflen, /*%< size of buffer */
int anslen) /*%< UDP answer buffer size */
{
HEADER *hp;
u_char *cp, *ep;
u_int16_t flags = 0;
#ifdef DEBUG
if ((statp->options & RES_DEBUG) != 0U)
printf(";; res_nopt()\n");
#endif
hp = (HEADER *) buf;
cp = buf + n0;
ep = buf + buflen;
if ((ep - cp) < 1 + RRFIXEDSZ)
return (-1);
*cp++ = 0; /*%< "." */
ns_put16(ns_t_opt, cp); /*%< TYPE */
cp += INT16SZ;
if (anslen > 0xffff)
anslen = 0xffff; /* limit to 16bit value */
ns_put16(anslen & 0xffff, cp); /*%< CLASS = UDP payload size */
cp += INT16SZ;
*cp++ = NOERROR; /*%< extended RCODE */
*cp++ = 0; /*%< EDNS version */
if (statp->options & RES_USE_DNSSEC) {
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_opt()... ENDS0 DNSSEC\n");
#endif
flags |= NS_OPT_DNSSEC_OK;
}
ns_put16(flags, cp);
cp += INT16SZ;
ns_put16(0U, cp); /*%< RDLEN */
cp += INT16SZ;
hp->arcount = htons(ntohs(hp->arcount) + 1);
return (cp - buf);
}
/*
* Construct variable data (RDATA) block for OPT pseudo-RR, append it
* to the buffer, then update the RDLEN field (previously set to zero by
* res_nopt()) with the new RDATA length.
*/
int
res_nopt_rdata(res_state statp,
int n0, /*%< current offset in buffer */
u_char *buf, /*%< buffer to put query */
int buflen, /*%< size of buffer */
u_char *rdata, /*%< ptr to start of opt rdata */
u_short code, /*%< OPTION-CODE */
u_short len, /*%< OPTION-LENGTH */
u_char *data) /*%< OPTION_DATA */
{
register u_char *cp, *ep;
#ifdef DEBUG
if ((statp->options & RES_DEBUG) != 0U)
printf(";; res_nopt_rdata()\n");
#endif
cp = buf + n0;
ep = buf + buflen;
if ((ep - cp) < (4 + len))
return (-1);
if (rdata < (buf + 2) || rdata >= ep)
return (-1);
ns_put16(code, cp);
cp += INT16SZ;
ns_put16(len, cp);
cp += INT16SZ;
memcpy(cp, data, len);
cp += len;
len = cp - rdata;
ns_put16(len, rdata - 2); /* Update RDLEN field */
return (cp - buf);
}
#endif
/*! \file */
diff --git a/lib/libc/resolv/res_mkupdate.c b/lib/libc/resolv/res_mkupdate.c
index 41447f60def6..d817c5b0728c 100644
--- a/lib/libc/resolv/res_mkupdate.c
+++ b/lib/libc/resolv/res_mkupdate.c
@@ -1,1198 +1,1197 @@
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/*! \file
* \brief
* Based on the Dynamic DNS reference implementation by Viraj Bais
* &lt;viraj_bais@ccm.fm.intel.com>
*/
#if !defined(lint) && !defined(SABER)
static const char rcsid[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
#endif /* not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <resolv.h>
#include <res_update.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#ifdef _LIBC
#include <isc/list.h>
#endif
#include "port_after.h"
/* Options. Leave them on. */
#ifndef DEBUG
#define DEBUG
#endif
#define MAXPORT 1024
static int getnum_str(u_char **, u_char *);
static int gethexnum_str(u_char **, u_char *);
static int getword_str(char *, int, u_char **, u_char *);
static int getstr_str(char *, int, u_char **, u_char *);
#define ShrinkBuffer(x) if ((buflen -= x) < 0) return (-2);
/* Forward. */
#ifdef _LIBC
static
#endif
int res_protocolnumber(const char *);
#ifdef _LIBC
static
#endif
int res_servicenumber(const char *);
/*%
* Form update packets.
* Returns the size of the resulting packet if no error
*
* On error,
* returns
*\li -1 if error in reading a word/number in rdata
* portion for update packets
*\li -2 if length of buffer passed is insufficient
*\li -3 if zone section is not the first section in
* the linked list, or section order has a problem
*\li -4 on a number overflow
*\li -5 unknown operation or no records
*/
int
res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
ns_updrec *rrecp_start = rrecp_in;
HEADER *hp;
u_char *cp, *sp2, *startp, *endp;
int n, i, soanum, multiline;
ns_updrec *rrecp;
struct in_addr ina;
struct in6_addr in6a;
char buf2[MAXDNAME];
u_char buf3[MAXDNAME];
int section, numrrs = 0, counts[ns_s_max];
u_int16_t rtype, rclass;
u_int32_t n1, rttl;
u_char *dnptrs[20], **dpp, **lastdnptr;
#ifndef _LIBC
int siglen;
#endif
int keylen, certlen;
/*
* Initialize header fields.
*/
if ((buf == NULL) || (buflen < HFIXEDSZ))
return (-1);
memset(buf, 0, HFIXEDSZ);
hp = (HEADER *) buf;
statp->id = res_nrandomid(statp);
hp->id = htons(statp->id);
hp->opcode = ns_o_update;
hp->rcode = NOERROR;
cp = buf + HFIXEDSZ;
buflen -= HFIXEDSZ;
dpp = dnptrs;
*dpp++ = buf;
*dpp++ = NULL;
lastdnptr = dnptrs + nitems(dnptrs);
if (rrecp_start == NULL)
return (-5);
else if (rrecp_start->r_section != S_ZONE)
return (-3);
memset(counts, 0, sizeof counts);
for (rrecp = rrecp_start; rrecp; rrecp = NEXT(rrecp, r_glink)) {
numrrs++;
section = rrecp->r_section;
if (section < 0 || section >= ns_s_max)
return (-1);
counts[section]++;
for (i = section + 1; i < ns_s_max; i++)
if (counts[i])
return (-3);
rtype = rrecp->r_type;
rclass = rrecp->r_class;
rttl = rrecp->r_ttl;
/* overload class and type */
if (section == S_PREREQ) {
rttl = 0;
switch (rrecp->r_opcode) {
case YXDOMAIN:
rclass = C_ANY;
rtype = T_ANY;
rrecp->r_size = 0;
break;
case NXDOMAIN:
rclass = C_NONE;
rtype = T_ANY;
rrecp->r_size = 0;
break;
case NXRRSET:
rclass = C_NONE;
rrecp->r_size = 0;
break;
case YXRRSET:
if (rrecp->r_size == 0)
rclass = C_ANY;
break;
default:
fprintf(stderr,
"res_mkupdate: incorrect opcode: %d\n",
rrecp->r_opcode);
fflush(stderr);
return (-1);
}
} else if (section == S_UPDATE) {
switch (rrecp->r_opcode) {
case DELETE:
rclass = rrecp->r_size == 0 ? C_ANY : C_NONE;
break;
case ADD:
break;
default:
fprintf(stderr,
"res_mkupdate: incorrect opcode: %d\n",
rrecp->r_opcode);
fflush(stderr);
return (-1);
}
}
/*
* XXX appending default domain to owner name is omitted,
* fqdn must be provided
*/
if ((n = dn_comp(rrecp->r_dname, cp, buflen, dnptrs,
lastdnptr)) < 0)
return (-1);
cp += n;
ShrinkBuffer(n + 2*INT16SZ);
PUTSHORT(rtype, cp);
PUTSHORT(rclass, cp);
if (section == S_ZONE) {
if (numrrs != 1 || rrecp->r_type != T_SOA)
return (-3);
continue;
}
ShrinkBuffer(INT32SZ + INT16SZ);
PUTLONG(rttl, cp);
sp2 = cp; /*%< save pointer to length byte */
cp += INT16SZ;
if (rrecp->r_size == 0) {
if (section == S_UPDATE && rclass != C_ANY)
return (-1);
else {
PUTSHORT(0, sp2);
continue;
}
}
startp = rrecp->r_data;
endp = startp + rrecp->r_size - 1;
/* XXX this should be done centrally. */
switch (rrecp->r_type) {
case T_A:
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
if (!inet_aton(buf2, &ina))
return (-1);
n1 = ntohl(ina.s_addr);
ShrinkBuffer(INT32SZ);
PUTLONG(n1, cp);
break;
case T_CNAME:
case T_MB:
case T_MG:
case T_MR:
case T_NS:
case T_PTR:
case ns_t_dname:
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
break;
case T_MINFO:
case T_SOA:
case T_RP:
for (i = 0; i < 2; i++) {
if (!getword_str(buf2, sizeof buf2, &startp,
endp))
return (-1);
n = dn_comp(buf2, cp, buflen,
dnptrs, lastdnptr);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
}
if (rrecp->r_type == T_SOA) {
ShrinkBuffer(5 * INT32SZ);
while (isspace(*startp) || !*startp)
startp++;
if (*startp == '(') {
multiline = 1;
startp++;
} else
multiline = 0;
/* serial, refresh, retry, expire, minimum */
for (i = 0; i < 5; i++) {
soanum = getnum_str(&startp, endp);
if (soanum < 0)
return (-1);
PUTLONG(soanum, cp);
}
if (multiline) {
while (isspace(*startp) || !*startp)
startp++;
if (*startp != ')')
return (-1);
}
}
break;
case T_MX:
case T_AFSDB:
case T_RT:
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
break;
case T_SRV:
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
n = dn_comp(buf2, cp, buflen, NULL, NULL);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
break;
case T_PX:
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
PUTSHORT(n, cp);
ShrinkBuffer(INT16SZ);
for (i = 0; i < 2; i++) {
if (!getword_str(buf2, sizeof buf2, &startp,
endp))
return (-1);
n = dn_comp(buf2, cp, buflen, dnptrs,
lastdnptr);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
}
break;
case T_WKS: {
char bm[MAXPORT/8];
unsigned int maxbm = 0;
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
if (!inet_aton(buf2, &ina))
return (-1);
n1 = ntohl(ina.s_addr);
ShrinkBuffer(INT32SZ);
PUTLONG(n1, cp);
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
if ((i = res_protocolnumber(buf2)) < 0)
return (-1);
ShrinkBuffer(1);
*cp++ = i & 0xff;
for (i = 0; i < MAXPORT/8 ; i++)
bm[i] = 0;
while (getword_str(buf2, sizeof buf2, &startp, endp)) {
if ((n = res_servicenumber(buf2)) <= 0)
return (-1);
if (n < MAXPORT) {
bm[n/8] |= (0x80>>(n%8));
if ((unsigned)n > maxbm)
maxbm = n;
} else
return (-1);
}
maxbm = maxbm/8 + 1;
ShrinkBuffer(maxbm);
memcpy(cp, bm, maxbm);
cp += maxbm;
break;
}
case T_HINFO:
for (i = 0; i < 2; i++) {
if ((n = getstr_str(buf2, sizeof buf2,
&startp, endp)) < 0)
return (-1);
if (n > 255)
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
}
break;
case T_TXT:
for (;;) {
if ((n = getstr_str(buf2, sizeof buf2,
&startp, endp)) < 0) {
if (cp != (sp2 + INT16SZ))
break;
return (-1);
}
if (n > 255)
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
}
break;
case T_X25:
/* RFC1183 */
if ((n = getstr_str(buf2, sizeof buf2, &startp,
endp)) < 0)
return (-1);
if (n > 255)
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
break;
case T_ISDN:
/* RFC1183 */
if ((n = getstr_str(buf2, sizeof buf2, &startp,
endp)) < 0)
return (-1);
if ((n > 255) || (n == 0))
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
if ((n = getstr_str(buf2, sizeof buf2, &startp,
endp)) < 0)
n = 0;
if (n > 255)
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
break;
case T_NSAP:
if ((n = inet_nsap_addr((char *)startp, (u_char *)buf2, sizeof(buf2))) != 0) {
ShrinkBuffer(n);
memcpy(cp, buf2, n);
cp += n;
} else {
return (-1);
}
break;
case T_LOC:
if ((n = loc_aton((char *)startp, (u_char *)buf2)) != 0) {
ShrinkBuffer(n);
memcpy(cp, buf2, n);
cp += n;
} else
return (-1);
break;
case ns_t_sig:
#ifdef _LIBC
return (-1);
#else
{
int sig_type, success, dateerror;
u_int32_t exptime, timesigned;
/* type */
if ((n = getword_str(buf2, sizeof buf2,
&startp, endp)) < 0)
return (-1);
sig_type = sym_ston(__p_type_syms, buf2, &success);
if (!success || sig_type == ns_t_any)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(sig_type, cp);
/* alg */
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(1);
*cp++ = n;
/* labels */
n = getnum_str(&startp, endp);
if (n <= 0 || n > 255)
return (-1);
ShrinkBuffer(1);
*cp++ = n;
/* ottl & expire */
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
exptime = ns_datetosecs(buf2, &dateerror);
if (!dateerror) {
ShrinkBuffer(INT32SZ);
PUTLONG(rttl, cp);
}
else {
char *ulendp;
u_int32_t ottl;
errno = 0;
ottl = strtoul(buf2, &ulendp, 10);
if (errno != 0 ||
(ulendp != NULL && *ulendp != '\0'))
return (-1);
ShrinkBuffer(INT32SZ);
PUTLONG(ottl, cp);
if (!getword_str(buf2, sizeof buf2, &startp,
endp))
return (-1);
exptime = ns_datetosecs(buf2, &dateerror);
if (dateerror)
return (-1);
}
/* expire */
ShrinkBuffer(INT32SZ);
PUTLONG(exptime, cp);
/* timesigned */
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
timesigned = ns_datetosecs(buf2, &dateerror);
if (!dateerror) {
ShrinkBuffer(INT32SZ);
PUTLONG(timesigned, cp);
}
else
return (-1);
/* footprint */
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
/* signer name */
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
n = dn_comp(buf2, cp, buflen, dnptrs, lastdnptr);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
/* sig */
if ((n = getword_str(buf2, sizeof buf2,
&startp, endp)) < 0)
return (-1);
siglen = b64_pton(buf2, buf3, sizeof(buf3));
if (siglen < 0)
return (-1);
ShrinkBuffer(siglen);
memcpy(cp, buf3, siglen);
cp += siglen;
break;
}
#endif
case ns_t_key:
/* flags */
n = gethexnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
/* proto */
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(1);
*cp++ = n;
/* alg */
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(1);
*cp++ = n;
/* key */
if ((n = getword_str(buf2, sizeof buf2,
&startp, endp)) < 0)
return (-1);
keylen = b64_pton(buf2, buf3, sizeof(buf3));
if (keylen < 0)
return (-1);
ShrinkBuffer(keylen);
memcpy(cp, buf3, keylen);
cp += keylen;
break;
case ns_t_nxt:
{
int success, nxt_type;
u_char data[32];
int maxtype;
/* next name */
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
n = dn_comp(buf2, cp, buflen, NULL, NULL);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
maxtype = 0;
memset(data, 0, sizeof data);
for (;;) {
if (!getword_str(buf2, sizeof buf2, &startp,
endp))
break;
nxt_type = sym_ston(__p_type_syms, buf2,
&success);
if (!success || !ns_t_rr_p(nxt_type))
return (-1);
NS_NXT_BIT_SET(nxt_type, data);
if (nxt_type > maxtype)
maxtype = nxt_type;
}
n = maxtype/NS_NXT_BITS+1;
ShrinkBuffer(n);
memcpy(cp, data, n);
cp += n;
break;
}
case ns_t_cert:
/* type */
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
/* key tag */
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
/* alg */
n = getnum_str(&startp, endp);
if (n < 0)
return (-1);
ShrinkBuffer(1);
*cp++ = n;
/* cert */
if ((n = getword_str(buf2, sizeof buf2,
&startp, endp)) < 0)
return (-1);
certlen = b64_pton(buf2, buf3, sizeof(buf3));
if (certlen < 0)
return (-1);
ShrinkBuffer(certlen);
memcpy(cp, buf3, certlen);
cp += certlen;
break;
case ns_t_aaaa:
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
if (inet_pton(AF_INET6, buf2, &in6a) <= 0)
return (-1);
ShrinkBuffer(NS_IN6ADDRSZ);
memcpy(cp, &in6a, NS_IN6ADDRSZ);
cp += NS_IN6ADDRSZ;
break;
case ns_t_naptr:
/* Order Preference Flags Service Replacement Regexp */
/* Order */
n = getnum_str(&startp, endp);
if (n < 0 || n > 65535)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
/* Preference */
n = getnum_str(&startp, endp);
if (n < 0 || n > 65535)
return (-1);
ShrinkBuffer(INT16SZ);
PUTSHORT(n, cp);
/* Flags */
if ((n = getstr_str(buf2, sizeof buf2,
&startp, endp)) < 0) {
return (-1);
}
if (n > 255)
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
/* Service Classes */
if ((n = getstr_str(buf2, sizeof buf2,
&startp, endp)) < 0) {
return (-1);
}
if (n > 255)
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
/* Pattern */
if ((n = getstr_str(buf2, sizeof buf2,
&startp, endp)) < 0) {
return (-1);
}
if (n > 255)
return (-1);
ShrinkBuffer(n+1);
*cp++ = n;
memcpy(cp, buf2, n);
cp += n;
/* Replacement */
if (!getword_str(buf2, sizeof buf2, &startp, endp))
return (-1);
n = dn_comp(buf2, cp, buflen, NULL, NULL);
if (n < 0)
return (-1);
cp += n;
ShrinkBuffer(n);
break;
default:
return (-1);
} /*switch*/
n = (u_int16_t)((cp - sp2) - INT16SZ);
PUTSHORT(n, sp2);
} /*for*/
hp->qdcount = htons(counts[0]);
hp->ancount = htons(counts[1]);
hp->nscount = htons(counts[2]);
hp->arcount = htons(counts[3]);
return (cp - buf);
}
/*%
* Get a whitespace delimited word from a string (not file)
* into buf. modify the start pointer to point after the
* word in the string.
*/
static int
getword_str(char *buf, int size, u_char **startpp, u_char *endp) {
char *cp;
int c;
for (cp = buf; *startpp <= endp; ) {
c = **startpp;
if (isspace(c) || c == '\0') {
if (cp != buf) /*%< trailing whitespace */
break;
else { /*%< leading whitespace */
(*startpp)++;
continue;
}
}
(*startpp)++;
if (cp >= buf+size-1)
break;
*cp++ = (u_char)c;
}
*cp = '\0';
return (cp != buf);
}
/*%
* get a white spae delimited string from memory. Process quoted strings
* and \\DDD escapes. Return length or -1 on error. Returned string may
* contain nulls.
*/
static char digits[] = "0123456789";
static int
getstr_str(char *buf, int size, u_char **startpp, u_char *endp) {
char *cp;
int c, c1 = 0;
int inquote = 0;
int seen_quote = 0;
int escape = 0;
int dig = 0;
for (cp = buf; *startpp <= endp; ) {
if ((c = **startpp) == '\0')
break;
/* leading white space */
if ((cp == buf) && !seen_quote && isspace(c)) {
(*startpp)++;
continue;
}
switch (c) {
case '\\':
if (!escape) {
escape = 1;
dig = 0;
c1 = 0;
(*startpp)++;
continue;
}
goto do_escape;
case '"':
if (!escape) {
inquote = !inquote;
seen_quote = 1;
(*startpp)++;
continue;
}
/* fall through */
default:
do_escape:
if (escape) {
switch (c) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
c1 = c1 * 10 +
(strchr(digits, c) - digits);
if (++dig == 3) {
c = c1 &0xff;
break;
}
(*startpp)++;
continue;
}
escape = 0;
} else if (!inquote && isspace(c))
goto done;
if (cp >= buf+size-1)
goto done;
*cp++ = (u_char)c;
(*startpp)++;
}
}
done:
*cp = '\0';
return ((cp == buf)? (seen_quote? 0: -1): (cp - buf));
}
/*%
* Get a whitespace delimited base 16 number from a string (not file) into buf
* update the start pointer to point after the number in the string.
*/
static int
gethexnum_str(u_char **startpp, u_char *endp) {
int c, n;
int seendigit = 0;
int m = 0;
if (*startpp + 2 >= endp || strncasecmp((char *)*startpp, "0x", 2) != 0)
return getnum_str(startpp, endp);
(*startpp)+=2;
for (n = 0; *startpp <= endp; ) {
c = **startpp;
if (isspace(c) || c == '\0') {
if (seendigit) /*%< trailing whitespace */
break;
else { /*%< leading whitespace */
(*startpp)++;
continue;
}
}
if (c == ';') {
while ((*startpp <= endp) &&
((c = **startpp) != '\n'))
(*startpp)++;
if (seendigit)
break;
continue;
}
if (!isxdigit(c)) {
if (c == ')' && seendigit) {
(*startpp)--;
break;
}
return (-1);
}
(*startpp)++;
if (isdigit(c))
n = n * 16 + (c - '0');
else
n = n * 16 + (tolower(c) - 'a' + 10);
seendigit = 1;
}
return (n + m);
}
/*%
* Get a whitespace delimited base 10 number from a string (not file) into buf
* update the start pointer to point after the number in the string.
*/
static int
getnum_str(u_char **startpp, u_char *endp) {
int c, n;
int seendigit = 0;
int m = 0;
for (n = 0; *startpp <= endp; ) {
c = **startpp;
if (isspace(c) || c == '\0') {
if (seendigit) /*%< trailing whitespace */
break;
else { /*%< leading whitespace */
(*startpp)++;
continue;
}
}
if (c == ';') {
while ((*startpp <= endp) &&
((c = **startpp) != '\n'))
(*startpp)++;
if (seendigit)
break;
continue;
}
if (!isdigit(c)) {
if (c == ')' && seendigit) {
(*startpp)--;
break;
}
return (-1);
}
(*startpp)++;
n = n * 10 + (c - '0');
seendigit = 1;
}
return (n + m);
}
/*%
* Allocate a resource record buffer & save rr info.
*/
ns_updrec *
res_mkupdrec(int section, const char *dname,
u_int class, u_int type, u_long ttl) {
ns_updrec *rrecp = (ns_updrec *)calloc(1, sizeof(ns_updrec));
if (!rrecp || !(rrecp->r_dname = strdup(dname))) {
if (rrecp)
free((char *)rrecp);
return (NULL);
}
INIT_LINK(rrecp, r_link);
INIT_LINK(rrecp, r_glink);
rrecp->r_class = (ns_class)class;
rrecp->r_type = (ns_type)type;
rrecp->r_ttl = ttl;
rrecp->r_section = (ns_sect)section;
return (rrecp);
}
/*%
* Free a resource record buffer created by res_mkupdrec.
*/
void
res_freeupdrec(ns_updrec *rrecp) {
/* Note: freeing r_dp is the caller's responsibility. */
if (rrecp->r_dname != NULL)
free(rrecp->r_dname);
free(rrecp);
}
struct valuelist {
struct valuelist * next;
struct valuelist * prev;
char * name;
char * proto;
int port;
};
static struct valuelist *servicelist, *protolist;
static void
res_buildservicelist(void) {
struct servent *sp;
struct valuelist *slp;
#ifdef MAYBE_HESIOD
setservent(0);
#else
setservent(1);
#endif
while ((sp = getservent()) != NULL) {
slp = (struct valuelist *)malloc(sizeof(struct valuelist));
if (!slp)
break;
slp->name = strdup(sp->s_name);
slp->proto = strdup(sp->s_proto);
if ((slp->name == NULL) || (slp->proto == NULL)) {
if (slp->name) free(slp->name);
if (slp->proto) free(slp->proto);
free(slp);
break;
}
slp->port = ntohs((u_int16_t)sp->s_port); /*%< host byt order */
slp->next = servicelist;
slp->prev = NULL;
if (servicelist)
servicelist->prev = slp;
servicelist = slp;
}
endservent();
}
#ifndef _LIBC
void
res_destroyservicelist() {
struct valuelist *slp, *slp_next;
for (slp = servicelist; slp != NULL; slp = slp_next) {
slp_next = slp->next;
free(slp->name);
free(slp->proto);
free(slp);
}
servicelist = (struct valuelist *)0;
}
#endif
#ifdef _LIBC
static
#endif
void
res_buildprotolist(void) {
struct protoent *pp;
struct valuelist *slp;
#ifdef MAYBE_HESIOD
setprotoent(0);
#else
setprotoent(1);
#endif
while ((pp = getprotoent()) != NULL) {
slp = (struct valuelist *)malloc(sizeof(struct valuelist));
if (!slp)
break;
slp->name = strdup(pp->p_name);
if (slp->name == NULL) {
free(slp);
break;
}
slp->port = pp->p_proto; /*%< host byte order */
slp->next = protolist;
slp->prev = NULL;
if (protolist)
protolist->prev = slp;
protolist = slp;
}
endprotoent();
}
#ifndef _LIBC
void
res_destroyprotolist(void) {
struct valuelist *plp, *plp_next;
for (plp = protolist; plp != NULL; plp = plp_next) {
plp_next = plp->next;
free(plp->name);
free(plp);
}
protolist = (struct valuelist *)0;
}
#endif
static int
findservice(const char *s, struct valuelist **list) {
struct valuelist *lp = *list;
int n;
for (; lp != NULL; lp = lp->next)
if (strcasecmp(lp->name, s) == 0) {
if (lp != *list) {
lp->prev->next = lp->next;
if (lp->next)
lp->next->prev = lp->prev;
(*list)->prev = lp;
lp->next = *list;
*list = lp;
}
return (lp->port); /*%< host byte order */
}
if (sscanf(s, "%d", &n) != 1 || n <= 0)
n = -1;
return (n);
}
/*%
* Convert service name or (ascii) number to int.
*/
#ifdef _LIBC
static
#endif
int
res_servicenumber(const char *p) {
if (servicelist == (struct valuelist *)0)
res_buildservicelist();
return (findservice(p, &servicelist));
}
/*%
* Convert protocol name or (ascii) number to int.
*/
#ifdef _LIBC
static
#endif
int
res_protocolnumber(const char *p) {
if (protolist == (struct valuelist *)0)
res_buildprotolist();
return (findservice(p, &protolist));
}
#ifndef _LIBC
static struct servent *
cgetservbyport(u_int16_t port, const char *proto) { /*%< Host byte order. */
struct valuelist **list = &servicelist;
struct valuelist *lp = *list;
static struct servent serv;
port = ntohs(port);
for (; lp != NULL; lp = lp->next) {
if (port != (u_int16_t)lp->port) /*%< Host byte order. */
continue;
if (strcasecmp(lp->proto, proto) == 0) {
if (lp != *list) {
lp->prev->next = lp->next;
if (lp->next)
lp->next->prev = lp->prev;
(*list)->prev = lp;
lp->next = *list;
*list = lp;
}
serv.s_name = lp->name;
serv.s_port = htons((u_int16_t)lp->port);
serv.s_proto = lp->proto;
return (&serv);
}
}
return (0);
}
static struct protoent *
cgetprotobynumber(int proto) { /*%< Host byte order. */
struct valuelist **list = &protolist;
struct valuelist *lp = *list;
static struct protoent prot;
for (; lp != NULL; lp = lp->next)
if (lp->port == proto) { /*%< Host byte order. */
if (lp != *list) {
lp->prev->next = lp->next;
if (lp->next)
lp->next->prev = lp->prev;
(*list)->prev = lp;
lp->next = *list;
*list = lp;
}
prot.p_name = lp->name;
prot.p_proto = lp->port; /*%< Host byte order. */
return (&prot);
}
return (0);
}
const char *
res_protocolname(int num) {
static char number[8];
struct protoent *pp;
if (protolist == (struct valuelist *)0)
res_buildprotolist();
pp = cgetprotobynumber(num);
if (pp == NULL) {
(void) sprintf(number, "%d", num);
return (number);
}
return (pp->p_name);
}
const char *
res_servicename(u_int16_t port, const char *proto) { /*%< Host byte order. */
static char number[8];
struct servent *ss;
if (servicelist == (struct valuelist *)0)
res_buildservicelist();
ss = cgetservbyport(htons(port), proto);
if (ss == NULL) {
(void) sprintf(number, "%d", port);
return (number);
}
return (ss->s_name);
}
#endif
diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c
index 8a134dd86395..43be4beb93eb 100644
--- a/lib/libc/resolv/res_query.c
+++ b/lib/libc/resolv/res_query.c
@@ -1,488 +1,487 @@
/*-
* SPDX-License-Identifier: (ISC AND BSD-3-Clause)
*
* Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 1996-2001, 2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_query.c,v 1.11 2008/11/14 02:36:51 marka Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "port_after.h"
/* Options. Leave them on. */
#ifndef DEBUG
#define DEBUG
#endif
#if PACKETSZ > 1024
#define MAXPACKET PACKETSZ
#else
#define MAXPACKET 1024
#endif
/*%
* Formulate a normal query, send, and await answer.
* Returned answer is placed in supplied buffer "answer".
* Perform preliminary check of answer, returning success only
* if no error is indicated and the answer count is nonzero.
* Return the size of the response on success, -1 on error.
* Error number is left in H_ERRNO.
*
* Caller must parse answer and determine whether it answers the question.
*/
int
res_nquery(res_state statp,
const char *name, /*%< domain name */
int class, int type, /*%< class and type of query */
u_char *answer, /*%< buffer to put answer */
int anslen) /*%< size of answer buffer */
{
u_char buf[MAXPACKET];
HEADER *hp = (HEADER *) answer;
u_int oflags;
u_char *rdata;
int n;
oflags = statp->_flags;
again:
hp->rcode = NOERROR; /*%< default */
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_query(%s, %d, %d)\n", name, class, type);
#endif
n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
buf, sizeof(buf));
#ifdef RES_USE_EDNS0
if (n > 0 && (statp->_flags & RES_F_EDNS0ERR) == 0 &&
(statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC|RES_NSID))) {
n = res_nopt(statp, n, buf, sizeof(buf), anslen);
if (n > 0 && (statp->options & RES_NSID) != 0U) {
rdata = &buf[n];
n = res_nopt_rdata(statp, n, buf, sizeof(buf), rdata,
NS_OPT_NSID, 0, NULL);
}
}
#endif
if (n <= 0) {
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_query: mkquery failed\n");
#endif
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (n);
}
n = res_nsend(statp, buf, n, answer, anslen);
if (n < 0) {
#ifdef RES_USE_EDNS0
/* if the query choked with EDNS0, retry without EDNS0 */
if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0U &&
((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
statp->_flags |= RES_F_EDNS0ERR;
if (statp->options & RES_DEBUG)
printf(";; res_nquery: retry without EDNS0\n");
goto again;
}
#endif
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_query: send error\n");
#endif
RES_SET_H_ERRNO(statp, TRY_AGAIN);
return (n);
}
if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; rcode = (%s), counts = an:%d ns:%d ar:%d\n",
p_rcode(hp->rcode),
ntohs(hp->ancount),
ntohs(hp->nscount),
ntohs(hp->arcount));
#endif
switch (hp->rcode) {
case NXDOMAIN:
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
break;
case SERVFAIL:
RES_SET_H_ERRNO(statp, TRY_AGAIN);
break;
case NOERROR:
RES_SET_H_ERRNO(statp, NO_DATA);
break;
case FORMERR:
case NOTIMP:
case REFUSED:
default:
RES_SET_H_ERRNO(statp, NO_RECOVERY);
break;
}
return (-1);
}
return (n);
}
/*%
* Formulate a normal query, send, and retrieve answer in supplied buffer.
* Return the size of the response on success, -1 on error.
* If enabled, implement search rules until answer or unrecoverable failure
* is detected. Error code, if any, is left in H_ERRNO.
*/
int
res_nsearch(res_state statp,
const char *name, /*%< domain name */
int class, int type, /*%< class and type of query */
u_char *answer, /*%< buffer to put answer */
int anslen) /*%< size of answer */
{
const char *cp, * const *domain;
HEADER *hp = (HEADER *) answer;
char tmp[NS_MAXDNAME];
u_int dots;
int trailing_dot, ret, saved_herrno;
int got_nodata = 0, got_servfail = 0, root_on_list = 0;
int tried_as_is = 0;
int searched = 0;
errno = 0;
RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /*%< True if we never query. */
dots = 0;
for (cp = name; *cp != '\0'; cp++)
dots += (*cp == '.');
trailing_dot = 0;
if (cp > name && *--cp == '.')
trailing_dot++;
/* If there aren't any dots, it could be a user-level alias. */
if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
return (res_nquery(statp, cp, class, type, answer, anslen));
/*
* If there are enough dots in the name, let's just give it a
* try 'as is'. The threshold can be set with the "ndots" option.
* Also, query 'as is', if there is a trailing dot in the name.
*/
saved_herrno = -1;
if (dots >= statp->ndots || trailing_dot) {
ret = res_nquerydomain(statp, name, NULL, class, type,
answer, anslen);
if (ret > 0 || trailing_dot)
return (ret);
if (errno == ECONNREFUSED) {
RES_SET_H_ERRNO(statp, TRY_AGAIN);
return (-1);
}
switch (statp->res_h_errno) {
case NO_DATA:
case HOST_NOT_FOUND:
break;
case TRY_AGAIN:
if (hp->rcode == SERVFAIL)
break;
/* FALLTHROUGH */
default:
return (-1);
}
saved_herrno = statp->res_h_errno;
tried_as_is++;
}
/*
* We do at least one level of search if
* - there is no dot and RES_DEFNAME is set, or
* - there is at least one dot, there is no trailing dot,
* and RES_DNSRCH is set.
*/
if ((!dots && (statp->options & RES_DEFNAMES) != 0U) ||
(dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0U)) {
int done = 0;
for (domain = (const char * const *)statp->dnsrch;
*domain && !done;
domain++) {
searched = 1;
if (domain[0][0] == '\0' ||
(domain[0][0] == '.' && domain[0][1] == '\0'))
root_on_list++;
if (root_on_list && tried_as_is)
continue;
ret = res_nquerydomain(statp, name, *domain,
class, type,
answer, anslen);
if (ret > 0)
return (ret);
/*
* If no server present, give up.
* If name isn't found in this domain,
* keep trying higher domains in the search list
* (if that's enabled).
* On a NO_DATA error, keep trying, otherwise
* a wildcard entry of another type could keep us
* from finding this entry higher in the domain.
* If we get some other error (negative answer or
* server failure), then stop searching up,
* but try the input name below in case it's
* fully-qualified.
*/
if (errno == ECONNREFUSED) {
RES_SET_H_ERRNO(statp, TRY_AGAIN);
return (-1);
}
switch (statp->res_h_errno) {
case NO_DATA:
got_nodata++;
/* FALLTHROUGH */
case HOST_NOT_FOUND:
/* keep trying */
break;
case TRY_AGAIN:
/*
* This can occur due to a server failure
* (that is, all listed servers have failed),
* or all listed servers have timed out.
* ((HEADER *)answer)->rcode may not be set
* to SERVFAIL in the case of a timeout.
*
* Either way we must return TRY_AGAIN in
* order to avoid non-deterministic
* return codes.
* For example, loaded name servers or races
* against network startup/validation (dhcp,
* ppp, etc) can cause the search to timeout
* on one search element, e.g. 'fu.bar.com',
* and return a definitive failure on the
* next search element, e.g. 'fu.'.
*/
got_servfail++;
if (hp->rcode == SERVFAIL) {
/* try next search element, if any */
break;
}
/* FALLTHROUGH */
default:
/* anything else implies that we're done */
done++;
}
/* if we got here for some reason other than DNSRCH,
* we only wanted one iteration of the loop, so stop.
*/
if ((statp->options & RES_DNSRCH) == 0U)
done++;
}
}
switch (statp->res_h_errno) {
case NO_DATA:
case HOST_NOT_FOUND:
break;
case TRY_AGAIN:
if (hp->rcode == SERVFAIL)
break;
/* FALLTHROUGH */
default:
goto giveup;
}
/*
* If the query has not already been tried as is then try it
* unless RES_NOTLDQUERY is set and there were no dots.
*/
if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0U) &&
!(tried_as_is || root_on_list)) {
ret = res_nquerydomain(statp, name, NULL, class, type,
answer, anslen);
if (ret > 0)
return (ret);
}
/* if we got here, we didn't satisfy the search.
* if we did an initial full query, return that query's H_ERRNO
* (note that we wouldn't be here if that query had succeeded).
* else if we ever got a nodata, send that back as the reason.
* else send back meaningless H_ERRNO, that being the one from
* the last DNSRCH we did.
*/
giveup:
if (saved_herrno != -1)
RES_SET_H_ERRNO(statp, saved_herrno);
else if (got_nodata)
RES_SET_H_ERRNO(statp, NO_DATA);
else if (got_servfail)
RES_SET_H_ERRNO(statp, TRY_AGAIN);
return (-1);
}
/*%
* Perform a call on res_query on the concatenation of name and domain,
* removing a trailing dot from name if domain is NULL.
*/
int
res_nquerydomain(res_state statp,
const char *name,
const char *domain,
int class, int type, /*%< class and type of query */
u_char *answer, /*%< buffer to put answer */
int anslen) /*%< size of answer */
{
char nbuf[MAXDNAME];
const char *longname = nbuf;
int n, d;
#ifdef DEBUG
if (statp->options & RES_DEBUG)
printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
name, domain?domain:"<Nil>", class, type);
#endif
if (domain == NULL) {
/*
* Check for trailing '.';
* copy without '.' if present.
*/
n = strlen(name);
if (n >= MAXDNAME) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
n--;
if (n >= 0 && name[n] == '.') {
strncpy(nbuf, name, n);
nbuf[n] = '\0';
} else
longname = name;
} else {
n = strlen(name);
d = strlen(domain);
if (n + d + 1 >= MAXDNAME) {
RES_SET_H_ERRNO(statp, NO_RECOVERY);
return (-1);
}
sprintf(nbuf, "%s.%s", name, domain);
}
return (res_nquery(statp, longname, class, type, answer, anslen));
}
const char *
res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
char *file, *cp1, *cp2;
char buf[BUFSIZ];
FILE *fp;
if (statp->options & RES_NOALIASES)
return (NULL);
file = secure_getenv("HOSTALIASES");
if (file == NULL || (fp = fopen(file, "re")) == NULL)
return (NULL);
setbuf(fp, NULL);
buf[sizeof(buf) - 1] = '\0';
while (fgets(buf, sizeof(buf), fp)) {
for (cp1 = buf; *cp1 && !isspace((unsigned char)*cp1); ++cp1)
;
if (!*cp1)
break;
*cp1 = '\0';
if (ns_samename(buf, name) == 1) {
while (isspace((unsigned char)*++cp1))
;
if (!*cp1)
break;
for (cp2 = cp1 + 1; *cp2 &&
!isspace((unsigned char)*cp2); ++cp2)
;
*cp2 = '\0';
strncpy(dst, cp1, siz - 1);
dst[siz - 1] = '\0';
fclose(fp);
return (dst);
}
}
fclose(fp);
return (NULL);
}
/*! \file */
diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c
index 4c228a4dbd5e..ebb7c738c812 100644
--- a/lib/libc/resolv/res_send.c
+++ b/lib/libc/resolv/res_send.c
@@ -1,1178 +1,1177 @@
/*-
* SPDX-License-Identifier: (ISC AND BSD-3-Clause)
*
* Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
* Portions Copyright (C) 1996-2003 Internet Software Consortium.
*
* Permission to use, copy, modify, and/or 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 ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/*
* Copyright (c) 1985, 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
*
* 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, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
* CORPORATION 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
static const char rcsid[] = "$Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp $";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*! \file
* \brief
* Send query to name server and wait for reply.
*/
#include "port_before.h"
#if !defined(USE_KQUEUE) && !defined(USE_POLL)
#include "fd_setsize.h"
#endif
#include "namespace.h"
#include <sys/param.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <arpa/nameser.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <isc/eventlib.h>
#include "port_after.h"
#ifdef USE_KQUEUE
#include <sys/event.h>
#else
#ifdef USE_POLL
#ifdef HAVE_STROPTS_H
#include <stropts.h>
#endif
#include <poll.h>
#endif /* USE_POLL */
#endif
#include "un-namespace.h"
/* Options. Leave them on. */
#ifndef DEBUG
#define DEBUG
#endif
#include "res_debug.h"
#include "res_private.h"
#define EXT(res) ((res)->_u._ext)
#if !defined(USE_POLL) && !defined(USE_KQUEUE)
static const int highestFD = FD_SETSIZE - 1;
#endif
/* Forward. */
static int get_salen(const struct sockaddr *);
static struct sockaddr * get_nsaddr(res_state, size_t);
static int send_vc(res_state, const u_char *, int,
u_char *, int, int *, int);
static int send_dg(res_state,
#ifdef USE_KQUEUE
int kq,
#endif
const u_char *, int,
u_char *, int, int *, int, int,
int *, int *);
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
void res_pquery(const res_state, const u_char *, int, FILE *);
static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
/* Public. */
/*%
* looks up "ina" in _res.ns_addr_list[]
*
* returns:
*\li 0 : not found
*\li >0 : found
*
* author:
*\li paul vixie, 29may94
*/
int
res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
const struct sockaddr_in *inp, *srv;
const struct sockaddr_in6 *in6p, *srv6;
int ns;
switch (sa->sa_family) {
case AF_INET:
inp = (const struct sockaddr_in *)sa;
for (ns = 0; ns < statp->nscount; ns++) {
srv = (struct sockaddr_in *)get_nsaddr(statp, ns);
if (srv->sin_family == inp->sin_family &&
srv->sin_port == inp->sin_port &&
(srv->sin_addr.s_addr == INADDR_ANY ||
srv->sin_addr.s_addr == inp->sin_addr.s_addr))
return (1);
}
break;
case AF_INET6:
if (EXT(statp).ext == NULL)
break;
in6p = (const struct sockaddr_in6 *)sa;
for (ns = 0; ns < statp->nscount; ns++) {
srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns);
if (srv6->sin6_family == in6p->sin6_family &&
srv6->sin6_port == in6p->sin6_port &&
#ifdef HAVE_SIN6_SCOPE_ID
(srv6->sin6_scope_id == 0 ||
srv6->sin6_scope_id == in6p->sin6_scope_id) &&
#endif
(IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
return (1);
}
break;
default:
break;
}
return (0);
}
/*%
* look for (name,type,class) in the query section of packet (buf,eom)
*
* requires:
*\li buf + HFIXEDSZ <= eom
*
* returns:
*\li -1 : format error
*\li 0 : not found
*\li >0 : found
*
* author:
*\li paul vixie, 29may94
*/
int
res_nameinquery(const char *name, int type, int class,
const u_char *buf, const u_char *eom)
{
const u_char *cp = buf + HFIXEDSZ;
int qdcount = ntohs(((const HEADER*)buf)->qdcount);
while (qdcount-- > 0) {
char tname[MAXDNAME+1];
int n, ttype, tclass;
n = dn_expand(buf, eom, cp, tname, sizeof tname);
if (n < 0)
return (-1);
cp += n;
if (cp + 2 * INT16SZ > eom)
return (-1);
ttype = ns_get16(cp); cp += INT16SZ;
tclass = ns_get16(cp); cp += INT16SZ;
if (ttype == type && tclass == class &&
ns_samename(tname, name) == 1)
return (1);
}
return (0);
}
/*%
* is there a 1:1 mapping of (name,type,class)
* in (buf1,eom1) and (buf2,eom2)?
*
* returns:
*\li -1 : format error
*\li 0 : not a 1:1 mapping
*\li >0 : is a 1:1 mapping
*
* author:
*\li paul vixie, 29may94
*/
int
res_queriesmatch(const u_char *buf1, const u_char *eom1,
const u_char *buf2, const u_char *eom2)
{
const u_char *cp = buf1 + HFIXEDSZ;
int qdcount = ntohs(((const HEADER*)buf1)->qdcount);
if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
return (-1);
/*
* Only header section present in replies to
* dynamic update packets.
*/
if ((((const HEADER *)buf1)->opcode == ns_o_update) &&
(((const HEADER *)buf2)->opcode == ns_o_update))
return (1);
if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
return (0);
while (qdcount-- > 0) {
char tname[MAXDNAME+1];
int n, ttype, tclass;
n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
if (n < 0)
return (-1);
cp += n;
if (cp + 2 * INT16SZ > eom1)
return (-1);
ttype = ns_get16(cp); cp += INT16SZ;
tclass = ns_get16(cp); cp += INT16SZ;
if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
return (0);
}
return (1);
}
int
res_nsend(res_state statp,
const u_char *buf, int buflen, u_char *ans, int anssiz)
{
int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
#ifdef USE_KQUEUE
int kq;
#endif
char abuf[NI_MAXHOST];
/* No name servers or res_init() failure */
if (statp->nscount == 0 || EXT(statp).ext == NULL) {
errno = ESRCH;
return (-1);
}
if (anssiz < HFIXEDSZ) {
errno = EINVAL;
return (-1);
}
DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
(stdout, ";; res_send()\n"), buf, buflen);
v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
gotsomewhere = 0;
terrno = ETIMEDOUT;
#ifdef USE_KQUEUE
if ((kq = kqueue()) < 0) {
Perror(statp, stderr, "kqueue", errno);
return (-1);
}
#endif
/*
* If the ns_addr_list in the resolver context has changed, then
* invalidate our cached copy and the associated timing data.
*/
if (EXT(statp).nscount != 0) {
int needclose = 0;
struct sockaddr_storage peer;
ISC_SOCKLEN_T peerlen;
if (EXT(statp).nscount != statp->nscount)
needclose++;
else
for (ns = 0; ns < statp->nscount; ns++) {
if (statp->nsaddr_list[ns].sin_family &&
!sock_eq((struct sockaddr *)&statp->nsaddr_list[ns],
(struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) {
needclose++;
break;
}
if (EXT(statp).nssocks[ns] == -1)
continue;
peerlen = sizeof(peer);
if (_getpeername(EXT(statp).nssocks[ns],
(struct sockaddr *)&peer, &peerlen) < 0) {
needclose++;
break;
}
if (!sock_eq((struct sockaddr *)&peer,
get_nsaddr(statp, ns))) {
needclose++;
break;
}
}
if (needclose) {
res_nclose(statp);
EXT(statp).nscount = 0;
}
}
/*
* Maybe initialize our private copy of the ns_addr_list.
*/
if (EXT(statp).nscount == 0) {
for (ns = 0; ns < statp->nscount; ns++) {
EXT(statp).nstimes[ns] = RES_MAXTIME;
EXT(statp).nssocks[ns] = -1;
if (!statp->nsaddr_list[ns].sin_family)
continue;
EXT(statp).ext->nsaddrs[ns].sin =
statp->nsaddr_list[ns];
}
EXT(statp).nscount = statp->nscount;
}
/*
* Some resolvers want to even out the load on their nameservers.
* Note that RES_BLAST overrides RES_ROTATE.
*/
if ((statp->options & RES_ROTATE) != 0U &&
(statp->options & RES_BLAST) == 0U) {
union res_sockaddr_union inu;
struct sockaddr_in ina;
int lastns = statp->nscount - 1;
int fd;
u_int16_t nstime;
if (EXT(statp).ext != NULL)
inu = EXT(statp).ext->nsaddrs[0];
ina = statp->nsaddr_list[0];
fd = EXT(statp).nssocks[0];
nstime = EXT(statp).nstimes[0];
for (ns = 0; ns < lastns; ns++) {
if (EXT(statp).ext != NULL)
EXT(statp).ext->nsaddrs[ns] =
EXT(statp).ext->nsaddrs[ns + 1];
statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
}
if (EXT(statp).ext != NULL)
EXT(statp).ext->nsaddrs[lastns] = inu;
statp->nsaddr_list[lastns] = ina;
EXT(statp).nssocks[lastns] = fd;
EXT(statp).nstimes[lastns] = nstime;
}
/*
* Send request, RETRY times, or until successful.
*/
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);
statp->_flags &= ~RES_F_LASTMASK;
statp->_flags |= (ns << RES_F_LASTSHIFT);
same_ns:
if (statp->qhook) {
int done = 0, loops = 0;
do {
res_sendhookact act;
act = (*statp->qhook)(&nsap, &buf, &buflen,
ans, anssiz, &resplen);
switch (act) {
case res_goahead:
done = 1;
break;
case res_nextns:
res_nclose(statp);
goto next_ns;
case res_done:
#ifdef USE_KQUEUE
_close(kq);
#endif
return (resplen);
case res_modified:
/* give the hook another try */
if (++loops < 42) /*doug adams*/
break;
/*FALLTHROUGH*/
case res_error:
/*FALLTHROUGH*/
default:
goto fail;
}
} while (!done);
}
Dprint(((statp->options & RES_DEBUG) &&
getnameinfo(nsap, nsaplen, abuf, sizeof(abuf),
NULL, 0, niflags) == 0),
(stdout, ";; Querying server (# %d) address = %s\n",
ns + 1, abuf));
if (v_circuit) {
/* Use VC; at most one attempt per server. */
tries = statp->retry;
n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
ns);
if (n < 0)
goto fail;
if (n == 0)
goto next_ns;
resplen = n;
} else {
/* Use datagrams. */
n = send_dg(statp,
#ifdef USE_KQUEUE
kq,
#endif
buf, buflen, ans, anssiz, &terrno,
ns, tries, &v_circuit, &gotsomewhere);
if (n < 0)
goto fail;
if (n == 0)
goto next_ns;
if (v_circuit)
goto same_ns;
resplen = n;
}
Dprint((statp->options & RES_DEBUG) ||
((statp->pfcode & RES_PRF_REPLY) &&
(statp->pfcode & RES_PRF_HEAD1)),
(stdout, ";; got answer:\n"));
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, "%s", ""),
ans, (resplen > anssiz) ? anssiz : resplen);
/*
* If we have temporarily opened a virtual circuit,
* or if we haven't been asked to keep a socket open,
* close the socket.
*/
if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
(statp->options & RES_STAYOPEN) == 0U) {
res_nclose(statp);
}
if (statp->rhook) {
int done = 0, loops = 0;
do {
res_sendhookact act;
act = (*statp->rhook)(nsap, buf, buflen,
ans, anssiz, &resplen);
switch (act) {
case res_goahead:
case res_done:
done = 1;
break;
case res_nextns:
res_nclose(statp);
goto next_ns;
case res_modified:
/* give the hook another try */
if (++loops < 42) /*doug adams*/
break;
/*FALLTHROUGH*/
case res_error:
/*FALLTHROUGH*/
default:
goto fail;
}
} while (!done);
}
#ifdef USE_KQUEUE
_close(kq);
#endif
return (resplen);
next_ns: ;
} /*foreach ns*/
} /*foreach retry*/
res_nclose(statp);
#ifdef USE_KQUEUE
_close(kq);
#endif
if (!v_circuit) {
if (!gotsomewhere)
errno = ECONNREFUSED; /*%< no nameservers found */
else
errno = ETIMEDOUT; /*%< no answer obtained */
} else
errno = terrno;
return (-1);
fail:
res_nclose(statp);
#ifdef USE_KQUEUE
_close(kq);
#endif
return (-1);
}
/* Private */
static int
get_salen(const struct sockaddr *sa)
{
#ifdef HAVE_SA_LEN
/* There are people do not set sa_len. Be forgiving to them. */
if (sa->sa_len)
return (sa->sa_len);
#endif
if (sa->sa_family == AF_INET)
return (sizeof(struct sockaddr_in));
else if (sa->sa_family == AF_INET6)
return (sizeof(struct sockaddr_in6));
else
return (0); /*%< unknown, die on connect */
}
/*%
* pick appropriate nsaddr_list for use. see res_init() for initialization.
*/
static struct sockaddr *
get_nsaddr(res_state statp, size_t n)
{
if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
/*
* - EXT(statp).ext->nsaddrs[n] holds an address that is larger
* than struct sockaddr, and
* - user code did not update statp->nsaddr_list[n].
*/
return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
} else {
/*
* - user code updated statp->nsaddr_list[n], or
* - statp->nsaddr_list[n] has the same content as
* EXT(statp).ext->nsaddrs[n].
*/
return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
}
}
static int
send_vc(res_state statp,
const u_char *buf, int buflen, u_char *ans, int anssiz,
int *terrno, int ns)
{
const HEADER *hp = (const HEADER *) buf;
HEADER *anhp = (HEADER *) ans;
struct sockaddr *nsap;
int nsaplen;
int truncating, connreset, resplen, n;
struct iovec iov[2];
u_short len;
u_char *cp;
void *tmp;
#ifdef SO_NOSIGPIPE
int on = 1;
#endif
nsap = get_nsaddr(statp, ns);
nsaplen = get_salen(nsap);
connreset = 0;
same_ns:
truncating = 0;
/* Are we still talking to whom we want to talk to? */
if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
struct sockaddr_storage peer;
ISC_SOCKLEN_T size = sizeof peer;
if (_getpeername(statp->_vcsock,
(struct sockaddr *)&peer, &size) < 0 ||
!sock_eq((struct sockaddr *)&peer, nsap)) {
res_nclose(statp);
statp->_flags &= ~RES_F_VC;
}
}
if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
if (statp->_vcsock >= 0)
res_nclose(statp);
statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM |
SOCK_CLOEXEC, 0);
#if !defined(USE_POLL) && !defined(USE_KQUEUE)
if (statp->_vcsock > highestFD) {
res_nclose(statp);
errno = ENOTSOCK;
}
#endif
if (statp->_vcsock < 0) {
switch (errno) {
case EPROTONOSUPPORT:
#ifdef EPFNOSUPPORT
case EPFNOSUPPORT:
#endif
case EAFNOSUPPORT:
Perror(statp, stderr, "socket(vc)", errno);
return (0);
default:
*terrno = errno;
Perror(statp, stderr, "socket(vc)", errno);
return (-1);
}
}
#ifdef SO_NOSIGPIPE
/*
* Disable generation of SIGPIPE when writing to a closed
* socket. Write should return -1 and set errno to EPIPE
* instead.
*
* Push on even if setsockopt(SO_NOSIGPIPE) fails.
*/
(void)_setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
sizeof(on));
#endif
errno = 0;
if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
*terrno = errno;
Aerror(statp, stderr, "connect/vc", errno, nsap,
nsaplen);
res_nclose(statp);
return (0);
}
statp->_flags |= RES_F_VC;
}
/*
* Send length & message
*/
ns_put16((u_short)buflen, (u_char*)&len);
iov[0] = evConsIovec(&len, INT16SZ);
DE_CONST(buf, tmp);
iov[1] = evConsIovec(tmp, buflen);
if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
*terrno = errno;
Perror(statp, stderr, "write failed", errno);
res_nclose(statp);
return (0);
}
/*
* Receive length & response
*/
read_len:
cp = ans;
len = INT16SZ;
while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
cp += n;
if ((len -= n) == 0)
break;
}
if (n <= 0) {
*terrno = errno;
Perror(statp, stderr, "read failed", errno);
res_nclose(statp);
/*
* A long running process might get its TCP
* connection reset if the remote server was
* restarted. Requery the server instead of
* trying a new one. When there is only one
* server, this means that a query might work
* instead of failing. We only allow one reset
* per query to prevent looping.
*/
if (*terrno == ECONNRESET && !connreset) {
connreset = 1;
res_nclose(statp);
goto same_ns;
}
res_nclose(statp);
return (0);
}
resplen = ns_get16(ans);
if (resplen > anssiz) {
Dprint(statp->options & RES_DEBUG,
(stdout, ";; response truncated\n")
);
truncating = 1;
len = anssiz;
} else
len = resplen;
if (len < HFIXEDSZ) {
/*
* Undersized message.
*/
Dprint(statp->options & RES_DEBUG,
(stdout, ";; undersized: %d\n", len));
*terrno = EMSGSIZE;
res_nclose(statp);
return (0);
}
cp = ans;
while (len != 0 &&
(n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
cp += n;
len -= n;
}
if (n <= 0) {
*terrno = errno;
Perror(statp, stderr, "read(vc)", errno);
res_nclose(statp);
return (0);
}
if (truncating) {
/*
* Flush rest of answer so connection stays in synch.
*/
anhp->tc = 1;
len = resplen - anssiz;
while (len != 0) {
char junk[PACKETSZ];
n = _read(statp->_vcsock, junk,
(len > sizeof junk) ? sizeof junk : len);
if (n > 0)
len -= n;
else
break;
}
}
/*
* If the calling applicating has bailed out of
* a previous call and failed to arrange to have
* the circuit closed or the server has got
* itself confused, then drop the packet and
* wait for the correct one.
*/
if (hp->id != anhp->id) {
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; old answer (unexpected):\n"),
ans, (resplen > anssiz) ? anssiz: resplen);
goto read_len;
}
/*
* All is well, or the error is fatal. Signal that the
* next nameserver ought not be tried.
*/
return (resplen);
}
static int
send_dg(res_state statp,
#ifdef USE_KQUEUE
int kq,
#endif
const u_char *buf, int buflen, u_char *ans,
int anssiz, int *terrno, int ns, int tries, int *v_circuit,
int *gotsomewhere)
{
const HEADER *hp = (const HEADER *) buf;
HEADER *anhp = (HEADER *) ans;
const struct sockaddr *nsap;
int nsaplen;
struct timespec now, timeout, finish;
struct sockaddr_storage from;
ISC_SOCKLEN_T fromlen;
int resplen, seconds, n, s;
#ifdef USE_KQUEUE
struct kevent kv;
#else
#ifdef USE_POLL
int polltimeout;
struct pollfd pollfd;
#else
fd_set dsmask;
#endif
#endif
nsap = get_nsaddr(statp, ns);
nsaplen = get_salen(nsap);
if (EXT(statp).nssocks[ns] == -1) {
EXT(statp).nssocks[ns] = _socket(nsap->sa_family,
SOCK_DGRAM | SOCK_CLOEXEC, 0);
#if !defined(USE_POLL) && !defined(USE_KQUEUE)
if (EXT(statp).nssocks[ns] > highestFD) {
res_nclose(statp);
errno = ENOTSOCK;
}
#endif
if (EXT(statp).nssocks[ns] < 0) {
switch (errno) {
case EPROTONOSUPPORT:
#ifdef EPFNOSUPPORT
case EPFNOSUPPORT:
#endif
case EAFNOSUPPORT:
Perror(statp, stderr, "socket(dg)", errno);
return (0);
default:
*terrno = errno;
Perror(statp, stderr, "socket(dg)", errno);
return (-1);
}
}
#ifndef CANNOT_CONNECT_DGRAM
/*
* On a 4.3BSD+ machine (client and server,
* actually), sending to a nameserver datagram
* port with no nameserver will cause an
* ICMP port unreachable message to be returned.
* If our datagram socket is "connected" to the
* server, we get an ECONNREFUSED error on the next
* socket operation, and select returns if the
* error message is received. We can thus detect
* the absence of a nameserver without timing out.
*
* When the option "insecure1" is specified, we'd
* rather expect to see responses from an "unknown"
* address. In order to let the kernel accept such
* responses, do not connect the socket here.
* XXX: or do we need an explicit option to disable
* connecting?
*/
if (!(statp->options & RES_INSECURE1) &&
_connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
Aerror(statp, stderr, "connect(dg)", errno, nsap,
nsaplen);
res_nclose(statp);
return (0);
}
#endif /* !CANNOT_CONNECT_DGRAM */
Dprint(statp->options & RES_DEBUG,
(stdout, ";; new DG socket\n"))
}
s = EXT(statp).nssocks[ns];
#ifndef CANNOT_CONNECT_DGRAM
if (statp->options & RES_INSECURE1) {
if (_sendto(s,
(const char*)buf, buflen, 0, nsap, nsaplen) != buflen) {
Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
res_nclose(statp);
return (0);
}
} else if (send(s, (const char*)buf, buflen, 0) != buflen) {
Perror(statp, stderr, "send", errno);
res_nclose(statp);
return (0);
}
#else /* !CANNOT_CONNECT_DGRAM */
if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
{
Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
res_nclose(statp);
return (0);
}
#endif /* !CANNOT_CONNECT_DGRAM */
/*
* Wait for reply.
*/
seconds = (statp->retrans << tries);
if (ns > 0)
seconds /= statp->nscount;
if (seconds <= 0)
seconds = 1;
now = evNowTime();
timeout = evConsTime(seconds, 0);
finish = evAddTime(now, timeout);
goto nonow;
wait:
now = evNowTime();
nonow:
#ifndef USE_POLL
if (evCmpTime(finish, now) > 0)
timeout = evSubTime(finish, now);
else
timeout = evConsTime(0, 0);
#ifdef USE_KQUEUE
EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
n = _kevent(kq, &kv, 1, &kv, 1, &timeout);
#else
FD_ZERO(&dsmask);
FD_SET(s, &dsmask);
n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
#endif
#else
timeout = evSubTime(finish, now);
if (timeout.tv_sec < 0)
timeout = evConsTime(0, 0);
polltimeout = 1000*timeout.tv_sec +
timeout.tv_nsec/1000000;
pollfd.fd = s;
pollfd.events = POLLRDNORM;
n = _poll(&pollfd, 1, polltimeout);
#endif /* USE_POLL */
if (n == 0) {
Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
*gotsomewhere = 1;
return (0);
}
if (n < 0) {
if (errno == EINTR)
goto wait;
#ifdef USE_KQUEUE
Perror(statp, stderr, "kevent", errno);
#else
#ifndef USE_POLL
Perror(statp, stderr, "select", errno);
#else
Perror(statp, stderr, "poll", errno);
#endif /* USE_POLL */
#endif
res_nclose(statp);
return (0);
}
#ifdef USE_KQUEUE
if (kv.ident != s)
goto wait;
#endif
errno = 0;
fromlen = sizeof(from);
resplen = _recvfrom(s, (char*)ans, anssiz,0,
(struct sockaddr *)&from, &fromlen);
if (resplen <= 0) {
Perror(statp, stderr, "recvfrom", errno);
res_nclose(statp);
return (0);
}
*gotsomewhere = 1;
if (resplen < HFIXEDSZ) {
/*
* Undersized message.
*/
Dprint(statp->options & RES_DEBUG,
(stdout, ";; undersized: %d\n",
resplen));
*terrno = EMSGSIZE;
res_nclose(statp);
return (0);
}
if (hp->id != anhp->id) {
/*
* response from old query, ignore it.
* XXX - potential security hazard could
* be detected here.
*/
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; old answer:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
goto wait;
}
if (!(statp->options & RES_INSECURE1) &&
!res_ourserver_p(statp, (struct sockaddr *)&from)) {
/*
* response from wrong server? ignore it.
* XXX - potential security hazard could
* be detected here.
*/
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; not our server:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
goto wait;
}
#ifdef RES_USE_EDNS0
if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
/*
* Do not retry if the server do not understand EDNS0.
* The case has to be captured here, as FORMERR packet do not
* carry query section, hence res_queriesmatch() returns 0.
*/
DprintQ(statp->options & RES_DEBUG,
(stdout, "server rejected query with EDNS0:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
/* record the error */
statp->_flags |= RES_F_EDNS0ERR;
res_nclose(statp);
return (0);
}
#endif
if (!(statp->options & RES_INSECURE2) &&
!res_queriesmatch(buf, buf + buflen,
ans, ans + anssiz)) {
/*
* response contains wrong query? ignore it.
* XXX - potential security hazard could
* be detected here.
*/
DprintQ((statp->options & RES_DEBUG) ||
(statp->pfcode & RES_PRF_REPLY),
(stdout, ";; wrong query name:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
goto wait;
}
if (anhp->rcode == SERVFAIL ||
anhp->rcode == NOTIMP ||
anhp->rcode == REFUSED) {
DprintQ(statp->options & RES_DEBUG,
(stdout, "server rejected query:\n"),
ans, (resplen > anssiz) ? anssiz : resplen);
res_nclose(statp);
/* don't retry if called from dig */
if (!statp->pfcode)
return (0);
}
if (!(statp->options & RES_IGNTC) && anhp->tc) {
/*
* To get the rest of answer,
* use TCP with same server.
*/
Dprint(statp->options & RES_DEBUG,
(stdout, ";; truncated answer\n"));
*v_circuit = 1;
res_nclose(statp);
return (1);
}
/*
* All is well, or the error is fatal. Signal that the
* next nameserver ought not be tried.
*/
return (resplen);
}
static void
Aerror(const res_state statp, FILE *file, const char *string, int error,
const struct sockaddr *address, int alen)
{
int save = errno;
char hbuf[NI_MAXHOST];
char sbuf[NI_MAXSERV];
if ((statp->options & RES_DEBUG) != 0U) {
if (getnameinfo(address, alen, hbuf, sizeof(hbuf),
sbuf, sizeof(sbuf), niflags)) {
strncpy(hbuf, "?", sizeof(hbuf) - 1);
hbuf[sizeof(hbuf) - 1] = '\0';
strncpy(sbuf, "?", sizeof(sbuf) - 1);
sbuf[sizeof(sbuf) - 1] = '\0';
}
fprintf(file, "res_send: %s ([%s].%s): %s\n",
string, hbuf, sbuf, strerror(error));
}
errno = save;
}
static void
Perror(const res_state statp, FILE *file, const char *string, int error) {
int save = errno;
if ((statp->options & RES_DEBUG) != 0U)
fprintf(file, "res_send: %s: %s\n",
string, strerror(error));
errno = save;
}
static int
sock_eq(struct sockaddr *a, struct sockaddr *b) {
struct sockaddr_in *a4, *b4;
struct sockaddr_in6 *a6, *b6;
if (a->sa_family != b->sa_family)
return 0;
switch (a->sa_family) {
case AF_INET:
a4 = (struct sockaddr_in *)a;
b4 = (struct sockaddr_in *)b;
return a4->sin_port == b4->sin_port &&
a4->sin_addr.s_addr == b4->sin_addr.s_addr;
case AF_INET6:
a6 = (struct sockaddr_in6 *)a;
b6 = (struct sockaddr_in6 *)b;
return a6->sin6_port == b6->sin6_port &&
#ifdef HAVE_SIN6_SCOPE_ID
a6->sin6_scope_id == b6->sin6_scope_id &&
#endif
IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
default:
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/resolv/res_update.c b/lib/libc/resolv/res_update.c
index 05e9969008b0..f9119edaeb12 100644
--- a/lib/libc/resolv/res_update.c
+++ b/lib/libc/resolv/res_update.c
@@ -1,222 +1,221 @@
#if !defined(lint) && !defined(SABER)
static const char rcsid[] = "$Id: res_update.c,v 1.13 2005/04/27 04:56:43 sra Exp $";
#endif /* not lint */
/*-
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
* Copyright (c) 1996-1999 by Internet Software Consortium.
*
* 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 ISC DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC 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.
*/
/*! \file
* \brief
* Based on the Dynamic DNS reference implementation by Viraj Bais
* &lt;viraj_bais@ccm.fm.intel.com>
*/
-#include <sys/cdefs.h>
#include "port_before.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <errno.h>
#include <limits.h>
#include <netdb.h>
#include <res_update.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <isc/list.h>
#include <resolv.h>
#include "port_after.h"
#include "res_private.h"
/*%
* Separate a linked list of records into groups so that all records
* in a group will belong to a single zone on the nameserver.
* Create a dynamic update packet for each zone and send it to the
* nameservers for that zone, and await answer.
* Abort if error occurs in updating any zone.
* Return the number of zones updated on success, < 0 on error.
*
* On error, caller must deal with the unsynchronized zones
* eg. an A record might have been successfully added to the forward
* zone but the corresponding PTR record would be missing if error
* was encountered while updating the reverse zone.
*/
struct zonegrp {
char z_origin[MAXDNAME];
ns_class z_class;
union res_sockaddr_union z_nsaddrs[MAXNS];
int z_nscount;
int z_flags;
LIST(ns_updrec) z_rrlist;
LINK(struct zonegrp) z_link;
};
#define ZG_F_ZONESECTADDED 0x0001
/* Forward. */
static void res_dprintf(const char *, ...) ISC_FORMAT_PRINTF(1, 2);
/* Macros. */
#define DPRINTF(x) do {\
int save_errno = errno; \
if ((statp->options & RES_DEBUG) != 0U) res_dprintf x; \
errno = save_errno; \
} while (0)
/* Public. */
int
res_nupdate(res_state statp, ns_updrec *rrecp_in, ns_tsig_key *key) {
ns_updrec *rrecp;
u_char answer[PACKETSZ];
u_char *packet;
struct zonegrp *zptr, tgrp;
LIST(struct zonegrp) zgrps;
int nzones = 0, nscount = 0, n;
union res_sockaddr_union nsaddrs[MAXNS];
packet = malloc(NS_MAXMSG);
if (packet == NULL) {
DPRINTF(("malloc failed"));
return (0);
}
/* Thread all of the updates onto a list of groups. */
INIT_LIST(zgrps);
memset(&tgrp, 0, sizeof (tgrp));
for (rrecp = rrecp_in; rrecp;
rrecp = LINKED(rrecp, r_link) ? NEXT(rrecp, r_link) : NULL) {
int nscnt;
/* Find the origin for it if there is one. */
tgrp.z_class = rrecp->r_class;
nscnt = res_findzonecut2(statp, rrecp->r_dname, tgrp.z_class,
RES_EXHAUSTIVE, tgrp.z_origin,
sizeof tgrp.z_origin,
tgrp.z_nsaddrs, MAXNS);
if (nscnt <= 0) {
DPRINTF(("res_findzonecut failed (%d)", nscnt));
goto done;
}
tgrp.z_nscount = nscnt;
/* Find the group for it if there is one. */
for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link))
if (ns_samename(tgrp.z_origin, zptr->z_origin) == 1 &&
tgrp.z_class == zptr->z_class)
break;
/* Make a group for it if there isn't one. */
if (zptr == NULL) {
zptr = malloc(sizeof *zptr);
if (zptr == NULL) {
DPRINTF(("malloc failed"));
goto done;
}
*zptr = tgrp;
zptr->z_flags = 0;
INIT_LINK(zptr, z_link);
INIT_LIST(zptr->z_rrlist);
APPEND(zgrps, zptr, z_link);
}
/* Thread this rrecp onto the right group. */
APPEND(zptr->z_rrlist, rrecp, r_glink);
}
for (zptr = HEAD(zgrps); zptr != NULL; zptr = NEXT(zptr, z_link)) {
/* Construct zone section and prepend it. */
rrecp = res_mkupdrec(ns_s_zn, zptr->z_origin,
zptr->z_class, ns_t_soa, 0);
if (rrecp == NULL) {
DPRINTF(("res_mkupdrec failed"));
goto done;
}
PREPEND(zptr->z_rrlist, rrecp, r_glink);
zptr->z_flags |= ZG_F_ZONESECTADDED;
/* Marshall the update message. */
n = res_nmkupdate(statp, HEAD(zptr->z_rrlist),
packet, NS_MAXMSG);
DPRINTF(("res_mkupdate -> %d", n));
if (n < 0)
goto done;
/* Temporarily replace the resolver's nameserver set. */
nscount = res_getservers(statp, nsaddrs, MAXNS);
res_setservers(statp, zptr->z_nsaddrs, zptr->z_nscount);
/* Send the update and remember the result. */
if (key != NULL) {
#ifdef _LIBC
DPRINTF(("TSIG is not supported\n"));
RES_SET_H_ERRNO(statp, NO_RECOVERY);
goto done;
#else
n = res_nsendsigned(statp, packet, n, key,
answer, sizeof answer);
#endif
} else
n = res_nsend(statp, packet, n, answer, sizeof answer);
if (n < 0) {
DPRINTF(("res_nsend: send error, n=%d (%s)\n",
n, strerror(errno)));
goto done;
}
if (((HEADER *)answer)->rcode == NOERROR)
nzones++;
/* Restore resolver's nameserver set. */
res_setservers(statp, nsaddrs, nscount);
nscount = 0;
}
done:
while (!EMPTY(zgrps)) {
zptr = HEAD(zgrps);
if ((zptr->z_flags & ZG_F_ZONESECTADDED) != 0)
res_freeupdrec(HEAD(zptr->z_rrlist));
UNLINK(zgrps, zptr, z_link);
free(zptr);
}
if (nscount != 0)
res_setservers(statp, nsaddrs, nscount);
free(packet);
return (nzones);
}
/* Private. */
static void
res_dprintf(const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
fputs(";; res_nupdate: ", stderr);
vfprintf(stderr, fmt, ap);
fputc('\n', stderr);
va_end(ap);
}
diff --git a/lib/libc/riscv/gen/flt_rounds.c b/lib/libc/riscv/gen/flt_rounds.c
index 46e2ab9ca63c..5d3771ea6cd3 100644
--- a/lib/libc/riscv/gen/flt_rounds.c
+++ b/lib/libc/riscv/gen/flt_rounds.c
@@ -1,70 +1,69 @@
/*-
* Copyright (c) 2015-2016 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
* University of Cambridge Computer Laboratory under DARPA/AFRL contract
* FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Portions of this software were developed by the University of Cambridge
* Computer Laboratory as part of the CTSRD Project, with support from the
* UK Higher Education Innovation Fund (HEIF).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <fenv.h>
#include <float.h>
#ifdef __riscv_float_abi_soft
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
#endif
int
__flt_rounds(void)
{
uint64_t mode;
#ifdef __riscv_float_abi_soft
mode = __softfloat_float_rounding_mode;
#else
__asm __volatile("csrr %0, fcsr" : "=r" (mode));
#endif
switch (mode & _ROUND_MASK) {
case FE_TOWARDZERO:
return (0);
case FE_TONEAREST:
return (1);
case FE_UPWARD:
return (2);
case FE_DOWNWARD:
return (3);
}
return (-1);
}
diff --git a/lib/libc/riscv/gen/fpgetmask.c b/lib/libc/riscv/gen/fpgetmask.c
index 781709b8bf22..7835a17cff60 100644
--- a/lib/libc/riscv/gen/fpgetmask.c
+++ b/lib/libc/riscv/gen/fpgetmask.c
@@ -1,39 +1,38 @@
/*-
* Copyright (c) 2020 Axiado
* All rights reserved.
*
* This software was developed by Kristof Provost under
* sponsorship from Axiado.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
fp_except_t
fpgetmask(void)
{
return (0);
}
diff --git a/lib/libc/riscv/gen/fpsetmask.c b/lib/libc/riscv/gen/fpsetmask.c
index bcb42845065c..024f1fd8d8bc 100644
--- a/lib/libc/riscv/gen/fpsetmask.c
+++ b/lib/libc/riscv/gen/fpsetmask.c
@@ -1,51 +1,50 @@
/*-
* Copyright (c) 2020 Axiado
* All rights reserved.
*
* This software was developed by Kristof Provost under
* sponsorship from Axiado.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ieeefp.h>
/**
* RISC-V doesn't support floating-point exceptions: RISC-V Instruction Set
* Manual: Volume I: User-Level ISA, 11.2 Floating-Point Control and Status
* Register: "As allowed by the standard, we do not support traps on
* floating-point exceptions in the base ISA, but instead require explicit
* checks of the flags in software. We considered adding branches controlled
* directly by the contents of the floating-point accrued exception flags, but
* ultimately chose to omit these instructions to keep the ISA simple."
*
* We still need this function, because some applications (notably Perl) call
* it, but we cannot provide a meaningful implementation.
**/
fp_except_t
fpsetmask(fp_except_t mask)
{
return (0);
}
diff --git a/lib/libc/riscv/gen/infinity.c b/lib/libc/riscv/gen/infinity.c
index 1639ac09d410..ae44d5195a3b 100644
--- a/lib/libc/riscv/gen/infinity.c
+++ b/lib/libc/riscv/gen/infinity.c
@@ -1,12 +1,11 @@
/*
* infinity.c
*/
-#include <sys/cdefs.h>
#include <math.h>
/* bytes for +Infinity on riscv */
const union __infinity_un __infinity = { { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f } };
/* bytes for NaN */
const union __nan_un __nan = { { 0, 0, 0xc0, 0xff } };
diff --git a/lib/libc/riscv/gen/makecontext.c b/lib/libc/riscv/gen/makecontext.c
index aea855544f4d..e5371d082b2c 100644
--- a/lib/libc/riscv/gen/makecontext.c
+++ b/lib/libc/riscv/gen/makecontext.c
@@ -1,89 +1,88 @@
/*-
* Copyright (c) 2015 Ruslan Bukin <br@bsdpad.com>
* All rights reserved.
*
* Portions of this software were developed by SRI International and the
* University of Cambridge Computer Laboratory under DARPA/AFRL contract
* FA8750-10-C-0237 ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Portions of this software were developed by the University of Cambridge
* Computer Laboratory as part of the CTSRD Project, with support from the
* UK Higher Education Innovation Fund (HEIF).
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <machine/riscvreg.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ucontext.h>
void _ctx_start(void);
void
ctx_done(ucontext_t *ucp)
{
if (ucp->uc_link == NULL) {
exit(0);
} else {
setcontext((const ucontext_t *)ucp->uc_link);
abort();
}
}
__weak_reference(__makecontext, makecontext);
void
__makecontext(ucontext_t *ucp, void (*func)(void), int argc, ...)
{
struct gpregs *gp;
va_list ap;
int i;
/* A valid context is required. */
if (ucp == NULL)
return;
if ((argc < 0) || (argc > 8))
return;
gp = &ucp->uc_mcontext.mc_gpregs;
va_start(ap, argc);
/* Pass up to eight arguments in a0-7. */
for (i = 0; i < argc && i < 8; i++)
gp->gp_a[i] = va_arg(ap, uint64_t);
va_end(ap);
/* Set the stack */
gp->gp_sp = STACKALIGN(ucp->uc_stack.ss_sp + ucp->uc_stack.ss_size);
/* Arrange for return via the trampoline code. */
gp->gp_sepc = (__register_t)_ctx_start;
gp->gp_s[0] = (__register_t)func;
gp->gp_s[1] = (__register_t)ucp;
}
diff --git a/lib/libc/riscv/sys/__vdso_gettc.c b/lib/libc/riscv/sys/__vdso_gettc.c
index 919351511983..5037debef461 100644
--- a/lib/libc/riscv/sys/__vdso_gettc.c
+++ b/lib/libc/riscv/sys/__vdso_gettc.c
@@ -1,54 +1,53 @@
/*-
* Copyright (c) 2021 Jessica Clarke
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/elf.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <machine/riscvreg.h>
#include <errno.h>
#include "libc_private.h"
#pragma weak __vdso_gettc
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
if (th->th_algo != VDSO_TH_ALGO_RISCV_RDTIME)
return (ENOSYS);
*tc = csr_read(time);
return (0);
}
#pragma weak __vdso_gettimekeep
int
__vdso_gettimekeep(struct vdso_timekeep **tk)
{
return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
}
diff --git a/lib/libc/rpc/auth_des.c b/lib/libc/rpc/auth_des.c
index 1ceabaf8d672..b9097c1c6c33 100644
--- a/lib/libc/rpc/auth_des.c
+++ b/lib/libc/rpc/auth_des.c
@@ -1,497 +1,495 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* auth_des.c, client-side implementation of DES authentication
*/
#include "namespace.h"
#include "reentrant.h"
#include <err.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
-#include <sys/cdefs.h>
#include <rpc/des_crypt.h>
#include <syslog.h>
#include <rpc/types.h>
#include <rpc/auth.h>
#include <rpc/auth_des.h>
#include <rpc/clnt.h>
#include <rpc/xdr.h>
#include <sys/socket.h>
#undef NIS
#include <rpcsvc/nis.h>
#include "un-namespace.h"
#include "mt_misc.h"
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)auth_des.c 2.2 88/07/29 4.0 RPCSRC; from 1.9 88/02/08 SMI";
#endif
-#include <sys/cdefs.h>
#define USEC_PER_SEC 1000000
#define RTIME_TIMEOUT 5 /* seconds to wait for sync */
#define AUTH_PRIVATE(auth) (struct ad_private *) auth->ah_private
#define ALLOC(object_type) (object_type *) mem_alloc(sizeof(object_type))
#define FREE(ptr, size) mem_free((char *)(ptr), (int) size)
#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE)
extern bool_t xdr_authdes_cred( XDR *, struct authdes_cred *);
extern bool_t xdr_authdes_verf( XDR *, struct authdes_verf *);
extern int key_encryptsession_pk(char *, netobj *, des_block *);
extern bool_t __rpc_get_time_offset(struct timeval *, nis_server *, char *,
char **, char **);
/*
* DES authenticator operations vector
*/
static void authdes_nextverf(AUTH *);
static bool_t authdes_marshal(AUTH *, XDR *);
static bool_t authdes_validate(AUTH *, struct opaque_auth *);
static bool_t authdes_refresh(AUTH *, void *);
static void authdes_destroy(AUTH *);
static struct auth_ops *authdes_ops(void);
/*
* This struct is pointed to by the ah_private field of an "AUTH *"
*/
struct ad_private {
char *ad_fullname; /* client's full name */
u_int ad_fullnamelen; /* length of name, rounded up */
char *ad_servername; /* server's full name */
u_int ad_servernamelen; /* length of name, rounded up */
u_int ad_window; /* client specified window */
bool_t ad_dosync; /* synchronize? */
struct netbuf ad_syncaddr; /* remote host to synch with */
char *ad_timehost; /* remote host to synch with */
struct timeval ad_timediff; /* server's time - client's time */
u_int ad_nickname; /* server's nickname for client */
struct authdes_cred ad_cred; /* storage for credential */
struct authdes_verf ad_verf; /* storage for verifier */
struct timeval ad_timestamp; /* timestamp sent */
des_block ad_xkey; /* encrypted conversation key */
u_char ad_pkey[1024]; /* Server's actual public key */
char *ad_netid; /* Timehost netid */
char *ad_uaddr; /* Timehost uaddr */
nis_server *ad_nis_srvr; /* NIS+ server struct */
};
AUTH *authdes_pk_seccreate(const char *, netobj *, u_int, const char *,
const des_block *, nis_server *);
/*
* documented version of authdes_seccreate
*/
/*
servername: network name of server
win: time to live
timehost: optional hostname to sync with
ckey: optional conversation key to use
*/
AUTH *
authdes_seccreate(const char *servername, const u_int win,
const char *timehost, const des_block *ckey)
{
u_char pkey_data[1024];
netobj pkey;
AUTH *dummy;
if (! getpublickey(servername, (char *) pkey_data)) {
syslog(LOG_ERR,
"authdes_seccreate: no public key found for %s",
servername);
return (NULL);
}
pkey.n_bytes = (char *) pkey_data;
pkey.n_len = (u_int)strlen((char *)pkey_data) + 1;
dummy = authdes_pk_seccreate(servername, &pkey, win, timehost,
ckey, NULL);
return (dummy);
}
/*
* Slightly modified version of authdessec_create which takes the public key
* of the server principal as an argument. This spares us a call to
* getpublickey() which in the nameserver context can cause a deadlock.
*/
AUTH *
authdes_pk_seccreate(const char *servername, netobj *pkey, u_int window,
const char *timehost, const des_block *ckey, nis_server *srvr)
{
AUTH *auth;
struct ad_private *ad;
char namebuf[MAXNETNAMELEN+1];
/*
* Allocate everything now
*/
auth = ALLOC(AUTH);
if (auth == NULL) {
syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
return (NULL);
}
ad = ALLOC(struct ad_private);
if (ad == NULL) {
syslog(LOG_ERR, "authdes_pk_seccreate: out of memory");
goto failed;
}
ad->ad_fullname = ad->ad_servername = NULL; /* Sanity reasons */
ad->ad_timehost = NULL;
ad->ad_netid = NULL;
ad->ad_uaddr = NULL;
ad->ad_nis_srvr = NULL;
ad->ad_timediff.tv_sec = 0;
ad->ad_timediff.tv_usec = 0;
memcpy(ad->ad_pkey, pkey->n_bytes, pkey->n_len);
if (!getnetname(namebuf))
goto failed;
ad->ad_fullnamelen = RNDUP((u_int) strlen(namebuf));
ad->ad_fullname = (char *)mem_alloc(ad->ad_fullnamelen + 1);
ad->ad_servernamelen = strlen(servername);
ad->ad_servername = (char *)mem_alloc(ad->ad_servernamelen + 1);
if (ad->ad_fullname == NULL || ad->ad_servername == NULL) {
syslog(LOG_ERR, "authdes_seccreate: out of memory");
goto failed;
}
if (timehost != NULL) {
ad->ad_timehost = (char *)mem_alloc(strlen(timehost) + 1);
if (ad->ad_timehost == NULL) {
syslog(LOG_ERR, "authdes_seccreate: out of memory");
goto failed;
}
memcpy(ad->ad_timehost, timehost, strlen(timehost) + 1);
ad->ad_dosync = TRUE;
} else if (srvr != NULL) {
ad->ad_nis_srvr = srvr; /* transient */
ad->ad_dosync = TRUE;
} else {
ad->ad_dosync = FALSE;
}
memcpy(ad->ad_fullname, namebuf, ad->ad_fullnamelen + 1);
memcpy(ad->ad_servername, servername, ad->ad_servernamelen + 1);
ad->ad_window = window;
if (ckey == NULL) {
if (key_gendes(&auth->ah_key) < 0) {
syslog(LOG_ERR,
"authdes_seccreate: keyserv(1m) is unable to generate session key");
goto failed;
}
} else {
auth->ah_key = *ckey;
}
/*
* Set up auth handle
*/
auth->ah_cred.oa_flavor = AUTH_DES;
auth->ah_verf.oa_flavor = AUTH_DES;
auth->ah_ops = authdes_ops();
auth->ah_private = (caddr_t)ad;
if (!authdes_refresh(auth, NULL)) {
goto failed;
}
ad->ad_nis_srvr = NULL; /* not needed any longer */
return (auth);
failed:
if (auth)
FREE(auth, sizeof (AUTH));
if (ad) {
if (ad->ad_fullname)
FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
if (ad->ad_servername)
FREE(ad->ad_servername, ad->ad_servernamelen + 1);
if (ad->ad_timehost)
FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
if (ad->ad_netid)
FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
if (ad->ad_uaddr)
FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
FREE(ad, sizeof (struct ad_private));
}
return (NULL);
}
/*
* Implement the five authentication operations
*/
/*
* 1. Next Verifier
*/
/*ARGSUSED*/
static void
authdes_nextverf(AUTH *auth __unused)
{
/* what the heck am I supposed to do??? */
}
/*
* 2. Marshal
*/
static bool_t
authdes_marshal(AUTH *auth, XDR *xdrs)
{
/* LINTED pointer alignment */
struct ad_private *ad = AUTH_PRIVATE(auth);
struct authdes_cred *cred = &ad->ad_cred;
struct authdes_verf *verf = &ad->ad_verf;
des_block cryptbuf[2];
des_block ivec;
int status;
int len;
rpc_inline_t *ixdr;
/*
* Figure out the "time", accounting for any time difference
* with the server if necessary.
*/
(void)gettimeofday(&ad->ad_timestamp, NULL);
ad->ad_timestamp.tv_sec += ad->ad_timediff.tv_sec;
ad->ad_timestamp.tv_usec += ad->ad_timediff.tv_usec;
while (ad->ad_timestamp.tv_usec >= USEC_PER_SEC) {
ad->ad_timestamp.tv_usec -= USEC_PER_SEC;
ad->ad_timestamp.tv_sec++;
}
/*
* XDR the timestamp and possibly some other things, then
* encrypt them.
*/
ixdr = (rpc_inline_t *)cryptbuf;
IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_sec);
IXDR_PUT_INT32(ixdr, ad->ad_timestamp.tv_usec);
if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
IXDR_PUT_U_INT32(ixdr, ad->ad_window);
IXDR_PUT_U_INT32(ixdr, ad->ad_window - 1);
ivec.key.high = ivec.key.low = 0;
status = cbc_crypt((char *)&auth->ah_key, (char *)cryptbuf,
(u_int) 2 * sizeof (des_block),
DES_ENCRYPT | DES_HW, (char *)&ivec);
} else {
status = ecb_crypt((char *)&auth->ah_key, (char *)cryptbuf,
(u_int) sizeof (des_block),
DES_ENCRYPT | DES_HW);
}
if (DES_FAILED(status)) {
syslog(LOG_ERR, "authdes_marshal: DES encryption failure");
return (FALSE);
}
ad->ad_verf.adv_xtimestamp = cryptbuf[0];
if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
ad->ad_cred.adc_fullname.window = cryptbuf[1].key.high;
ad->ad_verf.adv_winverf = cryptbuf[1].key.low;
} else {
ad->ad_cred.adc_nickname = ad->ad_nickname;
ad->ad_verf.adv_winverf = 0;
}
/*
* Serialize the credential and verifier into opaque
* authentication data.
*/
if (ad->ad_cred.adc_namekind == ADN_FULLNAME) {
len = ((1 + 1 + 2 + 1)*BYTES_PER_XDR_UNIT + ad->ad_fullnamelen);
} else {
len = (1 + 1)*BYTES_PER_XDR_UNIT;
}
if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
IXDR_PUT_INT32(ixdr, AUTH_DES);
IXDR_PUT_INT32(ixdr, len);
} else {
ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_cred.oa_flavor));
ATTEMPT(xdr_putint32(xdrs, &len));
}
ATTEMPT(xdr_authdes_cred(xdrs, cred));
len = (2 + 1)*BYTES_PER_XDR_UNIT;
if ((ixdr = xdr_inline(xdrs, 2*BYTES_PER_XDR_UNIT))) {
IXDR_PUT_INT32(ixdr, AUTH_DES);
IXDR_PUT_INT32(ixdr, len);
} else {
ATTEMPT(xdr_putint32(xdrs, (int *)&auth->ah_verf.oa_flavor));
ATTEMPT(xdr_putint32(xdrs, &len));
}
ATTEMPT(xdr_authdes_verf(xdrs, verf));
return (TRUE);
}
/*
* 3. Validate
*/
static bool_t
authdes_validate(AUTH *auth, struct opaque_auth *rverf)
{
/* LINTED pointer alignment */
struct ad_private *ad = AUTH_PRIVATE(auth);
struct authdes_verf verf;
int status;
uint32_t *ixdr;
des_block buf;
if (rverf->oa_length != (2 + 1) * BYTES_PER_XDR_UNIT) {
return (FALSE);
}
/* LINTED pointer alignment */
ixdr = (uint32_t *)rverf->oa_base;
buf.key.high = (uint32_t)*ixdr++;
buf.key.low = (uint32_t)*ixdr++;
verf.adv_int_u = (uint32_t)*ixdr++;
/*
* Decrypt the timestamp
*/
status = ecb_crypt((char *)&auth->ah_key, (char *)&buf,
(u_int)sizeof (des_block), DES_DECRYPT | DES_HW);
if (DES_FAILED(status)) {
syslog(LOG_ERR, "authdes_validate: DES decryption failure");
return (FALSE);
}
/*
* xdr the decrypted timestamp
*/
/* LINTED pointer alignment */
ixdr = (uint32_t *)buf.c;
verf.adv_timestamp.tv_sec = IXDR_GET_INT32(ixdr) + 1;
verf.adv_timestamp.tv_usec = IXDR_GET_INT32(ixdr);
/*
* validate
*/
if (bcmp((char *)&ad->ad_timestamp, (char *)&verf.adv_timestamp,
sizeof(struct timeval)) != 0) {
syslog(LOG_DEBUG, "authdes_validate: verifier mismatch");
return (FALSE);
}
/*
* We have a nickname now, let's use it
*/
ad->ad_nickname = verf.adv_nickname;
ad->ad_cred.adc_namekind = ADN_NICKNAME;
return (TRUE);
}
/*
* 4. Refresh
*/
/*ARGSUSED*/
static bool_t
authdes_refresh(AUTH *auth, void *dummy __unused)
{
/* LINTED pointer alignment */
struct ad_private *ad = AUTH_PRIVATE(auth);
struct authdes_cred *cred = &ad->ad_cred;
int ok;
netobj pkey;
if (ad->ad_dosync) {
ok = __rpc_get_time_offset(&ad->ad_timediff, ad->ad_nis_srvr,
ad->ad_timehost, &(ad->ad_uaddr),
&(ad->ad_netid));
if (! ok) {
/*
* Hope the clocks are synced!
*/
ad->ad_dosync = 0;
syslog(LOG_DEBUG,
"authdes_refresh: unable to synchronize clock");
}
}
ad->ad_xkey = auth->ah_key;
pkey.n_bytes = (char *)(ad->ad_pkey);
pkey.n_len = (u_int)strlen((char *)ad->ad_pkey) + 1;
if (key_encryptsession_pk(ad->ad_servername, &pkey, &ad->ad_xkey) < 0) {
syslog(LOG_INFO,
"authdes_refresh: keyserv(1m) is unable to encrypt session key");
return (FALSE);
}
cred->adc_fullname.key = ad->ad_xkey;
cred->adc_namekind = ADN_FULLNAME;
cred->adc_fullname.name = ad->ad_fullname;
return (TRUE);
}
/*
* 5. Destroy
*/
static void
authdes_destroy(AUTH *auth)
{
/* LINTED pointer alignment */
struct ad_private *ad = AUTH_PRIVATE(auth);
FREE(ad->ad_fullname, ad->ad_fullnamelen + 1);
FREE(ad->ad_servername, ad->ad_servernamelen + 1);
if (ad->ad_timehost)
FREE(ad->ad_timehost, strlen(ad->ad_timehost) + 1);
if (ad->ad_netid)
FREE(ad->ad_netid, strlen(ad->ad_netid) + 1);
if (ad->ad_uaddr)
FREE(ad->ad_uaddr, strlen(ad->ad_uaddr) + 1);
FREE(ad, sizeof (struct ad_private));
FREE(auth, sizeof(AUTH));
}
static struct auth_ops *
authdes_ops(void)
{
static struct auth_ops ops;
/* VARIABLES PROTECTED BY ops_lock: ops */
mutex_lock(&authdes_ops_lock);
if (ops.ah_nextverf == NULL) {
ops.ah_nextverf = authdes_nextverf;
ops.ah_marshal = authdes_marshal;
ops.ah_validate = authdes_validate;
ops.ah_refresh = authdes_refresh;
ops.ah_destroy = authdes_destroy;
}
mutex_unlock(&authdes_ops_lock);
return (&ops);
}
diff --git a/lib/libc/rpc/auth_none.c b/lib/libc/rpc/auth_none.c
index 5a702976cf14..eb763f7324fc 100644
--- a/lib/libc/rpc/auth_none.c
+++ b/lib/libc/rpc/auth_none.c
@@ -1,175 +1,174 @@
/* $NetBSD: auth_none.c,v 1.13 2000/01/22 22:19:17 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)auth_none.c 1.19 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)auth_none.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* auth_none.c
* Creates a client authentication handle for passing "null"
* credentials and verifiers to remote systems.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include "reentrant.h"
#include <assert.h>
#include <stdlib.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include "un-namespace.h"
#include "mt_misc.h"
#define MAX_MARSHAL_SIZE 20
/*
* Authenticator operations routines
*/
static bool_t authnone_marshal (AUTH *, XDR *);
static void authnone_verf (AUTH *);
static bool_t authnone_validate (AUTH *, struct opaque_auth *);
static bool_t authnone_refresh (AUTH *, void *);
static void authnone_destroy (AUTH *);
extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *);
static struct auth_ops *authnone_ops(void);
static struct authnone_private {
AUTH no_client;
char marshalled_client[MAX_MARSHAL_SIZE];
u_int mcnt;
} *authnone_private;
AUTH *
authnone_create(void)
{
struct authnone_private *ap = authnone_private;
XDR xdr_stream;
XDR *xdrs;
mutex_lock(&authnone_lock);
if (ap == NULL) {
ap = calloc(1, sizeof (*ap));
if (ap == NULL) {
mutex_unlock(&authnone_lock);
return (0);
}
authnone_private = ap;
}
if (!ap->mcnt) {
ap->no_client.ah_cred = ap->no_client.ah_verf = _null_auth;
ap->no_client.ah_ops = authnone_ops();
xdrs = &xdr_stream;
xdrmem_create(xdrs, ap->marshalled_client,
(u_int)MAX_MARSHAL_SIZE, XDR_ENCODE);
(void)xdr_opaque_auth(xdrs, &ap->no_client.ah_cred);
(void)xdr_opaque_auth(xdrs, &ap->no_client.ah_verf);
ap->mcnt = XDR_GETPOS(xdrs);
XDR_DESTROY(xdrs);
}
mutex_unlock(&authnone_lock);
return (&ap->no_client);
}
/*ARGSUSED*/
static bool_t
authnone_marshal(AUTH *client, XDR *xdrs)
{
struct authnone_private *ap;
bool_t dummy;
assert(xdrs != NULL);
ap = authnone_private;
if (ap == NULL) {
mutex_unlock(&authnone_lock);
return (FALSE);
}
dummy = (*xdrs->x_ops->x_putbytes)(xdrs,
ap->marshalled_client, ap->mcnt);
mutex_unlock(&authnone_lock);
return (dummy);
}
/* All these unused parameters are required to keep ANSI-C from grumbling */
/*ARGSUSED*/
static void
authnone_verf(AUTH *client)
{
}
/*ARGSUSED*/
static bool_t
authnone_validate(AUTH *client, struct opaque_auth *opaque)
{
return (TRUE);
}
/*ARGSUSED*/
static bool_t
authnone_refresh(AUTH *client, void *dummy)
{
return (FALSE);
}
/*ARGSUSED*/
static void
authnone_destroy(AUTH *client)
{
}
static struct auth_ops *
authnone_ops(void)
{
static struct auth_ops ops;
/* VARIABLES PROTECTED BY ops_lock: ops */
mutex_lock(&ops_lock);
if (ops.ah_nextverf == NULL) {
ops.ah_nextverf = authnone_verf;
ops.ah_marshal = authnone_marshal;
ops.ah_validate = authnone_validate;
ops.ah_refresh = authnone_refresh;
ops.ah_destroy = authnone_destroy;
}
mutex_unlock(&ops_lock);
return (&ops);
}
diff --git a/lib/libc/rpc/auth_time.c b/lib/libc/rpc/auth_time.c
index 8709dea3cfe6..6fd3169bbdc4 100644
--- a/lib/libc/rpc/auth_time.c
+++ b/lib/libc/rpc/auth_time.c
@@ -1,500 +1,499 @@
/* #pragma ident "@(#)auth_time.c 1.4 92/11/10 SMI" */
/*
* auth_time.c
*
* This module contains the private function __rpc_get_time_offset()
* which will return the difference in seconds between the local system's
* notion of time and a remote server's notion of time. This must be
* possible without calling any functions that may invoke the name
* service. (netdir_getbyxxx, getXbyY, etc). The function is used in the
* synchronize call of the authdes code to synchronize clocks between
* NIS+ clients and their servers.
*
* Note to minimize the amount of duplicate code, portions of the
* synchronize() function were folded into this code, and the synchronize
* call becomes simply a wrapper around this function. Further, if this
* function is called with a timehost it *DOES* recurse to the name
* server so don't use it in that mode if you are doing name service code.
*
* Copyright (c) 1992 Sun Microsystems Inc.
* All rights reserved.
*
* Side effects :
* When called a client handle to a RPCBIND process is created
* and destroyed. Two strings "netid" and "uaddr" are malloc'd
* and returned. The SIGALRM processing is modified only if
* needed to deal with TCP connections.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <syslog.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/signal.h>
#include <sys/errno.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/rpcb_prot.h>
#undef NIS
#include <rpcsvc/nis.h>
#include "un-namespace.h"
extern int _rpc_dtablesize( void );
#ifdef TESTING
#define msg(x) printf("ERROR: %s\n", x)
/* #define msg(x) syslog(LOG_ERR, "%s", x) */
#else
#define msg(x)
#endif
static int saw_alarm = 0;
static void
alarm_hndler(int s)
{
saw_alarm = 1;
return;
}
/*
* The internet time server defines the epoch to be Jan 1, 1900
* whereas UNIX defines it to be Jan 1, 1970. To adjust the result
* from internet time-service time, into UNIX time we subtract the
* following offset :
*/
#define NYEARS (1970 - 1900)
#define TOFFSET ((u_long)60*60*24*(365*NYEARS + (NYEARS/4)))
/*
* Stolen from rpc.nisd:
* Turn a 'universal address' into a struct sockaddr_in.
* Bletch.
*/
static int uaddr_to_sockaddr(char *uaddr, struct sockaddr_in *sin)
{
unsigned char p_bytes[2];
int i;
unsigned long a[6];
i = sscanf(uaddr, "%lu.%lu.%lu.%lu.%lu.%lu", &a[0], &a[1], &a[2],
&a[3], &a[4], &a[5]);
if (i < 6)
return(1);
for (i = 0; i < 4; i++)
sin->sin_addr.s_addr |= (a[i] & 0x000000FF) << (8 * i);
p_bytes[0] = (unsigned char)a[4] & 0x000000FF;
p_bytes[1] = (unsigned char)a[5] & 0x000000FF;
sin->sin_family = AF_INET; /* always */
bcopy((char *)&p_bytes, (char *)&sin->sin_port, 2);
return (0);
}
/*
* free_eps()
*
* Free the strings that were strduped into the eps structure.
*/
static void
free_eps(endpoint eps[], int num)
{
int i;
for (i = 0; i < num; i++) {
free(eps[i].uaddr);
free(eps[i].proto);
free(eps[i].family);
}
return;
}
/*
* get_server()
*
* This function constructs a nis_server structure description for the
* indicated hostname.
*
* NOTE: There is a chance we may end up recursing here due to the
* fact that gethostbyname() could do an NIS search. Ideally, the
* NIS+ server will call __rpc_get_time_offset() with the nis_server
* structure already populated.
*
* host - name of the time host
* srv - nis_server struct to use.
* eps[] - array of endpoints
* maxep - max array size
*/
static nis_server *
get_server(struct sockaddr_in *sin, char *host, nis_server *srv,
endpoint eps[], int maxep)
{
char hname[256];
int num_ep = 0, i;
struct hostent *he;
struct hostent dummy;
char *ptr[2];
endpoint *ep;
if (host == NULL && sin == NULL)
return (NULL);
if (sin == NULL) {
he = gethostbyname(host);
if (he == NULL)
return(NULL);
} else {
he = &dummy;
ptr[0] = (char *)&sin->sin_addr.s_addr;
ptr[1] = NULL;
dummy.h_addr_list = ptr;
}
/*
* This is lame. We go around once for TCP, then again
* for UDP.
*/
for (i = 0, ep = eps; (he->h_addr_list[i] != NULL) && (num_ep < maxep);
i++, ep++, num_ep++) {
struct in_addr *a;
a = (struct in_addr *)he->h_addr_list[i];
snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a));
ep->uaddr = strdup(hname);
ep->family = strdup("inet");
ep->proto = strdup("tcp");
if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) {
free_eps(eps, num_ep + 1);
return (NULL);
}
}
for (i = 0; (he->h_addr_list[i] != NULL) && (num_ep < maxep);
i++, ep++, num_ep++) {
struct in_addr *a;
a = (struct in_addr *)he->h_addr_list[i];
snprintf(hname, sizeof(hname), "%s.0.111", inet_ntoa(*a));
ep->uaddr = strdup(hname);
ep->family = strdup("inet");
ep->proto = strdup("udp");
if (ep->uaddr == NULL || ep->family == NULL || ep->proto == NULL) {
free_eps(eps, num_ep + 1);
return (NULL);
}
}
srv->name = (nis_name) host;
srv->ep.ep_len = num_ep;
srv->ep.ep_val = eps;
srv->key_type = NIS_PK_NONE;
srv->pkey.n_bytes = NULL;
srv->pkey.n_len = 0;
return (srv);
}
/*
* __rpc_get_time_offset()
*
* This function uses a nis_server structure to contact the a remote
* machine (as named in that structure) and returns the offset in time
* between that machine and this one. This offset is returned in seconds
* and may be positive or negative.
*
* The first time through, a lot of fiddling is done with the netconfig
* stuff to find a suitable transport. The function is very aggressive
* about choosing UDP or at worst TCP if it can. This is because
* those transports support both the RCPBIND call and the internet
* time service.
*
* Once through, *uaddr is set to the universal address of
* the machine and *netid is set to the local netid for the transport
* that uaddr goes with. On the second call, the netconfig stuff
* is skipped and the uaddr/netid pair are used to fetch the netconfig
* structure and to then contact the machine for the time.
*
* td = "server" - "client"
*
* td - Time difference
* srv - NIS Server description
* thost - if no server, this is the timehost
* uaddr - known universal address
* netid - known network identifier
*/
int
__rpc_get_time_offset(struct timeval *td, nis_server *srv, char *thost,
char **uaddr, struct sockaddr_in *netid)
{
CLIENT *clnt; /* Client handle */
endpoint *ep, /* useful endpoints */
*useep = NULL; /* endpoint of xp */
char *useua = NULL; /* uaddr of selected xp */
int epl, i; /* counters */
enum clnt_stat status; /* result of clnt_call */
u_long thetime, delta;
int needfree = 0;
struct timeval tv;
int time_valid;
int udp_ep = -1, tcp_ep = -1;
int a1, a2, a3, a4;
char ut[64], ipuaddr[64];
endpoint teps[32];
nis_server tsrv;
void (*oldsig)(int) = NULL; /* old alarm handler */
struct sockaddr_in sin;
socklen_t len;
int s = RPC_ANYSOCK;
int type = 0;
td->tv_sec = 0;
td->tv_usec = 0;
/*
* First check to see if we need to find and address for this
* server.
*/
if (*uaddr == NULL) {
if ((srv != NULL) && (thost != NULL)) {
msg("both timehost and srv pointer used!");
return (0);
}
if (! srv) {
srv = get_server(netid, thost, &tsrv, teps, 32);
if (srv == NULL) {
msg("unable to contruct server data.");
return (0);
}
needfree = 1; /* need to free data in endpoints */
}
ep = srv->ep.ep_val;
epl = srv->ep.ep_len;
/* Identify the TCP and UDP endpoints */
for (i = 0;
(i < epl) && ((udp_ep == -1) || (tcp_ep == -1)); i++) {
if (strcasecmp(ep[i].proto, "udp") == 0)
udp_ep = i;
if (strcasecmp(ep[i].proto, "tcp") == 0)
tcp_ep = i;
}
/* Check to see if it is UDP or TCP */
if (tcp_ep > -1) {
useep = &ep[tcp_ep];
useua = ep[tcp_ep].uaddr;
type = SOCK_STREAM;
} else if (udp_ep > -1) {
useep = &ep[udp_ep];
useua = ep[udp_ep].uaddr;
type = SOCK_DGRAM;
}
if (useep == NULL) {
msg("no acceptable transport endpoints.");
if (needfree)
free_eps(teps, tsrv.ep.ep_len);
return (0);
}
}
/*
* Create a sockaddr from the uaddr.
*/
if (*uaddr != NULL)
useua = *uaddr;
/* Fixup test for NIS+ */
sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4);
sprintf(ipuaddr, "%d.%d.%d.%d.0.111", a1, a2, a3, a4);
useua = &ipuaddr[0];
bzero((char *)&sin, sizeof(sin));
if (uaddr_to_sockaddr(useua, &sin)) {
msg("unable to translate uaddr to sockaddr.");
if (needfree)
free_eps(teps, tsrv.ep.ep_len);
return (0);
}
/*
* Create the client handle to rpcbind. Note we always try
* version 3 since that is the earliest version that supports
* the RPCB_GETTIME call. Also it is the version that comes
* standard with SVR4. Since most everyone supports TCP/IP
* we could consider trying the rtime call first.
*/
clnt = clnttcp_create(&sin, RPCBPROG, RPCBVERS, &s, 0, 0);
if (clnt == NULL) {
msg("unable to create client handle to rpcbind.");
if (needfree)
free_eps(teps, tsrv.ep.ep_len);
return (0);
}
tv.tv_sec = 5;
tv.tv_usec = 0;
time_valid = 0;
status = clnt_call(clnt, RPCBPROC_GETTIME, (xdrproc_t)xdr_void, NULL,
(xdrproc_t)xdr_u_long, &thetime, tv);
/*
* The only error we check for is anything but success. In
* fact we could have seen PROGMISMATCH if talking to a 4.1
* machine (pmap v2) or TIMEDOUT if the net was busy.
*/
if (status == RPC_SUCCESS)
time_valid = 1;
else {
int save;
/* Blow away possible stale CLNT handle. */
if (clnt != NULL) {
clnt_destroy(clnt);
clnt = NULL;
}
/*
* Convert PMAP address into timeservice address
* We take advantage of the fact that we "know" what
* the universal address looks like for inet transports.
*
* We also know that the internet timeservice is always
* listening on port 37.
*/
sscanf(useua, "%d.%d.%d.%d.", &a1, &a2, &a3, &a4);
sprintf(ut, "%d.%d.%d.%d.0.37", a1, a2, a3, a4);
if (uaddr_to_sockaddr(ut, &sin)) {
msg("cannot convert timeservice uaddr to sockaddr.");
goto error;
}
s = _socket(AF_INET, type, 0);
if (s == -1) {
msg("unable to open fd to network.");
goto error;
}
/*
* Now depending on whether or not we're talking to
* UDP we set a timeout or not.
*/
if (type == SOCK_DGRAM) {
struct timeval timeout = { 20, 0 };
struct sockaddr_in from;
fd_set readfds;
int res;
if (_sendto(s, &thetime, sizeof(thetime), 0,
(struct sockaddr *)&sin, sizeof(sin)) == -1) {
msg("udp : sendto failed.");
goto error;
}
do {
FD_ZERO(&readfds);
FD_SET(s, &readfds);
res = _select(_rpc_dtablesize(), &readfds,
(fd_set *)NULL, (fd_set *)NULL, &timeout);
} while (res < 0 && errno == EINTR);
if (res <= 0)
goto error;
len = sizeof(from);
res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0,
(struct sockaddr *)&from, &len);
if (res == -1) {
msg("recvfrom failed on udp transport.");
goto error;
}
time_valid = 1;
} else {
int res;
oldsig = (void (*)(int))signal(SIGALRM, alarm_hndler);
saw_alarm = 0; /* global tracking the alarm */
alarm(20); /* only wait 20 seconds */
res = _connect(s, (struct sockaddr *)&sin, sizeof(sin));
if (res == -1) {
msg("failed to connect to tcp endpoint.");
goto error;
}
if (saw_alarm) {
msg("alarm caught it, must be unreachable.");
goto error;
}
res = _read(s, (char *)&thetime, sizeof(thetime));
if (res != sizeof(thetime)) {
if (saw_alarm)
msg("timed out TCP call.");
else
msg("wrong size of results returned");
goto error;
}
time_valid = 1;
}
save = errno;
(void)_close(s);
errno = save;
s = RPC_ANYSOCK;
if (time_valid) {
thetime = ntohl(thetime);
thetime = thetime - TOFFSET; /* adjust to UNIX time */
} else
thetime = 0;
}
gettimeofday(&tv, 0);
error:
/*
* clean up our allocated data structures.
*/
if (s != RPC_ANYSOCK)
(void)_close(s);
if (clnt != NULL)
clnt_destroy(clnt);
alarm(0); /* reset that alarm if its outstanding */
if (oldsig) {
signal(SIGALRM, oldsig);
}
/*
* note, don't free uaddr strings until after we've made a
* copy of them.
*/
if (time_valid) {
if (*uaddr == NULL)
*uaddr = strdup(useua);
/* Round to the nearest second */
tv.tv_sec += (tv.tv_sec > 500000) ? 1 : 0;
delta = (thetime > tv.tv_sec) ? thetime - tv.tv_sec :
tv.tv_sec - thetime;
td->tv_sec = (thetime < tv.tv_sec) ? - delta : delta;
td->tv_usec = 0;
} else {
msg("unable to get the server's time.");
}
if (needfree)
free_eps(teps, tsrv.ep.ep_len);
return (time_valid);
}
diff --git a/lib/libc/rpc/auth_unix.c b/lib/libc/rpc/auth_unix.c
index 36b6a5b49e3b..851c410c6782 100644
--- a/lib/libc/rpc/auth_unix.c
+++ b/lib/libc/rpc/auth_unix.c
@@ -1,370 +1,369 @@
/* $NetBSD: auth_unix.c,v 1.18 2000/07/06 03:03:30 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)auth_unix.c 1.19 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)auth_unix.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* auth_unix.c, Implements UNIX style authentication parameters.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* The system is very weak. The client uses no encryption for it's
* credentials and only sends null verifiers. The server sends backs
* null verifiers or optionally a verifier that suggests a new short hand
* for the credentials.
*
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <assert.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/auth_unix.h>
#include "un-namespace.h"
#include "mt_misc.h"
/* auth_unix.c */
static void authunix_nextverf (AUTH *);
static bool_t authunix_marshal (AUTH *, XDR *);
static bool_t authunix_validate (AUTH *, struct opaque_auth *);
static bool_t authunix_refresh (AUTH *, void *);
static void authunix_destroy (AUTH *);
static void marshal_new_auth (AUTH *);
static struct auth_ops *authunix_ops (void);
/*
* This struct is pointed to by the ah_private field of an auth_handle.
*/
struct audata {
struct opaque_auth au_origcred; /* original credentials */
struct opaque_auth au_shcred; /* short hand cred */
u_long au_shfaults; /* short hand cache faults */
char au_marshed[MAX_AUTH_BYTES];
u_int au_mpos; /* xdr pos at end of marshed */
};
#define AUTH_PRIVATE(auth) ((struct audata *)auth->ah_private)
/*
* Create a unix style authenticator.
* Returns an auth handle with the given stuff in it.
*/
AUTH *
authunix_create(char *machname, u_int uid, u_int gid, int len, u_int *aup_gids)
{
struct authunix_parms aup;
char mymem[MAX_AUTH_BYTES];
struct timeval now;
XDR xdrs;
AUTH *auth;
struct audata *au;
/*
* Allocate and set up auth handle
*/
au = NULL;
auth = mem_alloc(sizeof(*auth));
#ifndef _KERNEL
if (auth == NULL) {
warnx("authunix_create: out of memory");
goto cleanup_authunix_create;
}
#endif
au = mem_alloc(sizeof(*au));
#ifndef _KERNEL
if (au == NULL) {
warnx("authunix_create: out of memory");
goto cleanup_authunix_create;
}
#endif
auth->ah_ops = authunix_ops();
auth->ah_private = (caddr_t)au;
auth->ah_verf = au->au_shcred = _null_auth;
au->au_shfaults = 0;
au->au_origcred.oa_base = NULL;
/*
* fill in param struct from the given params
*/
(void)gettimeofday(&now, NULL);
aup.aup_time = now.tv_sec;
aup.aup_machname = machname;
aup.aup_uid = uid;
aup.aup_gid = gid;
aup.aup_len = (u_int)len;
aup.aup_gids = aup_gids;
/*
* Serialize the parameters into origcred
*/
xdrmem_create(&xdrs, mymem, MAX_AUTH_BYTES, XDR_ENCODE);
if (! xdr_authunix_parms(&xdrs, &aup))
abort();
au->au_origcred.oa_length = len = XDR_GETPOS(&xdrs);
au->au_origcred.oa_flavor = AUTH_UNIX;
#ifdef _KERNEL
au->au_origcred.oa_base = mem_alloc((u_int) len);
#else
if ((au->au_origcred.oa_base = mem_alloc((u_int) len)) == NULL) {
warnx("authunix_create: out of memory");
goto cleanup_authunix_create;
}
#endif
memmove(au->au_origcred.oa_base, mymem, (size_t)len);
/*
* set auth handle to reflect new cred.
*/
auth->ah_cred = au->au_origcred;
marshal_new_auth(auth);
return (auth);
#ifndef _KERNEL
cleanup_authunix_create:
if (auth)
mem_free(auth, sizeof(*auth));
if (au) {
if (au->au_origcred.oa_base)
mem_free(au->au_origcred.oa_base, (u_int)len);
mem_free(au, sizeof(*au));
}
return (NULL);
#endif
}
/*
* Returns an auth handle with parameters determined by doing lots of
* syscalls.
*/
AUTH *
authunix_create_default(void)
{
AUTH *auth;
int ngids;
long ngids_max;
char machname[MAXHOSTNAMELEN + 1];
uid_t uid;
gid_t gid;
gid_t *gids;
ngids_max = sysconf(_SC_NGROUPS_MAX) + 1;
gids = malloc(sizeof(gid_t) * ngids_max);
if (gids == NULL)
return (NULL);
if (gethostname(machname, sizeof machname) == -1)
abort();
machname[sizeof(machname) - 1] = 0;
uid = geteuid();
gid = getegid();
if ((ngids = getgroups(ngids_max, gids)) < 0)
abort();
if (ngids > NGRPS)
ngids = NGRPS;
/* XXX: interface problem; we should translate from uid_t and gid_t */
auth = authunix_create(machname, uid, gid, ngids, gids);
free(gids);
return (auth);
}
/*
* authunix operations
*/
/* ARGSUSED */
static void
authunix_nextverf(AUTH *auth)
{
/* no action necessary */
}
static bool_t
authunix_marshal(AUTH *auth, XDR *xdrs)
{
struct audata *au;
assert(auth != NULL);
assert(xdrs != NULL);
au = AUTH_PRIVATE(auth);
return (XDR_PUTBYTES(xdrs, au->au_marshed, au->au_mpos));
}
static bool_t
authunix_validate(AUTH *auth, struct opaque_auth *verf)
{
struct audata *au;
XDR xdrs;
assert(auth != NULL);
assert(verf != NULL);
if (verf->oa_flavor == AUTH_SHORT) {
au = AUTH_PRIVATE(auth);
xdrmem_create(&xdrs, verf->oa_base, verf->oa_length,
XDR_DECODE);
if (au->au_shcred.oa_base != NULL) {
mem_free(au->au_shcred.oa_base,
au->au_shcred.oa_length);
au->au_shcred.oa_base = NULL;
}
if (xdr_opaque_auth(&xdrs, &au->au_shcred)) {
auth->ah_cred = au->au_shcred;
} else {
xdrs.x_op = XDR_FREE;
(void)xdr_opaque_auth(&xdrs, &au->au_shcred);
au->au_shcred.oa_base = NULL;
auth->ah_cred = au->au_origcred;
}
marshal_new_auth(auth);
}
return (TRUE);
}
static bool_t
authunix_refresh(AUTH *auth, void *dummy)
{
struct audata *au = AUTH_PRIVATE(auth);
struct authunix_parms aup;
struct timeval now;
XDR xdrs;
int stat;
assert(auth != NULL);
if (auth->ah_cred.oa_base == au->au_origcred.oa_base) {
/* there is no hope. Punt */
return (FALSE);
}
au->au_shfaults ++;
/* first deserialize the creds back into a struct authunix_parms */
aup.aup_machname = NULL;
aup.aup_gids = NULL;
xdrmem_create(&xdrs, au->au_origcred.oa_base,
au->au_origcred.oa_length, XDR_DECODE);
stat = xdr_authunix_parms(&xdrs, &aup);
if (! stat)
goto done;
/* update the time and serialize in place */
(void)gettimeofday(&now, NULL);
aup.aup_time = now.tv_sec;
xdrs.x_op = XDR_ENCODE;
XDR_SETPOS(&xdrs, 0);
stat = xdr_authunix_parms(&xdrs, &aup);
if (! stat)
goto done;
auth->ah_cred = au->au_origcred;
marshal_new_auth(auth);
done:
/* free the struct authunix_parms created by deserializing */
xdrs.x_op = XDR_FREE;
(void)xdr_authunix_parms(&xdrs, &aup);
XDR_DESTROY(&xdrs);
return (stat);
}
static void
authunix_destroy(AUTH *auth)
{
struct audata *au;
assert(auth != NULL);
au = AUTH_PRIVATE(auth);
mem_free(au->au_origcred.oa_base, au->au_origcred.oa_length);
if (au->au_shcred.oa_base != NULL)
mem_free(au->au_shcred.oa_base, au->au_shcred.oa_length);
mem_free(auth->ah_private, sizeof(struct audata));
if (auth->ah_verf.oa_base != NULL)
mem_free(auth->ah_verf.oa_base, auth->ah_verf.oa_length);
mem_free(auth, sizeof(*auth));
}
/*
* Marshals (pre-serializes) an auth struct.
* sets private data, au_marshed and au_mpos
*/
static void
marshal_new_auth(AUTH *auth)
{
XDR xdr_stream;
XDR *xdrs = &xdr_stream;
struct audata *au;
assert(auth != NULL);
au = AUTH_PRIVATE(auth);
xdrmem_create(xdrs, au->au_marshed, MAX_AUTH_BYTES, XDR_ENCODE);
if ((! xdr_opaque_auth(xdrs, &(auth->ah_cred))) ||
(! xdr_opaque_auth(xdrs, &(auth->ah_verf))))
warnx("auth_none.c - Fatal marshalling problem");
else
au->au_mpos = XDR_GETPOS(xdrs);
XDR_DESTROY(xdrs);
}
static struct auth_ops *
authunix_ops(void)
{
static struct auth_ops ops;
/* VARIABLES PROTECTED BY ops_lock: ops */
mutex_lock(&ops_lock);
if (ops.ah_nextverf == NULL) {
ops.ah_nextverf = authunix_nextverf;
ops.ah_marshal = authunix_marshal;
ops.ah_validate = authunix_validate;
ops.ah_refresh = authunix_refresh;
ops.ah_destroy = authunix_destroy;
}
mutex_unlock(&ops_lock);
return (&ops);
}
diff --git a/lib/libc/rpc/authdes_prot.c b/lib/libc/rpc/authdes_prot.c
index 94168a0dbcd0..4d1391d61a56 100644
--- a/lib/libc/rpc/authdes_prot.c
+++ b/lib/libc/rpc/authdes_prot.c
@@ -1,89 +1,88 @@
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)authdes_prot.c 2.1 88/07/29 4.0 RPCSRC; from 1.6 88/02/08 SMI";
#endif
-#include <sys/cdefs.h>
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
/*
* authdes_prot.c, XDR routines for DES authentication
*/
#include "namespace.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/auth_des.h>
#include "un-namespace.h"
#define ATTEMPT(xdr_op) if (!(xdr_op)) return (FALSE)
bool_t
xdr_authdes_cred(XDR *xdrs, struct authdes_cred *cred)
{
enum authdes_namekind *padc_namekind = &cred->adc_namekind;
/*
* Unrolled xdr
*/
ATTEMPT(xdr_enum(xdrs, (enum_t *) padc_namekind));
switch (cred->adc_namekind) {
case ADN_FULLNAME:
ATTEMPT(xdr_string(xdrs, &cred->adc_fullname.name,
MAXNETNAMELEN));
ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.key,
sizeof(des_block)));
ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_fullname.window,
sizeof(cred->adc_fullname.window)));
return (TRUE);
case ADN_NICKNAME:
ATTEMPT(xdr_opaque(xdrs, (caddr_t)&cred->adc_nickname,
sizeof(cred->adc_nickname)));
return (TRUE);
default:
return (FALSE);
}
}
bool_t
xdr_authdes_verf(XDR *xdrs, struct authdes_verf *verf)
{
/*
* Unrolled xdr
*/
ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_xtimestamp,
sizeof(des_block)));
ATTEMPT(xdr_opaque(xdrs, (caddr_t)&verf->adv_int_u,
sizeof(verf->adv_int_u)));
return (TRUE);
}
diff --git a/lib/libc/rpc/authunix_prot.c b/lib/libc/rpc/authunix_prot.c
index 0f2fc8a22f45..6dd0f6123446 100644
--- a/lib/libc/rpc/authunix_prot.c
+++ b/lib/libc/rpc/authunix_prot.c
@@ -1,76 +1,75 @@
/* $NetBSD: authunix_prot.c,v 1.12 2000/01/22 22:19:17 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)authunix_prot.c 1.15 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)authunix_prot.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* authunix_prot.c
* XDR for UNIX style authentication parameters for RPC
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <assert.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/auth_unix.h>
#include "un-namespace.h"
/*
* XDR for unix authentication parameters.
*/
bool_t
xdr_authunix_parms(XDR *xdrs, struct authunix_parms *p)
{
u_int **paup_gids;
assert(xdrs != NULL);
assert(p != NULL);
paup_gids = &p->aup_gids;
if (xdr_u_long(xdrs, &(p->aup_time)) &&
xdr_string(xdrs, &(p->aup_machname), MAX_MACHINE_NAME) &&
xdr_u_int(xdrs, &(p->aup_uid)) &&
xdr_u_int(xdrs, &(p->aup_gid)) &&
xdr_array(xdrs, (char **) paup_gids,
&(p->aup_len), NGRPS, sizeof(u_int), (xdrproc_t)xdr_u_int) ) {
return (TRUE);
}
return (FALSE);
}
diff --git a/lib/libc/rpc/bindresvport.c b/lib/libc/rpc/bindresvport.c
index 53abc2b2b64c..52488ac55d6f 100644
--- a/lib/libc/rpc/bindresvport.c
+++ b/lib/libc/rpc/bindresvport.c
@@ -1,156 +1,155 @@
/* $NetBSD: bindresvport.c,v 1.19 2000/07/06 03:03:59 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "from: @(#)bindresvport.c 1.8 88/02/08 SMI";
static char *sccsid = "from: @(#)bindresvport.c 2.2 88/07/29 4.0 RPCSRC";
#endif
/* from: $OpenBSD: bindresvport.c,v 1.7 1996/07/30 16:25:47 downsj Exp $ */
-#include <sys/cdefs.h>
/*
* Copyright (c) 1987 by Sun Microsystems, Inc.
*
* Portions Copyright(C) 1996, Jason Downs. All rights reserved.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <string.h>
#include "un-namespace.h"
/*
* Bind a socket to a privileged IP port
*/
int
bindresvport(int sd, struct sockaddr_in *sin)
{
return bindresvport_sa(sd, (struct sockaddr *)sin);
}
/*
* Bind a socket to a privileged IP port
*/
int
bindresvport_sa(int sd, struct sockaddr *sa)
{
int old, error, af;
struct sockaddr_storage myaddr;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
int proto, portrange, portlow;
u_int16_t *portp;
socklen_t salen;
if (sa == NULL) {
salen = sizeof(myaddr);
sa = (struct sockaddr *)&myaddr;
if (_getsockname(sd, sa, &salen) == -1)
return -1; /* errno is correctly set */
af = sa->sa_family;
memset(sa, 0, salen);
} else
af = sa->sa_family;
switch (af) {
case AF_INET:
proto = IPPROTO_IP;
portrange = IP_PORTRANGE;
portlow = IP_PORTRANGE_LOW;
sin = (struct sockaddr_in *)sa;
salen = sizeof(struct sockaddr_in);
portp = &sin->sin_port;
break;
#ifdef INET6
case AF_INET6:
proto = IPPROTO_IPV6;
portrange = IPV6_PORTRANGE;
portlow = IPV6_PORTRANGE_LOW;
sin6 = (struct sockaddr_in6 *)sa;
salen = sizeof(struct sockaddr_in6);
portp = &sin6->sin6_port;
break;
#endif
default:
errno = EPFNOSUPPORT;
return (-1);
}
sa->sa_family = af;
sa->sa_len = salen;
if (*portp == 0) {
socklen_t oldlen = sizeof(old);
error = _getsockopt(sd, proto, portrange, &old, &oldlen);
if (error < 0)
return (error);
error = _setsockopt(sd, proto, portrange, &portlow,
sizeof(portlow));
if (error < 0)
return (error);
}
error = _bind(sd, sa, salen);
if (*portp == 0) {
int saved_errno = errno;
if (error < 0) {
if (_setsockopt(sd, proto, portrange, &old,
sizeof(old)) < 0)
errno = saved_errno;
return (error);
}
if (sa != (struct sockaddr *)&myaddr) {
/* Hmm, what did the kernel assign? */
if (_getsockname(sd, sa, &salen) < 0)
errno = saved_errno;
return (error);
}
}
return (error);
}
diff --git a/lib/libc/rpc/clnt_bcast.c b/lib/libc/rpc/clnt_bcast.c
index 6d39bca2f83f..3e748e769081 100644
--- a/lib/libc/rpc/clnt_bcast.c
+++ b/lib/libc/rpc/clnt_bcast.c
@@ -1,678 +1,677 @@
/* $NetBSD: clnt_bcast.c,v 1.3 2000/07/06 03:05:20 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)clnt_bcast.c 1.18 94/05/03 SMI"
static char sccsid[] = "@(#)clnt_bcast.c 1.15 89/04/21 Copyr 1988 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* clnt_bcast.c
* Client interface to broadcast service.
*
* Copyright (C) 1988, Sun Microsystems, Inc.
*
* The following is kludged-up support for simple rpc broadcasts.
* Someday a large, complicated system will replace these routines.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/queue.h>
#include <net/if.h>
#include <netinet/in.h>
#include <ifaddrs.h>
#include <sys/poll.h>
#include <rpc/rpc.h>
#ifdef PORTMAP
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_rmt.h>
#endif /* PORTMAP */
#include <rpc/nettype.h>
#include <arpa/inet.h>
#ifdef RPC_DEBUG
#include <stdio.h>
#endif
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>
#include <err.h>
#include <string.h>
#include "un-namespace.h"
#include "rpc_com.h"
#define MAXBCAST 20 /* Max no of broadcasting transports */
#define INITTIME 4000 /* Time to wait initially */
#define WAITTIME 8000 /* Maximum time to wait */
/*
* If nettype is NULL, it broadcasts on all the available
* datagram_n transports. May potentially lead to broadacst storms
* and hence should be used with caution, care and courage.
*
* The current parameter xdr packet size is limited by the max tsdu
* size of the transport. If the max tsdu size of any transport is
* smaller than the parameter xdr packet, then broadcast is not
* sent on that transport.
*
* Also, the packet size should be less the packet size of
* the data link layer (for ethernet it is 1400 bytes). There is
* no easy way to find out the max size of the data link layer and
* we are assuming that the args would be smaller than that.
*
* The result size has to be smaller than the transport tsdu size.
*
* If PORTMAP has been defined, we send two packets for UDP, one for
* rpcbind and one for portmap. For those machines which support
* both rpcbind and portmap, it will cause them to reply twice, and
* also here it will get two responses ... inefficient and clumsy.
*/
struct broadif {
int index;
struct sockaddr_storage broadaddr;
TAILQ_ENTRY(broadif) link;
};
typedef TAILQ_HEAD(, broadif) broadlist_t;
int __rpc_getbroadifs(int, int, int, broadlist_t *);
void __rpc_freebroadifs(broadlist_t *);
int __rpc_broadenable(int, int, struct broadif *);
int __rpc_lowvers = 0;
int
__rpc_getbroadifs(int af, int proto, int socktype, broadlist_t *list)
{
int count = 0;
struct broadif *bip;
struct ifaddrs *ifap, *ifp;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
struct sockaddr_in *sin;
struct addrinfo hints, *res;
if (getifaddrs(&ifp) < 0)
return 0;
memset(&hints, 0, sizeof hints);
hints.ai_family = af;
hints.ai_protocol = proto;
hints.ai_socktype = socktype;
if (getaddrinfo(NULL, "sunrpc", &hints, &res) != 0) {
freeifaddrs(ifp);
return 0;
}
for (ifap = ifp; ifap != NULL; ifap = ifap->ifa_next) {
if (ifap->ifa_addr->sa_family != af ||
!(ifap->ifa_flags & IFF_UP))
continue;
bip = (struct broadif *)malloc(sizeof *bip);
if (bip == NULL)
break;
bip->index = if_nametoindex(ifap->ifa_name);
if (
#ifdef INET6
af != AF_INET6 &&
#endif
(ifap->ifa_flags & IFF_BROADCAST) &&
ifap->ifa_broadaddr) {
memcpy(&bip->broadaddr, ifap->ifa_broadaddr,
(size_t)ifap->ifa_broadaddr->sa_len);
sin = (struct sockaddr_in *)(void *)&bip->broadaddr;
sin->sin_port =
((struct sockaddr_in *)
(void *)res->ai_addr)->sin_port;
} else
#ifdef INET6
if (af == AF_INET6 && (ifap->ifa_flags & IFF_MULTICAST)) {
sin6 = (struct sockaddr_in6 *)(void *)&bip->broadaddr;
inet_pton(af, RPCB_MULTICAST_ADDR, &sin6->sin6_addr);
sin6->sin6_family = af;
sin6->sin6_len = sizeof *sin6;
sin6->sin6_port =
((struct sockaddr_in6 *)
(void *)res->ai_addr)->sin6_port;
sin6->sin6_scope_id = bip->index;
} else
#endif
{
free(bip);
continue;
}
TAILQ_INSERT_TAIL(list, bip, link);
count++;
}
freeifaddrs(ifp);
freeaddrinfo(res);
return count;
}
void
__rpc_freebroadifs(broadlist_t *list)
{
struct broadif *bip, *next;
bip = TAILQ_FIRST(list);
while (bip != NULL) {
next = TAILQ_NEXT(bip, link);
free(bip);
bip = next;
}
}
int
/*ARGSUSED*/
__rpc_broadenable(int af, int s, struct broadif *bip)
{
int o = 1;
#if 0
if (af == AF_INET6) {
fprintf(stderr, "set v6 multicast if to %d\n", bip->index);
if (_setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &bip->index,
sizeof bip->index) < 0)
return -1;
} else
#endif
if (_setsockopt(s, SOL_SOCKET, SO_BROADCAST, &o, sizeof o) < 0)
return -1;
return 0;
}
/*
* rpc_broadcast_exp()
*
* prog - program number
* vers - version number
* proc - procedure number
* xargs - xdr routine for args
* argsp - pointer to args
* xresults - xdr routine for results
* resultsp - pointer to results
* eachresult - call with each result obtained
* inittime - how long to wait initially
* waittime - maximum time to wait
* nettype - transport type
*/
enum clnt_stat
rpc_broadcast_exp(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc,
xdrproc_t xargs, caddr_t argsp, xdrproc_t xresults, caddr_t resultsp,
resultproc_t eachresult, int inittime, int waittime,
const char *nettype)
{
enum clnt_stat stat = RPC_SUCCESS; /* Return status */
XDR xdr_stream; /* XDR stream */
XDR *xdrs = &xdr_stream;
struct rpc_msg msg; /* RPC message */
struct timeval t;
char *outbuf = NULL; /* Broadcast msg buffer */
char *inbuf = NULL; /* Reply buf */
int inlen;
u_int maxbufsize = 0;
AUTH *sys_auth = authunix_create_default();
u_int i;
void *handle;
char uaddress[1024]; /* A self imposed limit */
char *uaddrp = uaddress;
int pmap_reply_flag; /* reply recvd from PORTMAP */
/* An array of all the suitable broadcast transports */
struct {
int fd; /* File descriptor */
int af;
int proto;
struct netconfig *nconf; /* Netconfig structure */
u_int asize; /* Size of the addr buf */
u_int dsize; /* Size of the data buf */
struct sockaddr_storage raddr; /* Remote address */
broadlist_t nal;
} fdlist[MAXBCAST];
struct pollfd pfd[MAXBCAST];
size_t fdlistno = 0;
struct r_rpcb_rmtcallargs barg; /* Remote arguments */
struct r_rpcb_rmtcallres bres; /* Remote results */
size_t outlen;
struct netconfig *nconf;
int msec;
int pollretval;
int fds_found;
#ifdef PORTMAP
size_t outlen_pmap = 0;
u_long port; /* Remote port number */
int pmap_flag = 0; /* UDP exists ? */
char *outbuf_pmap = NULL;
struct rmtcallargs barg_pmap; /* Remote arguments */
struct rmtcallres bres_pmap; /* Remote results */
u_int udpbufsz = 0;
#endif /* PORTMAP */
if (sys_auth == NULL) {
return (RPC_SYSTEMERROR);
}
/*
* initialization: create a fd, a broadcast address, and send the
* request on the broadcast transport.
* Listen on all of them and on replies, call the user supplied
* function.
*/
if (nettype == NULL)
nettype = "datagram_n";
if ((handle = __rpc_setconf(nettype)) == NULL) {
AUTH_DESTROY(sys_auth);
return (RPC_UNKNOWNPROTO);
}
while ((nconf = __rpc_getconf(handle)) != NULL) {
int fd;
struct __rpc_sockinfo si;
if (nconf->nc_semantics != NC_TPI_CLTS)
continue;
if (fdlistno >= MAXBCAST)
break; /* No more slots available */
if (!__rpc_nconf2sockinfo(nconf, &si))
continue;
TAILQ_INIT(&fdlist[fdlistno].nal);
if (__rpc_getbroadifs(si.si_af, si.si_proto, si.si_socktype,
&fdlist[fdlistno].nal) == 0)
continue;
fd = _socket(si.si_af, si.si_socktype, si.si_proto);
if (fd < 0) {
stat = RPC_CANTSEND;
continue;
}
fdlist[fdlistno].af = si.si_af;
fdlist[fdlistno].proto = si.si_proto;
fdlist[fdlistno].fd = fd;
fdlist[fdlistno].nconf = nconf;
fdlist[fdlistno].asize = __rpc_get_a_size(si.si_af);
pfd[fdlistno].events = POLLIN | POLLPRI |
POLLRDNORM | POLLRDBAND;
pfd[fdlistno].fd = fdlist[fdlistno].fd = fd;
fdlist[fdlistno].dsize = __rpc_get_t_size(si.si_af, si.si_proto,
0);
if (maxbufsize <= fdlist[fdlistno].dsize)
maxbufsize = fdlist[fdlistno].dsize;
#ifdef PORTMAP
if (si.si_af == AF_INET && si.si_proto == IPPROTO_UDP) {
udpbufsz = fdlist[fdlistno].dsize;
outbuf_pmap = reallocf(outbuf_pmap, udpbufsz);
if (outbuf_pmap == NULL) {
_close(fd);
stat = RPC_SYSTEMERROR;
goto done_broad;
}
pmap_flag = 1;
}
#endif /* PORTMAP */
fdlistno++;
}
if (fdlistno == 0) {
if (stat == RPC_SUCCESS)
stat = RPC_UNKNOWNPROTO;
goto done_broad;
}
if (maxbufsize == 0) {
if (stat == RPC_SUCCESS)
stat = RPC_CANTSEND;
goto done_broad;
}
inbuf = malloc(maxbufsize);
outbuf = malloc(maxbufsize);
if ((inbuf == NULL) || (outbuf == NULL)) {
stat = RPC_SYSTEMERROR;
goto done_broad;
}
/* Serialize all the arguments which have to be sent */
(void) gettimeofday(&t, NULL);
msg.rm_xid = __RPC_GETXID(&t);
msg.rm_direction = CALL;
msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
msg.rm_call.cb_prog = RPCBPROG;
msg.rm_call.cb_vers = RPCBVERS;
msg.rm_call.cb_proc = RPCBPROC_CALLIT;
barg.prog = prog;
barg.vers = vers;
barg.proc = proc;
barg.args.args_val = argsp;
barg.xdr_args = xargs;
bres.addr = uaddrp;
bres.results.results_val = resultsp;
bres.xdr_res = xresults;
msg.rm_call.cb_cred = sys_auth->ah_cred;
msg.rm_call.cb_verf = sys_auth->ah_verf;
xdrmem_create(xdrs, outbuf, maxbufsize, XDR_ENCODE);
if ((!xdr_callmsg(xdrs, &msg)) ||
(!xdr_rpcb_rmtcallargs(xdrs,
(struct rpcb_rmtcallargs *)(void *)&barg))) {
stat = RPC_CANTENCODEARGS;
goto done_broad;
}
outlen = xdr_getpos(xdrs);
xdr_destroy(xdrs);
#ifdef PORTMAP
/* Prepare the packet for version 2 PORTMAP */
if (pmap_flag) {
msg.rm_xid++; /* One way to distinguish */
msg.rm_call.cb_prog = PMAPPROG;
msg.rm_call.cb_vers = PMAPVERS;
msg.rm_call.cb_proc = PMAPPROC_CALLIT;
barg_pmap.prog = prog;
barg_pmap.vers = vers;
barg_pmap.proc = proc;
barg_pmap.args_ptr = argsp;
barg_pmap.xdr_args = xargs;
bres_pmap.port_ptr = &port;
bres_pmap.xdr_results = xresults;
bres_pmap.results_ptr = resultsp;
xdrmem_create(xdrs, outbuf_pmap, udpbufsz, XDR_ENCODE);
if ((! xdr_callmsg(xdrs, &msg)) ||
(! xdr_rmtcall_args(xdrs, &barg_pmap))) {
stat = RPC_CANTENCODEARGS;
goto done_broad;
}
outlen_pmap = xdr_getpos(xdrs);
xdr_destroy(xdrs);
}
#endif /* PORTMAP */
/*
* Basic loop: broadcast the packets to transports which
* support data packets of size such that one can encode
* all the arguments.
* Wait a while for response(s).
* The response timeout grows larger per iteration.
*/
for (msec = inittime; msec <= waittime; msec += msec) {
struct broadif *bip;
/* Broadcast all the packets now */
for (i = 0; i < fdlistno; i++) {
if (fdlist[i].dsize < outlen) {
stat = RPC_CANTSEND;
continue;
}
for (bip = TAILQ_FIRST(&fdlist[i].nal); bip != NULL;
bip = TAILQ_NEXT(bip, link)) {
void *addr;
addr = &bip->broadaddr;
__rpc_broadenable(fdlist[i].af, fdlist[i].fd,
bip);
/*
* Only use version 3 if lowvers is not set
*/
if (!__rpc_lowvers)
if (_sendto(fdlist[i].fd, outbuf,
outlen, 0, (struct sockaddr*)addr,
(size_t)fdlist[i].asize) !=
outlen) {
#ifdef RPC_DEBUG
perror("sendto");
#endif
warnx("clnt_bcast: cannot send "
"broadcast packet");
stat = RPC_CANTSEND;
continue;
}
#ifdef RPC_DEBUG
if (!__rpc_lowvers)
fprintf(stderr, "Broadcast packet sent "
"for %s\n",
fdlist[i].nconf->nc_netid);
#endif
#ifdef PORTMAP
/*
* Send the version 2 packet also
* for UDP/IP
*/
if (pmap_flag &&
fdlist[i].proto == IPPROTO_UDP) {
if (_sendto(fdlist[i].fd, outbuf_pmap,
outlen_pmap, 0, addr,
(size_t)fdlist[i].asize) !=
outlen_pmap) {
warnx("clnt_bcast: "
"Cannot send broadcast packet");
stat = RPC_CANTSEND;
continue;
}
}
#ifdef RPC_DEBUG
fprintf(stderr, "PMAP Broadcast packet "
"sent for %s\n",
fdlist[i].nconf->nc_netid);
#endif
#endif /* PORTMAP */
}
/* End for sending all packets on this transport */
} /* End for sending on all transports */
if (eachresult == NULL) {
stat = RPC_SUCCESS;
goto done_broad;
}
/*
* Get all the replies from these broadcast requests
*/
recv_again:
switch (pollretval = _poll(pfd, fdlistno, msec)) {
case 0: /* timed out */
stat = RPC_TIMEDOUT;
continue;
case -1: /* some kind of error - we ignore it */
goto recv_again;
} /* end of poll results switch */
for (i = fds_found = 0;
i < fdlistno && fds_found < pollretval; i++) {
bool_t done = FALSE;
if (pfd[i].revents == 0)
continue;
else if (pfd[i].revents & POLLNVAL) {
/*
* Something bad has happened to this descri-
* ptor. We can cause _poll() to ignore
* it simply by using a negative fd. We do that
* rather than compacting the pfd[] and fdlist[]
* arrays.
*/
pfd[i].fd = -1;
fds_found++;
continue;
} else
fds_found++;
#ifdef RPC_DEBUG
fprintf(stderr, "response for %s\n",
fdlist[i].nconf->nc_netid);
#endif
try_again:
inlen = _recvfrom(fdlist[i].fd, inbuf, fdlist[i].dsize,
0, (struct sockaddr *)(void *)&fdlist[i].raddr,
&fdlist[i].asize);
if (inlen < 0) {
if (errno == EINTR)
goto try_again;
warnx("clnt_bcast: Cannot receive reply to "
"broadcast");
stat = RPC_CANTRECV;
continue;
}
if (inlen < sizeof (u_int32_t))
continue; /* Drop that and go ahead */
/*
* see if reply transaction id matches sent id.
* If so, decode the results. If return id is xid + 1
* it was a PORTMAP reply
*/
if (*((u_int32_t *)(void *)(inbuf)) ==
*((u_int32_t *)(void *)(outbuf))) {
pmap_reply_flag = 0;
msg.acpted_rply.ar_verf = _null_auth;
msg.acpted_rply.ar_results.where =
(caddr_t)(void *)&bres;
msg.acpted_rply.ar_results.proc =
(xdrproc_t)xdr_rpcb_rmtcallres;
#ifdef PORTMAP
} else if (pmap_flag &&
*((u_int32_t *)(void *)(inbuf)) ==
*((u_int32_t *)(void *)(outbuf_pmap))) {
pmap_reply_flag = 1;
msg.acpted_rply.ar_verf = _null_auth;
msg.acpted_rply.ar_results.where =
(caddr_t)(void *)&bres_pmap;
msg.acpted_rply.ar_results.proc =
(xdrproc_t)xdr_rmtcallres;
#endif /* PORTMAP */
} else
continue;
xdrmem_create(xdrs, inbuf, (u_int)inlen, XDR_DECODE);
if (xdr_replymsg(xdrs, &msg)) {
if ((msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(msg.acpted_rply.ar_stat == SUCCESS)) {
struct netbuf taddr, *np;
struct sockaddr_in *sin;
#ifdef PORTMAP
if (pmap_flag && pmap_reply_flag) {
sin = (struct sockaddr_in *)
(void *)&fdlist[i].raddr;
sin->sin_port =
htons((u_short)port);
taddr.len = taddr.maxlen =
fdlist[i].raddr.ss_len;
taddr.buf = &fdlist[i].raddr;
done = (*eachresult)(resultsp,
&taddr, fdlist[i].nconf);
} else {
#endif /* PORTMAP */
#ifdef RPC_DEBUG
fprintf(stderr, "uaddr %s\n",
uaddrp);
#endif
np = uaddr2taddr(
fdlist[i].nconf, uaddrp);
done = (*eachresult)(resultsp,
np, fdlist[i].nconf);
free(np);
#ifdef PORTMAP
}
#endif /* PORTMAP */
}
/* otherwise, we just ignore the errors ... */
}
/* else some kind of deserialization problem ... */
xdrs->x_op = XDR_FREE;
msg.acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
(void) xdr_replymsg(xdrs, &msg);
(void) (*xresults)(xdrs, resultsp);
XDR_DESTROY(xdrs);
if (done) {
stat = RPC_SUCCESS;
goto done_broad;
} else {
goto recv_again;
}
} /* The recv for loop */
} /* The giant for loop */
done_broad:
free(inbuf);
free(outbuf);
#ifdef PORTMAP
free(outbuf_pmap);
#endif /* PORTMAP */
for (i = 0; i < fdlistno; i++) {
(void)_close(fdlist[i].fd);
__rpc_freebroadifs(&fdlist[i].nal);
}
AUTH_DESTROY(sys_auth);
(void) __rpc_endconf(handle);
return (stat);
}
/*
* rpc_broadcast()
*
* prog - program number
* vers - version number
* proc - procedure number
* xargs - xdr routine for args
* argsp - pointer to args
* xresults - xdr routine for results
* resultsp - pointer to results
* eachresult - call with each result obtained
* nettype - transport type
*/
enum clnt_stat
rpc_broadcast(rpcprog_t prog, rpcvers_t vers, rpcproc_t proc, xdrproc_t xargs,
caddr_t argsp, xdrproc_t xresults, caddr_t resultsp,
resultproc_t eachresult, const char *nettype)
{
enum clnt_stat dummy;
dummy = rpc_broadcast_exp(prog, vers, proc, xargs, argsp,
xresults, resultsp, eachresult,
INITTIME, WAITTIME, nettype);
return (dummy);
}
diff --git a/lib/libc/rpc/clnt_dg.c b/lib/libc/rpc/clnt_dg.c
index d6b9698bf4db..40511f30135e 100644
--- a/lib/libc/rpc/clnt_dg.c
+++ b/lib/libc/rpc/clnt_dg.c
@@ -1,851 +1,850 @@
/* $NetBSD: clnt_dg.c,v 1.4 2000/07/14 08:40:41 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)clnt_dg.c 1.23 94/04/22 SMI"
static char sccsid[] = "@(#)clnt_dg.c 1.19 89/03/16 Copyr 1988 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* Implements a connectionless client side RPC.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <rpc/rpc.h>
#include <rpc/rpcsec_gss.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>
#include <err.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
#ifdef _FREEFALL_CONFIG
/*
* Disable RPC exponential back-off for FreeBSD.org systems.
*/
#define RPC_MAX_BACKOFF 1 /* second */
#else
#define RPC_MAX_BACKOFF 30 /* seconds */
#endif
static struct clnt_ops *clnt_dg_ops(void);
static bool_t time_not_ok(struct timeval *);
static enum clnt_stat clnt_dg_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
xdrproc_t, void *, struct timeval);
static void clnt_dg_geterr(CLIENT *, struct rpc_err *);
static bool_t clnt_dg_freeres(CLIENT *, xdrproc_t, void *);
static void clnt_dg_abort(CLIENT *);
static bool_t clnt_dg_control(CLIENT *, u_int, void *);
static void clnt_dg_destroy(CLIENT *);
/*
* This machinery implements per-fd locks for MT-safety. It is not
* sufficient to do per-CLIENT handle locks for MT-safety because a
* user may create more than one CLIENT handle with the same fd behind
* it. Therefore, we allocate an array of flags (dg_fd_locks), protected
* by the clnt_fd_lock mutex, and an array (dg_cv) of condition variables
* similarly protected. Dg_fd_lock[fd] == 1 => a call is active on some
* CLIENT handle created for that fd.
* The current implementation holds locks across the entire RPC and reply,
* including retransmissions. Yes, this is silly, and as soon as this
* code is proven to work, this should be the first thing fixed. One step
* at a time.
*/
static int *dg_fd_locks;
static cond_t *dg_cv;
#define release_fd_lock(fd, mask) { \
mutex_lock(&clnt_fd_lock); \
dg_fd_locks[fd] = 0; \
mutex_unlock(&clnt_fd_lock); \
thr_sigsetmask(SIG_SETMASK, &(mask), NULL); \
cond_signal(&dg_cv[fd]); \
}
static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory";
/* VARIABLES PROTECTED BY clnt_fd_lock: dg_fd_locks, dg_cv */
#define MCALL_MSG_SIZE 24
/*
* Private data kept per client handle
*/
struct cu_data {
int cu_fd; /* connections fd */
bool_t cu_closeit; /* opened by library */
struct sockaddr_storage cu_raddr; /* remote address */
int cu_rlen;
struct timeval cu_wait; /* retransmit interval */
struct timeval cu_total; /* total time for the call */
struct rpc_err cu_error;
XDR cu_outxdrs;
u_int cu_xdrpos;
u_int cu_sendsz; /* send size */
char cu_outhdr[MCALL_MSG_SIZE];
char *cu_outbuf;
u_int cu_recvsz; /* recv size */
int cu_async;
int cu_connect; /* Use connect(). */
int cu_connected; /* Have done connect(). */
struct kevent cu_kin;
int cu_kq;
char cu_inbuf[1];
};
/*
* Connection less client creation returns with client handle parameters.
* Default options are set, which the user can change using clnt_control().
* fd should be open and bound.
* NB: The rpch->cl_auth is initialized to null authentication.
* Caller may wish to set this something more useful.
*
* sendsz and recvsz are the maximum allowable packet sizes that can be
* sent and received. Normally they are the same, but they can be
* changed to improve the program efficiency and buffer allocation.
* If they are 0, use the transport default.
*
* If svcaddr is NULL, returns NULL.
*
* fd - open file descriptor
* svcaddr - servers address
* program - program number
* version - version number
* sendsz - buffer recv size
* recvsz - buffer send size
*/
CLIENT *
clnt_dg_create(int fd, const struct netbuf *svcaddr, rpcprog_t program,
rpcvers_t version, u_int sendsz, u_int recvsz)
{
CLIENT *cl = NULL; /* client handle */
struct cu_data *cu = NULL; /* private data */
struct timeval now;
struct rpc_msg call_msg;
sigset_t mask;
sigset_t newmask;
struct __rpc_sockinfo si;
int one = 1;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
if (dg_fd_locks == (int *) NULL) {
int cv_allocsz;
size_t fd_allocsz;
int dtbsize = __rpc_dtbsize();
fd_allocsz = dtbsize * sizeof (int);
dg_fd_locks = (int *) mem_alloc(fd_allocsz);
if (dg_fd_locks == (int *) NULL) {
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err1;
} else
memset(dg_fd_locks, '\0', fd_allocsz);
cv_allocsz = dtbsize * sizeof (cond_t);
dg_cv = (cond_t *) mem_alloc(cv_allocsz);
if (dg_cv == (cond_t *) NULL) {
mem_free(dg_fd_locks, fd_allocsz);
dg_fd_locks = (int *) NULL;
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err1;
} else {
int i;
for (i = 0; i < dtbsize; i++)
cond_init(&dg_cv[i], 0, (void *) 0);
}
}
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
if (svcaddr == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
return (NULL);
}
if (!__rpc_fd2sockinfo(fd, &si)) {
rpc_createerr.cf_stat = RPC_TLIERROR;
rpc_createerr.cf_error.re_errno = 0;
return (NULL);
}
/*
* Find the receive and the send size
*/
sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
if ((sendsz == 0) || (recvsz == 0)) {
rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */
rpc_createerr.cf_error.re_errno = 0;
return (NULL);
}
if ((cl = mem_alloc(sizeof (CLIENT))) == NULL)
goto err1;
/*
* Should be multiple of 4 for XDR.
*/
sendsz = ((sendsz + 3) / 4) * 4;
recvsz = ((recvsz + 3) / 4) * 4;
cu = mem_alloc(sizeof (*cu) + sendsz + recvsz);
if (cu == NULL)
goto err1;
(void) memcpy(&cu->cu_raddr, svcaddr->buf, (size_t)svcaddr->len);
cu->cu_rlen = svcaddr->len;
cu->cu_outbuf = &cu->cu_inbuf[recvsz];
/* Other values can also be set through clnt_control() */
cu->cu_wait.tv_sec = 15; /* heuristically chosen */
cu->cu_wait.tv_usec = 0;
cu->cu_total.tv_sec = -1;
cu->cu_total.tv_usec = -1;
cu->cu_sendsz = sendsz;
cu->cu_recvsz = recvsz;
cu->cu_async = FALSE;
cu->cu_connect = FALSE;
cu->cu_connected = FALSE;
(void) gettimeofday(&now, NULL);
call_msg.rm_xid = __RPC_GETXID(&now);
call_msg.rm_call.cb_prog = program;
call_msg.rm_call.cb_vers = version;
xdrmem_create(&(cu->cu_outxdrs), cu->cu_outhdr, MCALL_MSG_SIZE,
XDR_ENCODE);
if (! xdr_callhdr(&cu->cu_outxdrs, &call_msg)) {
rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */
rpc_createerr.cf_error.re_errno = 0;
goto err2;
}
cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs));
XDR_DESTROY(&cu->cu_outxdrs);
xdrmem_create(&cu->cu_outxdrs, cu->cu_outbuf, sendsz, XDR_ENCODE);
/* XXX fvdl - do we still want this? */
#if 0
(void)bindresvport_sa(fd, (struct sockaddr *)svcaddr->buf);
#endif
_ioctl(fd, FIONBIO, (char *)(void *)&one);
/*
* By default, closeit is always FALSE. It is users responsibility
* to do a close on it, else the user may use clnt_control
* to let clnt_destroy do it for him/her.
*/
cu->cu_closeit = FALSE;
cu->cu_fd = fd;
cl->cl_ops = clnt_dg_ops();
cl->cl_private = (caddr_t)(void *)cu;
cl->cl_auth = authnone_create();
cl->cl_tp = NULL;
cl->cl_netid = NULL;
cu->cu_kq = -1;
EV_SET(&cu->cu_kin, cu->cu_fd, EVFILT_READ, EV_ADD, 0, 0, 0);
return (cl);
err1:
warnx(mem_err_clnt_dg);
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
err2:
if (cl) {
mem_free(cl, sizeof (CLIENT));
if (cu)
mem_free(cu, sizeof (*cu) + sendsz + recvsz);
}
return (NULL);
}
/*
* cl - client handle
* proc - procedure number
* xargs - xdr routine for args
* argsp - pointer to args
* xresults - xdr routine for results
* resultsp - pointer to results
* utimeout - seconds to wait before giving up
*/
static enum clnt_stat
clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, void *argsp,
xdrproc_t xresults, void *resultsp, struct timeval utimeout)
{
struct cu_data *cu = (struct cu_data *)cl->cl_private;
XDR *xdrs;
size_t outlen = 0;
struct rpc_msg reply_msg;
XDR reply_xdrs;
bool_t ok;
int nrefreshes = 2; /* number of times to refresh cred */
int nretries = 0; /* number of times we retransmitted */
struct timeval timeout;
struct timeval retransmit_time;
struct timeval next_sendtime, starttime, time_waited, tv;
struct timespec ts;
struct kevent kv;
struct sockaddr *sa;
sigset_t mask;
sigset_t newmask;
socklen_t salen;
ssize_t recvlen = 0;
int kin_len, n, rpc_lock_value;
u_int32_t xid;
outlen = 0;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (dg_fd_locks[cu->cu_fd])
cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
if (__isthreaded)
rpc_lock_value = 1;
else
rpc_lock_value = 0;
dg_fd_locks[cu->cu_fd] = rpc_lock_value;
mutex_unlock(&clnt_fd_lock);
if (cu->cu_total.tv_usec == -1) {
timeout = utimeout; /* use supplied timeout */
} else {
timeout = cu->cu_total; /* use default timeout */
}
if (cu->cu_connect && !cu->cu_connected) {
if (_connect(cu->cu_fd, (struct sockaddr *)&cu->cu_raddr,
cu->cu_rlen) < 0) {
cu->cu_error.re_errno = errno;
cu->cu_error.re_status = RPC_CANTSEND;
goto out;
}
cu->cu_connected = 1;
}
if (cu->cu_connected) {
sa = NULL;
salen = 0;
} else {
sa = (struct sockaddr *)&cu->cu_raddr;
salen = cu->cu_rlen;
}
time_waited.tv_sec = 0;
time_waited.tv_usec = 0;
retransmit_time = next_sendtime = cu->cu_wait;
gettimeofday(&starttime, NULL);
/* Clean up in case the last call ended in a longjmp(3) call. */
if (cu->cu_kq >= 0)
_close(cu->cu_kq);
if ((cu->cu_kq = kqueue()) < 0) {
cu->cu_error.re_errno = errno;
cu->cu_error.re_status = RPC_CANTSEND;
goto out;
}
kin_len = 1;
call_again:
if (cu->cu_async == TRUE && xargs == NULL)
goto get_reply;
/*
* the transaction is the first thing in the out buffer
* XXX Yes, and it's in network byte order, so we should to
* be careful when we increment it, shouldn't we.
*/
xid = ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr));
xid++;
*(u_int32_t *)(void *)(cu->cu_outhdr) = htonl(xid);
call_again_same_xid:
xdrs = &(cu->cu_outxdrs);
xdrs->x_op = XDR_ENCODE;
XDR_SETPOS(xdrs, 0);
if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
if ((! XDR_PUTBYTES(xdrs, cu->cu_outhdr, cu->cu_xdrpos)) ||
(! XDR_PUTINT32(xdrs, &proc)) ||
(! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
(! (*xargs)(xdrs, argsp))) {
cu->cu_error.re_status = RPC_CANTENCODEARGS;
goto out;
}
} else {
*(uint32_t *) &cu->cu_outhdr[cu->cu_xdrpos] = htonl(proc);
if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outhdr,
cu->cu_xdrpos + sizeof(uint32_t),
xdrs, xargs, argsp)) {
cu->cu_error.re_status = RPC_CANTENCODEARGS;
goto out;
}
}
outlen = (size_t)XDR_GETPOS(xdrs);
send_again:
if (_sendto(cu->cu_fd, cu->cu_outbuf, outlen, 0, sa, salen) != outlen) {
cu->cu_error.re_errno = errno;
cu->cu_error.re_status = RPC_CANTSEND;
goto out;
}
/*
* Hack to provide rpc-based message passing
*/
if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
cu->cu_error.re_status = RPC_TIMEDOUT;
goto out;
}
get_reply:
/*
* sub-optimal code appears here because we have
* some clock time to spare while the packets are in flight.
* (We assume that this is actually only executed once.)
*/
reply_msg.acpted_rply.ar_verf = _null_auth;
if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
reply_msg.acpted_rply.ar_results.where = resultsp;
reply_msg.acpted_rply.ar_results.proc = xresults;
} else {
reply_msg.acpted_rply.ar_results.where = NULL;
reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
}
for (;;) {
/* Decide how long to wait. */
if (timercmp(&next_sendtime, &timeout, <))
timersub(&next_sendtime, &time_waited, &tv);
else
timersub(&timeout, &time_waited, &tv);
if (tv.tv_sec < 0 || tv.tv_usec < 0)
tv.tv_sec = tv.tv_usec = 0;
TIMEVAL_TO_TIMESPEC(&tv, &ts);
n = _kevent(cu->cu_kq, &cu->cu_kin, kin_len, &kv, 1, &ts);
/* We don't need to register the event again. */
kin_len = 0;
if (n == 1) {
if (kv.flags & EV_ERROR) {
cu->cu_error.re_errno = kv.data;
cu->cu_error.re_status = RPC_CANTRECV;
goto out;
}
/* We have some data now */
do {
recvlen = _recvfrom(cu->cu_fd, cu->cu_inbuf,
cu->cu_recvsz, 0, NULL, NULL);
} while (recvlen < 0 && errno == EINTR);
if (recvlen < 0 && errno != EWOULDBLOCK) {
cu->cu_error.re_errno = errno;
cu->cu_error.re_status = RPC_CANTRECV;
goto out;
}
if (recvlen >= sizeof(u_int32_t) &&
(cu->cu_async == TRUE ||
*((u_int32_t *)(void *)(cu->cu_inbuf)) ==
*((u_int32_t *)(void *)(cu->cu_outbuf)))) {
/* We now assume we have the proper reply. */
break;
}
}
if (n == -1 && errno != EINTR) {
cu->cu_error.re_errno = errno;
cu->cu_error.re_status = RPC_CANTRECV;
goto out;
}
gettimeofday(&tv, NULL);
timersub(&tv, &starttime, &time_waited);
/* Check for timeout. */
if (timercmp(&time_waited, &timeout, >)) {
cu->cu_error.re_status = RPC_TIMEDOUT;
goto out;
}
/* Retransmit if necessary. */
if (timercmp(&time_waited, &next_sendtime, >)) {
/* update retransmit_time */
if (retransmit_time.tv_sec < RPC_MAX_BACKOFF)
timeradd(&retransmit_time, &retransmit_time,
&retransmit_time);
timeradd(&next_sendtime, &retransmit_time,
&next_sendtime);
nretries++;
/*
* When retransmitting a RPCSEC_GSS message,
* we must use a new sequence number (handled
* by __rpc_gss_wrap above).
*/
if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS)
goto send_again;
else
goto call_again_same_xid;
}
}
/*
* now decode and validate the response
*/
xdrmem_create(&reply_xdrs, cu->cu_inbuf, (u_int)recvlen, XDR_DECODE);
ok = xdr_replymsg(&reply_xdrs, &reply_msg);
/* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */
if (ok) {
if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) &&
(reply_msg.acpted_rply.ar_stat == SUCCESS))
cu->cu_error.re_status = RPC_SUCCESS;
else
_seterr_reply(&reply_msg, &(cu->cu_error));
if (cu->cu_error.re_status == RPC_SUCCESS) {
if (! AUTH_VALIDATE(cl->cl_auth,
&reply_msg.acpted_rply.ar_verf)) {
if (nretries &&
cl->cl_auth->ah_cred.oa_flavor
== RPCSEC_GSS)
/*
* If we retransmitted, its
* possible that we will
* receive a reply for one of
* the earlier transmissions
* (which will use an older
* RPCSEC_GSS sequence
* number). In this case, just
* go back and listen for a
* new reply. We could keep a
* record of all the seq
* numbers we have transmitted
* so far so that we could
* accept a reply for any of
* them here.
*/
goto get_reply;
cu->cu_error.re_status = RPC_AUTHERROR;
cu->cu_error.re_why = AUTH_INVALIDRESP;
} else {
if (cl->cl_auth->ah_cred.oa_flavor
== RPCSEC_GSS) {
if (!__rpc_gss_unwrap(cl->cl_auth,
&reply_xdrs, xresults,
resultsp))
cu->cu_error.re_status =
RPC_CANTDECODERES;
}
}
if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
xdrs->x_op = XDR_FREE;
(void) xdr_opaque_auth(xdrs,
&(reply_msg.acpted_rply.ar_verf));
}
} /* end successful completion */
/*
* If unsuccessful AND error is an authentication error
* then refresh credentials and try again, else break
*/
else if (cu->cu_error.re_status == RPC_AUTHERROR)
/* maybe our credentials need to be refreshed ... */
if (nrefreshes > 0 &&
AUTH_REFRESH(cl->cl_auth, &reply_msg)) {
nrefreshes--;
goto call_again;
}
/* end of unsuccessful completion */
} /* end of valid reply message */
else {
cu->cu_error.re_status = RPC_CANTDECODERES;
}
out:
if (cu->cu_kq >= 0)
_close(cu->cu_kq);
cu->cu_kq = -1;
release_fd_lock(cu->cu_fd, mask);
return (cu->cu_error.re_status);
}
static void
clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp)
{
struct cu_data *cu = (struct cu_data *)cl->cl_private;
*errp = cu->cu_error;
}
static bool_t
clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
{
struct cu_data *cu = (struct cu_data *)cl->cl_private;
XDR *xdrs = &(cu->cu_outxdrs);
bool_t dummy;
sigset_t mask;
sigset_t newmask;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (dg_fd_locks[cu->cu_fd])
cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
xdrs->x_op = XDR_FREE;
dummy = (*xdr_res)(xdrs, res_ptr);
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &mask, NULL);
cond_signal(&dg_cv[cu->cu_fd]);
return (dummy);
}
/*ARGSUSED*/
static void
clnt_dg_abort(CLIENT *h)
{
}
static bool_t
clnt_dg_control(CLIENT *cl, u_int request, void *info)
{
struct cu_data *cu = (struct cu_data *)cl->cl_private;
struct netbuf *addr;
sigset_t mask;
sigset_t newmask;
int rpc_lock_value;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (dg_fd_locks[cu->cu_fd])
cond_wait(&dg_cv[cu->cu_fd], &clnt_fd_lock);
if (__isthreaded)
rpc_lock_value = 1;
else
rpc_lock_value = 0;
dg_fd_locks[cu->cu_fd] = rpc_lock_value;
mutex_unlock(&clnt_fd_lock);
switch (request) {
case CLSET_FD_CLOSE:
cu->cu_closeit = TRUE;
release_fd_lock(cu->cu_fd, mask);
return (TRUE);
case CLSET_FD_NCLOSE:
cu->cu_closeit = FALSE;
release_fd_lock(cu->cu_fd, mask);
return (TRUE);
}
/* for other requests which use info */
if (info == NULL) {
release_fd_lock(cu->cu_fd, mask);
return (FALSE);
}
switch (request) {
case CLSET_TIMEOUT:
if (time_not_ok((struct timeval *)info)) {
release_fd_lock(cu->cu_fd, mask);
return (FALSE);
}
cu->cu_total = *(struct timeval *)info;
break;
case CLGET_TIMEOUT:
*(struct timeval *)info = cu->cu_total;
break;
case CLGET_SERVER_ADDR: /* Give him the fd address */
/* Now obsolete. Only for backward compatibility */
(void) memcpy(info, &cu->cu_raddr, (size_t)cu->cu_rlen);
break;
case CLSET_RETRY_TIMEOUT:
if (time_not_ok((struct timeval *)info)) {
release_fd_lock(cu->cu_fd, mask);
return (FALSE);
}
cu->cu_wait = *(struct timeval *)info;
break;
case CLGET_RETRY_TIMEOUT:
*(struct timeval *)info = cu->cu_wait;
break;
case CLGET_FD:
*(int *)info = cu->cu_fd;
break;
case CLGET_SVC_ADDR:
addr = (struct netbuf *)info;
addr->buf = &cu->cu_raddr;
addr->len = cu->cu_rlen;
addr->maxlen = sizeof cu->cu_raddr;
break;
case CLSET_SVC_ADDR: /* set to new address */
addr = (struct netbuf *)info;
if (addr->len < sizeof cu->cu_raddr) {
release_fd_lock(cu->cu_fd, mask);
return (FALSE);
}
(void) memcpy(&cu->cu_raddr, addr->buf, addr->len);
cu->cu_rlen = addr->len;
break;
case CLGET_XID:
/*
* use the knowledge that xid is the
* first element in the call structure *.
* This will get the xid of the PREVIOUS call
*/
*(u_int32_t *)info =
ntohl(*(u_int32_t *)(void *)cu->cu_outhdr);
break;
case CLSET_XID:
/* This will set the xid of the NEXT call */
*(u_int32_t *)(void *)cu->cu_outhdr =
htonl(*(u_int32_t *)info - 1);
/* decrement by 1 as clnt_dg_call() increments once */
break;
case CLGET_VERS:
/*
* This RELIES on the information that, in the call body,
* the version number field is the fifth field from the
* beginning of the RPC header. MUST be changed if the
* call_struct is changed
*/
*(u_int32_t *)info =
ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr +
4 * BYTES_PER_XDR_UNIT));
break;
case CLSET_VERS:
*(u_int32_t *)(void *)(cu->cu_outhdr + 4 * BYTES_PER_XDR_UNIT)
= htonl(*(u_int32_t *)info);
break;
case CLGET_PROG:
/*
* This RELIES on the information that, in the call body,
* the program number field is the fourth field from the
* beginning of the RPC header. MUST be changed if the
* call_struct is changed
*/
*(u_int32_t *)info =
ntohl(*(u_int32_t *)(void *)(cu->cu_outhdr +
3 * BYTES_PER_XDR_UNIT));
break;
case CLSET_PROG:
*(u_int32_t *)(void *)(cu->cu_outhdr + 3 * BYTES_PER_XDR_UNIT)
= htonl(*(u_int32_t *)info);
break;
case CLSET_ASYNC:
cu->cu_async = *(int *)info;
break;
case CLSET_CONNECT:
cu->cu_connect = *(int *)info;
break;
default:
release_fd_lock(cu->cu_fd, mask);
return (FALSE);
}
release_fd_lock(cu->cu_fd, mask);
return (TRUE);
}
static void
clnt_dg_destroy(CLIENT *cl)
{
struct cu_data *cu = (struct cu_data *)cl->cl_private;
int cu_fd = cu->cu_fd;
sigset_t mask;
sigset_t newmask;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (dg_fd_locks[cu_fd])
cond_wait(&dg_cv[cu_fd], &clnt_fd_lock);
if (cu->cu_closeit)
(void)_close(cu_fd);
if (cu->cu_kq >= 0)
_close(cu->cu_kq);
XDR_DESTROY(&(cu->cu_outxdrs));
mem_free(cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz));
if (cl->cl_netid && cl->cl_netid[0])
mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
if (cl->cl_tp && cl->cl_tp[0])
mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
mem_free(cl, sizeof (CLIENT));
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &mask, NULL);
cond_signal(&dg_cv[cu_fd]);
}
static struct clnt_ops *
clnt_dg_ops(void)
{
static struct clnt_ops ops;
sigset_t mask;
sigset_t newmask;
/* VARIABLES PROTECTED BY ops_lock: ops */
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&ops_lock);
if (ops.cl_call == NULL) {
ops.cl_call = clnt_dg_call;
ops.cl_abort = clnt_dg_abort;
ops.cl_geterr = clnt_dg_geterr;
ops.cl_freeres = clnt_dg_freeres;
ops.cl_destroy = clnt_dg_destroy;
ops.cl_control = clnt_dg_control;
}
mutex_unlock(&ops_lock);
thr_sigsetmask(SIG_SETMASK, &mask, NULL);
return (&ops);
}
/*
* Make sure that the time is not garbage. -1 value is allowed.
*/
static bool_t
time_not_ok(struct timeval *t)
{
return (t->tv_sec < -1 || t->tv_sec > 100000000 ||
t->tv_usec < -1 || t->tv_usec > 1000000);
}
diff --git a/lib/libc/rpc/clnt_generic.c b/lib/libc/rpc/clnt_generic.c
index 0233de9a4b59..d1721821a88d 100644
--- a/lib/libc/rpc/clnt_generic.c
+++ b/lib/libc/rpc/clnt_generic.c
@@ -1,448 +1,447 @@
/* $NetBSD: clnt_generic.c,v 1.18 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* #ident "@(#)clnt_generic.c 1.40 99/04/21 SMI" */
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "from: @(#)clnt_generic.c 1.4 87/08/11 (C) 1987 SMI";
static char *sccsid = "from: @(#)clnt_generic.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* Copyright (c) 1986-1996,1998 by Sun Microsystems, Inc.
* All rights reserved.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <stdio.h>
#include <errno.h>
#include <netdb.h>
#include <syslog.h>
#include <rpc/rpc.h>
#include <rpc/nettype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "un-namespace.h"
#include "rpc_com.h"
extern bool_t __rpc_is_local_host(const char *);
int __rpc_raise_fd(int);
#ifndef NETIDLEN
#define NETIDLEN 32
#endif
/*
* Generic client creation with version checking the value of
* vers_out is set to the highest server supported value
* vers_low <= vers_out <= vers_high AND an error results
* if this can not be done.
*
* It calls clnt_create_vers_timed() with a NULL value for the timeout
* pointer, which indicates that the default timeout should be used.
*/
CLIENT *
clnt_create_vers(const char *hostname, rpcprog_t prog, rpcvers_t *vers_out,
rpcvers_t vers_low, rpcvers_t vers_high, const char *nettype)
{
return (clnt_create_vers_timed(hostname, prog, vers_out, vers_low,
vers_high, nettype, NULL));
}
/*
* This the routine has the same definition as clnt_create_vers(),
* except it takes an additional timeout parameter - a pointer to
* a timeval structure. A NULL value for the pointer indicates
* that the default timeout value should be used.
*/
CLIENT *
clnt_create_vers_timed(const char *hostname, rpcprog_t prog,
rpcvers_t *vers_out, rpcvers_t vers_low, rpcvers_t vers_high,
const char *nettype, const struct timeval *tp)
{
CLIENT *clnt;
struct timeval to;
enum clnt_stat rpc_stat;
struct rpc_err rpcerr;
clnt = clnt_create_timed(hostname, prog, vers_high, nettype, tp);
if (clnt == NULL) {
return (NULL);
}
to.tv_sec = 10;
to.tv_usec = 0;
rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
(char *)NULL, (xdrproc_t)xdr_void, (char *)NULL, to);
if (rpc_stat == RPC_SUCCESS) {
*vers_out = vers_high;
return (clnt);
}
while (rpc_stat == RPC_PROGVERSMISMATCH && vers_high > vers_low) {
unsigned int minvers, maxvers;
clnt_geterr(clnt, &rpcerr);
minvers = rpcerr.re_vers.low;
maxvers = rpcerr.re_vers.high;
if (maxvers < vers_high)
vers_high = maxvers;
else
vers_high--;
if (minvers > vers_low)
vers_low = minvers;
if (vers_low > vers_high) {
goto error;
}
CLNT_CONTROL(clnt, CLSET_VERS, (char *)&vers_high);
rpc_stat = clnt_call(clnt, NULLPROC, (xdrproc_t)xdr_void,
(char *)NULL, (xdrproc_t)xdr_void,
(char *)NULL, to);
if (rpc_stat == RPC_SUCCESS) {
*vers_out = vers_high;
return (clnt);
}
}
clnt_geterr(clnt, &rpcerr);
error:
rpc_createerr.cf_stat = rpc_stat;
rpc_createerr.cf_error = rpcerr;
clnt_destroy(clnt);
return (NULL);
}
/*
* Top level client creation routine.
* Generic client creation: takes (servers name, program-number, nettype) and
* returns client handle. Default options are set, which the user can
* change using the rpc equivalent of _ioctl()'s.
*
* It tries for all the netids in that particular class of netid until
* it succeeds.
* XXX The error message in the case of failure will be the one
* pertaining to the last create error.
*
* It calls clnt_create_timed() with the default timeout.
*/
CLIENT *
clnt_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
const char *nettype)
{
return (clnt_create_timed(hostname, prog, vers, nettype, NULL));
}
/*
* This the routine has the same definition as clnt_create(),
* except it takes an additional timeout parameter - a pointer to
* a timeval structure. A NULL value for the pointer indicates
* that the default timeout value should be used.
*
* This function calls clnt_tp_create_timed().
*/
CLIENT *
clnt_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
const char *netclass, const struct timeval *tp)
{
struct netconfig *nconf;
CLIENT *clnt = NULL;
void *handle;
enum clnt_stat save_cf_stat = RPC_SUCCESS;
struct rpc_err save_cf_error;
char nettype_array[NETIDLEN];
char *nettype = &nettype_array[0];
if (netclass == NULL)
nettype = NULL;
else {
size_t len = strlen(netclass);
if (len >= sizeof (nettype_array)) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
strcpy(nettype, netclass);
}
if ((handle = __rpc_setconf((char *)nettype)) == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
rpc_createerr.cf_stat = RPC_SUCCESS;
while (clnt == NULL) {
if ((nconf = __rpc_getconf(handle)) == NULL) {
if (rpc_createerr.cf_stat == RPC_SUCCESS)
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
break;
}
#ifdef CLNT_DEBUG
printf("trying netid %s\n", nconf->nc_netid);
#endif
clnt = clnt_tp_create_timed(hostname, prog, vers, nconf, tp);
if (clnt)
break;
else
/*
* Since we didn't get a name-to-address
* translation failure here, we remember
* this particular error. The object of
* this is to enable us to return to the
* caller a more-specific error than the
* unhelpful ``Name to address translation
* failed'' which might well occur if we
* merely returned the last error (because
* the local loopbacks are typically the
* last ones in /etc/netconfig and the most
* likely to be unable to translate a host
* name). We also check for a more
* meaningful error than ``unknown host
* name'' for the same reasons.
*/
if (rpc_createerr.cf_stat != RPC_N2AXLATEFAILURE &&
rpc_createerr.cf_stat != RPC_UNKNOWNHOST) {
save_cf_stat = rpc_createerr.cf_stat;
save_cf_error = rpc_createerr.cf_error;
}
}
/*
* Attempt to return an error more specific than ``Name to address
* translation failed'' or ``unknown host name''
*/
if ((rpc_createerr.cf_stat == RPC_N2AXLATEFAILURE ||
rpc_createerr.cf_stat == RPC_UNKNOWNHOST) &&
(save_cf_stat != RPC_SUCCESS)) {
rpc_createerr.cf_stat = save_cf_stat;
rpc_createerr.cf_error = save_cf_error;
}
__rpc_endconf(handle);
return (clnt);
}
/*
* Generic client creation: takes (servers name, program-number, netconf) and
* returns client handle. Default options are set, which the user can
* change using the rpc equivalent of _ioctl()'s : clnt_control()
* It finds out the server address from rpcbind and calls clnt_tli_create().
*
* It calls clnt_tp_create_timed() with the default timeout.
*/
CLIENT *
clnt_tp_create(const char *hostname, rpcprog_t prog, rpcvers_t vers,
const struct netconfig *nconf)
{
return (clnt_tp_create_timed(hostname, prog, vers, nconf, NULL));
}
/*
* This has the same definition as clnt_tp_create(), except it
* takes an additional parameter - a pointer to a timeval structure.
* A NULL value for the timeout pointer indicates that the default
* value for the timeout should be used.
*/
CLIENT *
clnt_tp_create_timed(const char *hostname, rpcprog_t prog, rpcvers_t vers,
const struct netconfig *nconf, const struct timeval *tp)
{
struct netbuf *svcaddr; /* servers address */
CLIENT *cl = NULL; /* client handle */
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
/*
* Get the address of the server
*/
if ((svcaddr = __rpcb_findaddr_timed(prog, vers,
(struct netconfig *)nconf, (char *)hostname,
&cl, (struct timeval *)tp)) == NULL) {
/* appropriate error number is set by rpcbind libraries */
return (NULL);
}
if (cl == NULL) {
cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
prog, vers, 0, 0);
} else {
/* Reuse the CLIENT handle and change the appropriate fields */
if (CLNT_CONTROL(cl, CLSET_SVC_ADDR, (void *)svcaddr) == TRUE) {
if (cl->cl_netid == NULL)
cl->cl_netid = strdup(nconf->nc_netid);
if (cl->cl_tp == NULL)
cl->cl_tp = strdup(nconf->nc_device);
(void) CLNT_CONTROL(cl, CLSET_PROG, (void *)&prog);
(void) CLNT_CONTROL(cl, CLSET_VERS, (void *)&vers);
} else {
CLNT_DESTROY(cl);
cl = clnt_tli_create(RPC_ANYFD, nconf, svcaddr,
prog, vers, 0, 0);
}
}
free(svcaddr->buf);
free(svcaddr);
return (cl);
}
/*
* Generic client creation: returns client handle.
* Default options are set, which the user can
* change using the rpc equivalent of _ioctl()'s : clnt_control().
* If fd is RPC_ANYFD, it will be opened using nconf.
* It will be bound if not so.
* If sizes are 0; appropriate defaults will be chosen.
*/
CLIENT *
clnt_tli_create(int fd, const struct netconfig *nconf,
struct netbuf *svcaddr, rpcprog_t prog, rpcvers_t vers,
uint sendsz, uint recvsz)
{
CLIENT *cl; /* client handle */
bool_t madefd = FALSE; /* whether fd opened here */
long servtype;
int one = 1;
struct __rpc_sockinfo si;
extern int __rpc_minfd;
if (fd == RPC_ANYFD) {
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
fd = __rpc_nconf2fd(nconf);
if (fd == -1)
goto err;
if (fd < __rpc_minfd)
fd = __rpc_raise_fd(fd);
madefd = TRUE;
servtype = nconf->nc_semantics;
if (!__rpc_fd2sockinfo(fd, &si))
goto err;
bindresvport(fd, NULL);
} else {
if (!__rpc_fd2sockinfo(fd, &si))
goto err;
servtype = __rpc_socktype2seman(si.si_socktype);
if (servtype == -1) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
}
if (si.si_af != ((struct sockaddr *)svcaddr->buf)->sa_family) {
rpc_createerr.cf_stat = RPC_UNKNOWNHOST; /* XXX */
goto err1;
}
switch (servtype) {
case NC_TPI_COTS:
cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
break;
case NC_TPI_COTS_ORD:
if (nconf && ((strcmp(nconf->nc_protofmly, "inet") == 0))) {
_setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &one,
sizeof (one));
}
cl = clnt_vc_create(fd, svcaddr, prog, vers, sendsz, recvsz);
break;
case NC_TPI_CLTS:
cl = clnt_dg_create(fd, svcaddr, prog, vers, sendsz, recvsz);
break;
default:
goto err;
}
if (cl == NULL)
goto err1; /* borrow errors from clnt_dg/vc creates */
if (nconf) {
cl->cl_netid = strdup(nconf->nc_netid);
cl->cl_tp = strdup(nconf->nc_device);
} else {
cl->cl_netid = "";
cl->cl_tp = "";
}
if (madefd) {
(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
/* (void) CLNT_CONTROL(cl, CLSET_POP_TIMOD, NULL); */
}
return (cl);
err:
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
err1: if (madefd)
(void)_close(fd);
return (NULL);
}
/*
* To avoid conflicts with the "magic" file descriptors (0, 1, and 2),
* we try to not use them. The __rpc_raise_fd() routine will dup
* a descriptor to a higher value. If we fail to do it, we continue
* to use the old one (and hope for the best).
*/
int __rpc_minfd = 3;
int
__rpc_raise_fd(int fd)
{
int nfd;
if (fd >= __rpc_minfd)
return (fd);
if ((nfd = _fcntl(fd, F_DUPFD, __rpc_minfd)) == -1)
return (fd);
if (_fsync(nfd) == -1) {
_close(nfd);
return (fd);
}
if (_close(fd) == -1) {
/* this is okay, we will syslog an error, then use the new fd */
(void) syslog(LOG_ERR,
"could not close() fd %d; mem & fd leak", fd);
}
return (nfd);
}
diff --git a/lib/libc/rpc/clnt_perror.c b/lib/libc/rpc/clnt_perror.c
index 878439a11109..6affd70f723c 100644
--- a/lib/libc/rpc/clnt_perror.c
+++ b/lib/libc/rpc/clnt_perror.c
@@ -1,323 +1,322 @@
/* $NetBSD: clnt_perror.c,v 1.24 2000/06/02 23:11:07 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)clnt_perror.c 1.15 87/10/07 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)clnt_perror.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* clnt_perror.c
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
*/
#include "namespace.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/rpc.h>
#include <rpc/types.h>
#include <rpc/auth.h>
#include <rpc/clnt.h>
#include "un-namespace.h"
static char *buf;
static char *_buf(void);
static char *auth_errmsg(enum auth_stat);
#define CLNT_PERROR_BUFLEN 256
static char *
_buf(void)
{
if (buf == NULL)
buf = malloc(CLNT_PERROR_BUFLEN);
return (buf);
}
/*
* Print reply error info
*/
char *
clnt_sperror(CLIENT *rpch, const char *s)
{
struct rpc_err e;
char *err;
char *str;
char *strstart;
size_t len, i;
assert(rpch != NULL);
assert(s != NULL);
str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */
if (str == NULL)
return (0);
len = CLNT_PERROR_BUFLEN;
strstart = str;
CLNT_GETERR(rpch, &e);
if ((i = snprintf(str, len, "%s: ", s)) > 0) {
str += i;
len -= i;
}
(void)strncpy(str, clnt_sperrno(e.re_status), len - 1);
i = strlen(str);
str += i;
len -= i;
switch (e.re_status) {
case RPC_SUCCESS:
case RPC_CANTENCODEARGS:
case RPC_CANTDECODERES:
case RPC_TIMEDOUT:
case RPC_PROGUNAVAIL:
case RPC_PROCUNAVAIL:
case RPC_CANTDECODEARGS:
case RPC_SYSTEMERROR:
case RPC_UNKNOWNHOST:
case RPC_UNKNOWNPROTO:
case RPC_PMAPFAILURE:
case RPC_PROGNOTREGISTERED:
case RPC_FAILED:
break;
case RPC_CANTSEND:
case RPC_CANTRECV:
i = snprintf(str, len, "; errno = %s", strerror(e.re_errno));
if (i > 0) {
str += i;
len -= i;
}
break;
case RPC_VERSMISMATCH:
i = snprintf(str, len, "; low version = %u, high version = %u",
e.re_vers.low, e.re_vers.high);
if (i > 0) {
str += i;
len -= i;
}
break;
case RPC_AUTHERROR:
err = auth_errmsg(e.re_why);
i = snprintf(str, len, "; why = ");
if (i > 0) {
str += i;
len -= i;
}
if (err != NULL) {
i = snprintf(str, len, "%s",err);
} else {
i = snprintf(str, len,
"(unknown authentication error - %d)",
(int) e.re_why);
}
if (i > 0) {
str += i;
len -= i;
}
break;
case RPC_PROGVERSMISMATCH:
i = snprintf(str, len, "; low version = %u, high version = %u",
e.re_vers.low, e.re_vers.high);
if (i > 0) {
str += i;
len -= i;
}
break;
default: /* unknown */
i = snprintf(str, len, "; s1 = %u, s2 = %u",
e.re_lb.s1, e.re_lb.s2);
if (i > 0) {
str += i;
len -= i;
}
break;
}
strstart[CLNT_PERROR_BUFLEN-1] = '\0';
return(strstart) ;
}
void
clnt_perror(CLIENT *rpch, const char *s)
{
assert(rpch != NULL);
assert(s != NULL);
(void) fprintf(stderr, "%s\n", clnt_sperror(rpch,s));
}
static const char *const rpc_errlist[] = {
"RPC: Success", /* 0 - RPC_SUCCESS */
"RPC: Can't encode arguments", /* 1 - RPC_CANTENCODEARGS */
"RPC: Can't decode result", /* 2 - RPC_CANTDECODERES */
"RPC: Unable to send", /* 3 - RPC_CANTSEND */
"RPC: Unable to receive", /* 4 - RPC_CANTRECV */
"RPC: Timed out", /* 5 - RPC_TIMEDOUT */
"RPC: Incompatible versions of RPC", /* 6 - RPC_VERSMISMATCH */
"RPC: Authentication error", /* 7 - RPC_AUTHERROR */
"RPC: Program unavailable", /* 8 - RPC_PROGUNAVAIL */
"RPC: Program/version mismatch", /* 9 - RPC_PROGVERSMISMATCH */
"RPC: Procedure unavailable", /* 10 - RPC_PROCUNAVAIL */
"RPC: Server can't decode arguments", /* 11 - RPC_CANTDECODEARGS */
"RPC: Remote system error", /* 12 - RPC_SYSTEMERROR */
"RPC: Unknown host", /* 13 - RPC_UNKNOWNHOST */
"RPC: Port mapper failure", /* 14 - RPC_PMAPFAILURE */
"RPC: Program not registered", /* 15 - RPC_PROGNOTREGISTERED */
"RPC: Failed (unspecified error)", /* 16 - RPC_FAILED */
"RPC: Unknown protocol" /* 17 - RPC_UNKNOWNPROTO */
};
/*
* This interface for use by clntrpc
*/
char *
clnt_sperrno(enum clnt_stat stat)
{
unsigned int errnum = stat;
if (errnum < (sizeof(rpc_errlist)/sizeof(rpc_errlist[0])))
/* LINTED interface problem */
return (char *)rpc_errlist[errnum];
return ("RPC: (unknown error code)");
}
void
clnt_perrno(enum clnt_stat num)
{
(void) fprintf(stderr, "%s\n", clnt_sperrno(num));
}
char *
clnt_spcreateerror(const char *s)
{
char *str;
size_t len, i;
assert(s != NULL);
str = _buf(); /* side effect: sets CLNT_PERROR_BUFLEN */
if (str == NULL)
return(0);
len = CLNT_PERROR_BUFLEN;
i = snprintf(str, len, "%s: ", s);
if (i > 0)
len -= i;
(void)strncat(str, clnt_sperrno(rpc_createerr.cf_stat), len - 1);
switch (rpc_createerr.cf_stat) {
case RPC_PMAPFAILURE:
(void) strncat(str, " - ", len - 1);
(void) strncat(str,
clnt_sperrno(rpc_createerr.cf_error.re_status), len - 4);
break;
case RPC_SYSTEMERROR:
(void)strncat(str, " - ", len - 1);
(void)strncat(str, strerror(rpc_createerr.cf_error.re_errno),
len - 4);
break;
case RPC_CANTSEND:
case RPC_CANTDECODERES:
case RPC_CANTENCODEARGS:
case RPC_SUCCESS:
case RPC_UNKNOWNPROTO:
case RPC_PROGNOTREGISTERED:
case RPC_FAILED:
case RPC_UNKNOWNHOST:
case RPC_CANTDECODEARGS:
case RPC_PROCUNAVAIL:
case RPC_PROGVERSMISMATCH:
case RPC_PROGUNAVAIL:
case RPC_AUTHERROR:
case RPC_VERSMISMATCH:
case RPC_TIMEDOUT:
case RPC_CANTRECV:
default:
break;
}
str[CLNT_PERROR_BUFLEN-1] = '\0';
return (str);
}
void
clnt_pcreateerror(const char *s)
{
assert(s != NULL);
(void) fprintf(stderr, "%s\n", clnt_spcreateerror(s));
}
static const char *const auth_errlist[] = {
"Authentication OK", /* 0 - AUTH_OK */
"Invalid client credential", /* 1 - AUTH_BADCRED */
"Server rejected credential", /* 2 - AUTH_REJECTEDCRED */
"Invalid client verifier", /* 3 - AUTH_BADVERF */
"Server rejected verifier", /* 4 - AUTH_REJECTEDVERF */
"Client credential too weak", /* 5 - AUTH_TOOWEAK */
"Invalid server verifier", /* 6 - AUTH_INVALIDRESP */
"Failed (unspecified error)", /* 7 - AUTH_FAILED */
"Kerberos generic error", /* 8 - AUTH_KERB_GENERIC*/
"Kerberos credential expired", /* 9 - AUTH_TIMEEXPIRE */
"Bad kerberos ticket file", /* 10 - AUTH_TKT_FILE */
"Can't decode kerberos authenticator", /* 11 - AUTH_DECODE */
"Address wrong in kerberos ticket", /* 12 - AUTH_NET_ADDR */
"GSS-API crediential problem", /* 13 - RPCSEC_GSS_CREDPROBLEM */
"GSS-API context problem" /* 14 - RPCSEC_GSS_CTXPROBLEM */
};
static char *
auth_errmsg(enum auth_stat stat)
{
unsigned int errnum = stat;
if (errnum < (sizeof(auth_errlist)/sizeof(auth_errlist[0])))
/* LINTED interface problem */
return (char *)auth_errlist[errnum];
return(NULL);
}
diff --git a/lib/libc/rpc/clnt_raw.c b/lib/libc/rpc/clnt_raw.c
index d09494c9206f..0bf7da0b6792 100644
--- a/lib/libc/rpc/clnt_raw.c
+++ b/lib/libc/rpc/clnt_raw.c
@@ -1,296 +1,295 @@
/* $NetBSD: clnt_raw.c,v 1.20 2000/12/10 04:12:03 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)clnt_raw.c 1.22 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)clnt_raw.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* clnt_raw.c
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* Memory based rpc for simple testing and timing.
* Interface to create an rpc client and server in the same process.
* This lets us similate rpc and get round trip overhead, without
* any interference from the kernel.
*/
#include "namespace.h"
#include "reentrant.h"
#include <assert.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#include <rpc/raw.h>
#include "un-namespace.h"
#include "mt_misc.h"
#define MCALL_MSG_SIZE 24
/*
* This is the "network" we will be moving stuff over.
*/
static struct clntraw_private {
CLIENT client_object;
XDR xdr_stream;
char *_raw_buf;
union {
struct rpc_msg mashl_rpcmsg;
char mashl_callmsg[MCALL_MSG_SIZE];
} u;
u_int mcnt;
} *clntraw_private;
static enum clnt_stat clnt_raw_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
xdrproc_t, void *, struct timeval);
static void clnt_raw_geterr(CLIENT *, struct rpc_err *);
static bool_t clnt_raw_freeres(CLIENT *, xdrproc_t, void *);
static void clnt_raw_abort(CLIENT *);
static bool_t clnt_raw_control(CLIENT *, u_int, void *);
static void clnt_raw_destroy(CLIENT *);
static struct clnt_ops *clnt_raw_ops(void);
/*
* Create a client handle for memory based rpc.
*/
CLIENT *
clnt_raw_create(rpcprog_t prog, rpcvers_t vers)
{
struct clntraw_private *clp;
struct rpc_msg call_msg;
XDR *xdrs;
CLIENT *client;
mutex_lock(&clntraw_lock);
if ((clp = clntraw_private) == NULL) {
clp = (struct clntraw_private *)calloc(1, sizeof (*clp));
if (clp == NULL) {
mutex_unlock(&clntraw_lock);
return NULL;
}
if (__rpc_rawcombuf == NULL)
__rpc_rawcombuf =
(char *)calloc(UDPMSGSIZE, sizeof (char));
clp->_raw_buf = __rpc_rawcombuf;
clntraw_private = clp;
}
xdrs = &clp->xdr_stream;
client = &clp->client_object;
/*
* pre-serialize the static part of the call msg and stash it away
*/
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
/* XXX: prog and vers have been long historically :-( */
call_msg.rm_call.cb_prog = (u_int32_t)prog;
call_msg.rm_call.cb_vers = (u_int32_t)vers;
xdrmem_create(xdrs, clp->u.mashl_callmsg, MCALL_MSG_SIZE, XDR_ENCODE);
if (! xdr_callhdr(xdrs, &call_msg))
warnx("clntraw_create - Fatal header serialization error.");
clp->mcnt = XDR_GETPOS(xdrs);
XDR_DESTROY(xdrs);
/*
* Set xdrmem for client/server shared buffer
*/
xdrmem_create(xdrs, clp->_raw_buf, UDPMSGSIZE, XDR_FREE);
/*
* create client handle
*/
client->cl_ops = clnt_raw_ops();
client->cl_auth = authnone_create();
mutex_unlock(&clntraw_lock);
return (client);
}
/* ARGSUSED */
static enum clnt_stat
clnt_raw_call(CLIENT *h, rpcproc_t proc, xdrproc_t xargs, void *argsp,
xdrproc_t xresults, void *resultsp, struct timeval timeout)
{
struct clntraw_private *clp = clntraw_private;
XDR *xdrs = &clp->xdr_stream;
struct rpc_msg msg;
enum clnt_stat status;
struct rpc_err error;
assert(h != NULL);
mutex_lock(&clntraw_lock);
if (clp == NULL) {
mutex_unlock(&clntraw_lock);
return (RPC_FAILED);
}
mutex_unlock(&clntraw_lock);
call_again:
/*
* send request
*/
xdrs->x_op = XDR_ENCODE;
XDR_SETPOS(xdrs, 0);
clp->u.mashl_rpcmsg.rm_xid ++ ;
if ((! XDR_PUTBYTES(xdrs, clp->u.mashl_callmsg, clp->mcnt)) ||
(! XDR_PUTINT32(xdrs, &proc)) ||
(! AUTH_MARSHALL(h->cl_auth, xdrs)) ||
(! (*xargs)(xdrs, argsp))) {
return (RPC_CANTENCODEARGS);
}
(void)XDR_GETPOS(xdrs); /* called just to cause overhead */
/*
* We have to call server input routine here because this is
* all going on in one process. Yuk.
*/
svc_getreq_common(FD_SETSIZE);
/*
* get results
*/
xdrs->x_op = XDR_DECODE;
XDR_SETPOS(xdrs, 0);
msg.acpted_rply.ar_verf = _null_auth;
msg.acpted_rply.ar_results.where = resultsp;
msg.acpted_rply.ar_results.proc = xresults;
if (! xdr_replymsg(xdrs, &msg)) {
/*
* It's possible for xdr_replymsg() to fail partway
* through its attempt to decode the result from the
* server. If this happens, it will leave the reply
* structure partially populated with dynamically
* allocated memory. (This can happen if someone uses
* clntudp_bufcreate() to create a CLIENT handle and
* specifies a receive buffer size that is too small.)
* This memory must be free()ed to avoid a leak.
*/
int op = xdrs->x_op;
xdrs->x_op = XDR_FREE;
xdr_replymsg(xdrs, &msg);
xdrs->x_op = op;
return (RPC_CANTDECODERES);
}
_seterr_reply(&msg, &error);
status = error.re_status;
if (status == RPC_SUCCESS) {
if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
status = RPC_AUTHERROR;
}
} /* end successful completion */
else {
if (AUTH_REFRESH(h->cl_auth, &msg))
goto call_again;
} /* end of unsuccessful completion */
if (status == RPC_SUCCESS) {
if (! AUTH_VALIDATE(h->cl_auth, &msg.acpted_rply.ar_verf)) {
status = RPC_AUTHERROR;
}
if (msg.acpted_rply.ar_verf.oa_base != NULL) {
xdrs->x_op = XDR_FREE;
(void)xdr_opaque_auth(xdrs, &(msg.acpted_rply.ar_verf));
}
}
return (status);
}
/*ARGSUSED*/
static void
clnt_raw_geterr(CLIENT *cl, struct rpc_err *err)
{
}
/* ARGSUSED */
static bool_t
clnt_raw_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
{
struct clntraw_private *clp = clntraw_private;
XDR *xdrs = &clp->xdr_stream;
bool_t rval;
mutex_lock(&clntraw_lock);
if (clp == NULL) {
rval = (bool_t) RPC_FAILED;
mutex_unlock(&clntraw_lock);
return (rval);
}
mutex_unlock(&clntraw_lock);
xdrs->x_op = XDR_FREE;
return ((*xdr_res)(xdrs, res_ptr));
}
/*ARGSUSED*/
static void
clnt_raw_abort(CLIENT *cl)
{
}
/*ARGSUSED*/
static bool_t
clnt_raw_control(CLIENT *cl, u_int ui, void *str)
{
return (FALSE);
}
/*ARGSUSED*/
static void
clnt_raw_destroy(CLIENT *cl)
{
}
static struct clnt_ops *
clnt_raw_ops(void)
{
static struct clnt_ops ops;
/* VARIABLES PROTECTED BY ops_lock: ops */
mutex_lock(&ops_lock);
if (ops.cl_call == NULL) {
ops.cl_call = clnt_raw_call;
ops.cl_abort = clnt_raw_abort;
ops.cl_geterr = clnt_raw_geterr;
ops.cl_freeres = clnt_raw_freeres;
ops.cl_destroy = clnt_raw_destroy;
ops.cl_control = clnt_raw_control;
}
mutex_unlock(&ops_lock);
return (&ops);
}
diff --git a/lib/libc/rpc/clnt_simple.c b/lib/libc/rpc/clnt_simple.c
index 657d0ac399d5..b2a46c4b8029 100644
--- a/lib/libc/rpc/clnt_simple.c
+++ b/lib/libc/rpc/clnt_simple.c
@@ -1,207 +1,206 @@
/* $NetBSD: clnt_simple.c,v 1.21 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "from: @(#)clnt_simple.c 1.35 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "from: @(#)clnt_simple.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* clnt_simple.c
* Simplified front end to client rpc.
*
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <stdio.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include "un-namespace.h"
#include "mt_misc.h"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 64
#endif
#ifndef NETIDLEN
#define NETIDLEN 32
#endif
struct rpc_call_private {
int valid; /* Is this entry valid ? */
CLIENT *client; /* Client handle */
pid_t pid; /* process-id at moment of creation */
rpcprog_t prognum; /* Program */
rpcvers_t versnum; /* Version */
char host[MAXHOSTNAMELEN]; /* Servers host */
char nettype[NETIDLEN]; /* Network type */
};
static struct rpc_call_private *rpc_call_private_main;
static thread_key_t rpc_call_key;
static once_t rpc_call_once = ONCE_INITIALIZER;
static int rpc_call_key_error;
static void rpc_call_key_init(void);
static void rpc_call_destroy(void *);
static void
rpc_call_destroy(void *vp)
{
struct rpc_call_private *rcp = (struct rpc_call_private *)vp;
if (rcp) {
if (rcp->client)
CLNT_DESTROY(rcp->client);
free(rcp);
}
}
static void
rpc_call_key_init(void)
{
rpc_call_key_error = thr_keycreate(&rpc_call_key, rpc_call_destroy);
}
/*
* This is the simplified interface to the client rpc layer.
* The client handle is not destroyed here and is reused for
* the future calls to same prog, vers, host and nettype combination.
*
* The total time available is 25 seconds.
*
* host - host name
* prognum - program number
* versnum - version number
* procnum - procedure number
* inproc, outproc - in/out XDR procedures
* in, out - recv/send data
* nettype - nettype
*/
enum clnt_stat
rpc_call(const char *host, const rpcprog_t prognum, const rpcvers_t versnum,
const rpcproc_t procnum, const xdrproc_t inproc, const char *in,
const xdrproc_t outproc, char *out, const char *nettype)
{
struct rpc_call_private *rcp = (struct rpc_call_private *) 0;
enum clnt_stat clnt_stat;
struct timeval timeout, tottimeout;
int main_thread = 1;
if ((main_thread = thr_main())) {
rcp = rpc_call_private_main;
} else {
if (thr_once(&rpc_call_once, rpc_call_key_init) != 0 ||
rpc_call_key_error != 0) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = rpc_call_key_error;
return (rpc_createerr.cf_stat);
}
rcp = (struct rpc_call_private *)thr_getspecific(rpc_call_key);
}
if (rcp == NULL) {
rcp = malloc(sizeof (*rcp));
if (rcp == NULL) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
return (rpc_createerr.cf_stat);
}
if (main_thread)
rpc_call_private_main = rcp;
else
thr_setspecific(rpc_call_key, (void *) rcp);
rcp->valid = 0;
rcp->client = NULL;
}
if ((nettype == NULL) || (nettype[0] == 0))
nettype = "netpath";
if (!(rcp->valid && rcp->pid == getpid() &&
(rcp->prognum == prognum) &&
(rcp->versnum == versnum) &&
(!strcmp(rcp->host, host)) &&
(!strcmp(rcp->nettype, nettype)))) {
int fd;
rcp->valid = 0;
if (rcp->client)
CLNT_DESTROY(rcp->client);
/*
* Using the first successful transport for that type
*/
rcp->client = clnt_create(host, prognum, versnum, nettype);
rcp->pid = getpid();
if (rcp->client == NULL) {
return (rpc_createerr.cf_stat);
}
/*
* Set time outs for connectionless case. Do it
* unconditionally. Faster than doing a t_getinfo()
* and then doing the right thing.
*/
timeout.tv_usec = 0;
timeout.tv_sec = 5;
(void) CLNT_CONTROL(rcp->client,
CLSET_RETRY_TIMEOUT, (char *)(void *)&timeout);
if (CLNT_CONTROL(rcp->client, CLGET_FD, (char *)(void *)&fd))
_fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
rcp->prognum = prognum;
rcp->versnum = versnum;
if ((strlen(host) < (size_t)MAXHOSTNAMELEN) &&
(strlen(nettype) < (size_t)NETIDLEN)) {
(void) strcpy(rcp->host, host);
(void) strcpy(rcp->nettype, nettype);
rcp->valid = 1;
} else {
rcp->valid = 0;
}
} /* else reuse old client */
tottimeout.tv_sec = 25;
tottimeout.tv_usec = 0;
/*LINTED const castaway*/
clnt_stat = CLNT_CALL(rcp->client, procnum, inproc, (char *) in,
outproc, out, tottimeout);
/*
* if call failed, empty cache
*/
if (clnt_stat != RPC_SUCCESS)
rcp->valid = 0;
return (clnt_stat);
}
diff --git a/lib/libc/rpc/clnt_vc.c b/lib/libc/rpc/clnt_vc.c
index d3c96945d25a..25cd5a273531 100644
--- a/lib/libc/rpc/clnt_vc.c
+++ b/lib/libc/rpc/clnt_vc.c
@@ -1,847 +1,846 @@
/* $NetBSD: clnt_vc.c,v 1.4 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)clnt_tcp.c 1.37 87/10/05 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)clnt_tcp.c 2.2 88/08/01 4.0 RPCSRC";
static char sccsid3[] = "@(#)clnt_vc.c 1.19 89/03/16 Copyr 1988 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* clnt_tcp.c, Implements a TCP/IP based, client side RPC.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* TCP based RPC supports 'batched calls'.
* A sequence of calls may be batched-up in a send buffer. The rpc call
* return immediately to the client even though the call was not necessarily
* sent. The batching occurs if the results' xdr routine is NULL (0) AND
* the rpc timeout value is zero (see clnt.h, rpc).
*
* Clients should NOT casually batch calls that in fact return results; that is,
* the server side should be aware that a call is batched and not produce any
* return message. Batched calls that produce many result messages can
* deadlock (netlock) the client and the server....
*
* Now go hang yourself.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/poll.h>
#include <sys/syslog.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <rpc/rpc.h>
#include <rpc/rpcsec_gss.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
#define MCALL_MSG_SIZE 24
struct cmessage {
struct cmsghdr cmsg;
struct cmsgcred cmcred;
};
static enum clnt_stat clnt_vc_call(CLIENT *, rpcproc_t, xdrproc_t, void *,
xdrproc_t, void *, struct timeval);
static void clnt_vc_geterr(CLIENT *, struct rpc_err *);
static bool_t clnt_vc_freeres(CLIENT *, xdrproc_t, void *);
static void clnt_vc_abort(CLIENT *);
static bool_t clnt_vc_control(CLIENT *, u_int, void *);
static void clnt_vc_destroy(CLIENT *);
static struct clnt_ops *clnt_vc_ops(void);
static bool_t time_not_ok(struct timeval *);
static int read_vc(void *, void *, int);
static int write_vc(void *, void *, int);
static int __msgwrite(int, void *, size_t);
static int __msgread(int, void *, size_t);
struct ct_data {
int ct_fd; /* connection's fd */
bool_t ct_closeit; /* close it on destroy */
struct timeval ct_wait; /* wait interval in milliseconds */
bool_t ct_waitset; /* wait set by clnt_control? */
struct netbuf ct_addr; /* remote addr */
struct rpc_err ct_error;
union {
char ct_mcallc[MCALL_MSG_SIZE]; /* marshalled callmsg */
u_int32_t ct_mcalli;
} ct_u;
u_int ct_mpos; /* pos after marshal */
XDR ct_xdrs; /* XDR stream */
};
/*
* This machinery implements per-fd locks for MT-safety. It is not
* sufficient to do per-CLIENT handle locks for MT-safety because a
* user may create more than one CLIENT handle with the same fd behind
* it. Therefore, we allocate an array of flags (vc_fd_locks), protected
* by the clnt_fd_lock mutex, and an array (vc_cv) of condition variables
* similarly protected. Vc_fd_lock[fd] == 1 => a call is active on some
* CLIENT handle created for that fd.
* The current implementation holds locks across the entire RPC and reply.
* Yes, this is silly, and as soon as this code is proven to work, this
* should be the first thing fixed. One step at a time.
*/
static int *vc_fd_locks;
static cond_t *vc_cv;
#define release_fd_lock(fd, mask) { \
mutex_lock(&clnt_fd_lock); \
vc_fd_locks[fd] = 0; \
mutex_unlock(&clnt_fd_lock); \
thr_sigsetmask(SIG_SETMASK, &(mask), (sigset_t *) NULL); \
cond_signal(&vc_cv[fd]); \
}
static const char clnt_vc_errstr[] = "%s : %s";
static const char clnt_vc_str[] = "clnt_vc_create";
static const char __no_mem_str[] = "out of memory";
/*
* Create a client handle for a connection.
* Default options are set, which the user can change using clnt_control()'s.
* The rpc/vc package does buffering similar to stdio, so the client
* must pick send and receive buffer sizes, 0 => use the default.
* NB: fd is copied into a private area.
* NB: The rpch->cl_auth is set null authentication. Caller may wish to
* set this something more useful.
*
* fd should be an open socket
*
* fd - open file descriptor
* raddr - servers address
* prog - program number
* vers - version number
* sendsz - buffer send size
* recvsz - buffer recv size
*/
CLIENT *
clnt_vc_create(int fd, const struct netbuf *raddr, const rpcprog_t prog,
const rpcvers_t vers, u_int sendsz, u_int recvsz)
{
CLIENT *cl; /* client handle */
struct ct_data *ct = NULL; /* client handle */
struct timeval now;
struct rpc_msg call_msg;
static u_int32_t disrupt;
sigset_t mask;
sigset_t newmask;
struct sockaddr_storage ss;
socklen_t slen;
struct __rpc_sockinfo si;
if (disrupt == 0)
disrupt = (u_int32_t)(long)raddr;
cl = (CLIENT *)mem_alloc(sizeof (*cl));
ct = (struct ct_data *)mem_alloc(sizeof (*ct));
if ((cl == (CLIENT *)NULL) || (ct == (struct ct_data *)NULL)) {
(void) syslog(LOG_ERR, clnt_vc_errstr,
clnt_vc_str, __no_mem_str);
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
goto err;
}
ct->ct_addr.buf = NULL;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
if (vc_fd_locks == (int *) NULL) {
int cv_allocsz, fd_allocsz;
int dtbsize = __rpc_dtbsize();
fd_allocsz = dtbsize * sizeof (int);
vc_fd_locks = (int *) mem_alloc(fd_allocsz);
if (vc_fd_locks == (int *) NULL) {
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err;
} else
memset(vc_fd_locks, '\0', fd_allocsz);
assert(vc_cv == (cond_t *) NULL);
cv_allocsz = dtbsize * sizeof (cond_t);
vc_cv = (cond_t *) mem_alloc(cv_allocsz);
if (vc_cv == (cond_t *) NULL) {
mem_free(vc_fd_locks, fd_allocsz);
vc_fd_locks = (int *) NULL;
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err;
} else {
int i;
for (i = 0; i < dtbsize; i++)
cond_init(&vc_cv[i], 0, (void *) 0);
}
} else
assert(vc_cv != (cond_t *) NULL);
/*
* XXX - fvdl connecting while holding a mutex?
*/
slen = sizeof ss;
if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
if (errno != ENOTCONN) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err;
}
if (_connect(fd, (struct sockaddr *)raddr->buf, raddr->len) < 0){
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
goto err;
}
}
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
if (!__rpc_fd2sockinfo(fd, &si))
goto err;
ct->ct_closeit = FALSE;
/*
* Set up private data struct
*/
ct->ct_fd = fd;
ct->ct_wait.tv_usec = 0;
ct->ct_waitset = FALSE;
ct->ct_addr.buf = malloc(raddr->maxlen);
if (ct->ct_addr.buf == NULL)
goto err;
memcpy(ct->ct_addr.buf, raddr->buf, raddr->len);
ct->ct_addr.len = raddr->len;
ct->ct_addr.maxlen = raddr->maxlen;
/*
* Initialize call message
*/
(void)gettimeofday(&now, NULL);
call_msg.rm_xid = ((u_int32_t)++disrupt) ^ __RPC_GETXID(&now);
call_msg.rm_direction = CALL;
call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
call_msg.rm_call.cb_prog = (u_int32_t)prog;
call_msg.rm_call.cb_vers = (u_int32_t)vers;
/*
* pre-serialize the static part of the call msg and stash it away
*/
xdrmem_create(&(ct->ct_xdrs), ct->ct_u.ct_mcallc, MCALL_MSG_SIZE,
XDR_ENCODE);
if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
if (ct->ct_closeit) {
(void)_close(fd);
}
goto err;
}
ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
XDR_DESTROY(&(ct->ct_xdrs));
assert(ct->ct_mpos + sizeof(uint32_t) <= MCALL_MSG_SIZE);
/*
* Create a client handle which uses xdrrec for serialization
* and authnone for authentication.
*/
cl->cl_ops = clnt_vc_ops();
cl->cl_private = ct;
cl->cl_auth = authnone_create();
sendsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsz);
recvsz = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsz);
xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz,
cl->cl_private, read_vc, write_vc);
return (cl);
err:
if (ct) {
if (ct->ct_addr.len)
mem_free(ct->ct_addr.buf, ct->ct_addr.len);
mem_free(ct, sizeof (struct ct_data));
}
if (cl)
mem_free(cl, sizeof (CLIENT));
return ((CLIENT *)NULL);
}
static enum clnt_stat
clnt_vc_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xdr_args, void *args_ptr,
xdrproc_t xdr_results, void *results_ptr, struct timeval timeout)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
XDR *xdrs = &(ct->ct_xdrs);
struct rpc_msg reply_msg;
u_int32_t x_id;
u_int32_t *msg_x_id = &ct->ct_u.ct_mcalli; /* yuk */
bool_t shipnow;
int refreshes = 2;
sigset_t mask, newmask;
int rpc_lock_value;
bool_t reply_stat;
assert(cl != NULL);
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (vc_fd_locks[ct->ct_fd])
cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
if (__isthreaded)
rpc_lock_value = 1;
else
rpc_lock_value = 0;
vc_fd_locks[ct->ct_fd] = rpc_lock_value;
mutex_unlock(&clnt_fd_lock);
if (!ct->ct_waitset) {
/* If time is not within limits, we ignore it. */
if (time_not_ok(&timeout) == FALSE)
ct->ct_wait = timeout;
}
shipnow =
(xdr_results == NULL && timeout.tv_sec == 0
&& timeout.tv_usec == 0) ? FALSE : TRUE;
call_again:
xdrs->x_op = XDR_ENCODE;
ct->ct_error.re_status = RPC_SUCCESS;
x_id = ntohl(--(*msg_x_id));
if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
if ((! XDR_PUTBYTES(xdrs, ct->ct_u.ct_mcallc, ct->ct_mpos)) ||
(! XDR_PUTINT32(xdrs, &proc)) ||
(! AUTH_MARSHALL(cl->cl_auth, xdrs)) ||
(! (*xdr_args)(xdrs, args_ptr))) {
if (ct->ct_error.re_status == RPC_SUCCESS)
ct->ct_error.re_status = RPC_CANTENCODEARGS;
(void)xdrrec_endofrecord(xdrs, TRUE);
release_fd_lock(ct->ct_fd, mask);
return (ct->ct_error.re_status);
}
} else {
*(uint32_t *) &ct->ct_u.ct_mcallc[ct->ct_mpos] = htonl(proc);
if (! __rpc_gss_wrap(cl->cl_auth, ct->ct_u.ct_mcallc,
ct->ct_mpos + sizeof(uint32_t),
xdrs, xdr_args, args_ptr)) {
if (ct->ct_error.re_status == RPC_SUCCESS)
ct->ct_error.re_status = RPC_CANTENCODEARGS;
(void)xdrrec_endofrecord(xdrs, TRUE);
release_fd_lock(ct->ct_fd, mask);
return (ct->ct_error.re_status);
}
}
if (! xdrrec_endofrecord(xdrs, shipnow)) {
release_fd_lock(ct->ct_fd, mask);
return (ct->ct_error.re_status = RPC_CANTSEND);
}
if (! shipnow) {
release_fd_lock(ct->ct_fd, mask);
return (RPC_SUCCESS);
}
/*
* Hack to provide rpc-based message passing
*/
if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
release_fd_lock(ct->ct_fd, mask);
return(ct->ct_error.re_status = RPC_TIMEDOUT);
}
/*
* Keep receiving until we get a valid transaction id
*/
xdrs->x_op = XDR_DECODE;
while (TRUE) {
reply_msg.acpted_rply.ar_verf = _null_auth;
reply_msg.acpted_rply.ar_results.where = NULL;
reply_msg.acpted_rply.ar_results.proc = (xdrproc_t)xdr_void;
if (! xdrrec_skiprecord(xdrs)) {
release_fd_lock(ct->ct_fd, mask);
return (ct->ct_error.re_status);
}
/* now decode and validate the response header */
if (! xdr_replymsg(xdrs, &reply_msg)) {
if (ct->ct_error.re_status == RPC_SUCCESS)
continue;
release_fd_lock(ct->ct_fd, mask);
return (ct->ct_error.re_status);
}
if (reply_msg.rm_xid == x_id)
break;
}
/*
* process header
*/
_seterr_reply(&reply_msg, &(ct->ct_error));
if (ct->ct_error.re_status == RPC_SUCCESS) {
if (! AUTH_VALIDATE(cl->cl_auth,
&reply_msg.acpted_rply.ar_verf)) {
ct->ct_error.re_status = RPC_AUTHERROR;
ct->ct_error.re_why = AUTH_INVALIDRESP;
} else {
if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) {
reply_stat = (*xdr_results)(xdrs, results_ptr);
} else {
reply_stat = __rpc_gss_unwrap(cl->cl_auth,
xdrs, xdr_results, results_ptr);
}
if (! reply_stat) {
if (ct->ct_error.re_status == RPC_SUCCESS)
ct->ct_error.re_status =
RPC_CANTDECODERES;
}
}
/* free verifier ... */
if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
xdrs->x_op = XDR_FREE;
(void)xdr_opaque_auth(xdrs,
&(reply_msg.acpted_rply.ar_verf));
}
} /* end successful completion */
else {
/* maybe our credentials need to be refreshed ... */
if (refreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg))
goto call_again;
} /* end of unsuccessful completion */
release_fd_lock(ct->ct_fd, mask);
return (ct->ct_error.re_status);
}
static void
clnt_vc_geterr(CLIENT *cl, struct rpc_err *errp)
{
struct ct_data *ct;
assert(cl != NULL);
assert(errp != NULL);
ct = (struct ct_data *) cl->cl_private;
*errp = ct->ct_error;
}
static bool_t
clnt_vc_freeres(CLIENT *cl, xdrproc_t xdr_res, void *res_ptr)
{
struct ct_data *ct;
XDR *xdrs;
bool_t dummy;
sigset_t mask;
sigset_t newmask;
assert(cl != NULL);
ct = (struct ct_data *)cl->cl_private;
xdrs = &(ct->ct_xdrs);
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (vc_fd_locks[ct->ct_fd])
cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
xdrs->x_op = XDR_FREE;
dummy = (*xdr_res)(xdrs, res_ptr);
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
cond_signal(&vc_cv[ct->ct_fd]);
return dummy;
}
/*ARGSUSED*/
static void
clnt_vc_abort(CLIENT *cl)
{
}
static __inline void
htonlp(void *dst, const void *src, uint32_t incr)
{
/* We are aligned, so we think */
*(uint32_t *)dst = htonl(*(const uint32_t *)src + incr);
}
static __inline void
ntohlp(void *dst, const void *src)
{
/* We are aligned, so we think */
*(uint32_t *)dst = htonl(*(const uint32_t *)src);
}
static bool_t
clnt_vc_control(CLIENT *cl, u_int request, void *info)
{
struct ct_data *ct;
void *infop = info;
sigset_t mask;
sigset_t newmask;
int rpc_lock_value;
assert(cl != NULL);
ct = (struct ct_data *)cl->cl_private;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (vc_fd_locks[ct->ct_fd])
cond_wait(&vc_cv[ct->ct_fd], &clnt_fd_lock);
if (__isthreaded)
rpc_lock_value = 1;
else
rpc_lock_value = 0;
vc_fd_locks[ct->ct_fd] = rpc_lock_value;
mutex_unlock(&clnt_fd_lock);
switch (request) {
case CLSET_FD_CLOSE:
ct->ct_closeit = TRUE;
release_fd_lock(ct->ct_fd, mask);
return (TRUE);
case CLSET_FD_NCLOSE:
ct->ct_closeit = FALSE;
release_fd_lock(ct->ct_fd, mask);
return (TRUE);
default:
break;
}
/* for other requests which use info */
if (info == NULL) {
release_fd_lock(ct->ct_fd, mask);
return (FALSE);
}
switch (request) {
case CLSET_TIMEOUT:
if (time_not_ok((struct timeval *)info)) {
release_fd_lock(ct->ct_fd, mask);
return (FALSE);
}
ct->ct_wait = *(struct timeval *)infop;
ct->ct_waitset = TRUE;
break;
case CLGET_TIMEOUT:
*(struct timeval *)infop = ct->ct_wait;
break;
case CLGET_SERVER_ADDR:
(void) memcpy(info, ct->ct_addr.buf, (size_t)ct->ct_addr.len);
break;
case CLGET_FD:
*(int *)info = ct->ct_fd;
break;
case CLGET_SVC_ADDR:
/* The caller should not free this memory area */
*(struct netbuf *)info = ct->ct_addr;
break;
case CLSET_SVC_ADDR: /* set to new address */
release_fd_lock(ct->ct_fd, mask);
return (FALSE);
case CLGET_XID:
/*
* use the knowledge that xid is the
* first element in the call structure
* This will get the xid of the PREVIOUS call
*/
ntohlp(info, &ct->ct_u.ct_mcalli);
break;
case CLSET_XID:
/* This will set the xid of the NEXT call */
/* increment by 1 as clnt_vc_call() decrements once */
htonlp(&ct->ct_u.ct_mcalli, info, 1);
break;
case CLGET_VERS:
/*
* This RELIES on the information that, in the call body,
* the version number field is the fifth field from the
* beginning of the RPC header. MUST be changed if the
* call_struct is changed
*/
ntohlp(info, ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT);
break;
case CLSET_VERS:
htonlp(ct->ct_u.ct_mcallc + 4 * BYTES_PER_XDR_UNIT, info, 0);
break;
case CLGET_PROG:
/*
* This RELIES on the information that, in the call body,
* the program number field is the fourth field from the
* beginning of the RPC header. MUST be changed if the
* call_struct is changed
*/
ntohlp(info, ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT);
break;
case CLSET_PROG:
htonlp(ct->ct_u.ct_mcallc + 3 * BYTES_PER_XDR_UNIT, info, 0);
break;
default:
release_fd_lock(ct->ct_fd, mask);
return (FALSE);
}
release_fd_lock(ct->ct_fd, mask);
return (TRUE);
}
static void
clnt_vc_destroy(CLIENT *cl)
{
struct ct_data *ct = (struct ct_data *) cl->cl_private;
int ct_fd = ct->ct_fd;
sigset_t mask;
sigset_t newmask;
assert(cl != NULL);
ct = (struct ct_data *) cl->cl_private;
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&clnt_fd_lock);
while (vc_fd_locks[ct_fd])
cond_wait(&vc_cv[ct_fd], &clnt_fd_lock);
if (ct->ct_closeit && ct->ct_fd != -1) {
(void)_close(ct->ct_fd);
}
XDR_DESTROY(&(ct->ct_xdrs));
free(ct->ct_addr.buf);
mem_free(ct, sizeof(struct ct_data));
if (cl->cl_netid && cl->cl_netid[0])
mem_free(cl->cl_netid, strlen(cl->cl_netid) +1);
if (cl->cl_tp && cl->cl_tp[0])
mem_free(cl->cl_tp, strlen(cl->cl_tp) +1);
mem_free(cl, sizeof(CLIENT));
mutex_unlock(&clnt_fd_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
cond_signal(&vc_cv[ct_fd]);
}
/*
* Interface between xdr serializer and tcp connection.
* Behaves like the system calls, read & write, but keeps some error state
* around for the rpc level.
*/
static int
read_vc(void *ctp, void *buf, int len)
{
struct sockaddr sa;
socklen_t sal;
struct ct_data *ct = (struct ct_data *)ctp;
struct pollfd fd;
int milliseconds = (int)((ct->ct_wait.tv_sec * 1000) +
(ct->ct_wait.tv_usec / 1000));
if (len == 0)
return (0);
fd.fd = ct->ct_fd;
fd.events = POLLIN;
for (;;) {
switch (_poll(&fd, 1, milliseconds)) {
case 0:
ct->ct_error.re_status = RPC_TIMEDOUT;
return (-1);
case -1:
if (errno == EINTR)
continue;
ct->ct_error.re_status = RPC_CANTRECV;
ct->ct_error.re_errno = errno;
return (-1);
}
break;
}
sal = sizeof(sa);
if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
(sa.sa_family == AF_LOCAL)) {
len = __msgread(ct->ct_fd, buf, (size_t)len);
} else {
len = _read(ct->ct_fd, buf, (size_t)len);
}
switch (len) {
case 0:
/* premature eof */
ct->ct_error.re_errno = ECONNRESET;
ct->ct_error.re_status = RPC_CANTRECV;
len = -1; /* it's really an error */
break;
case -1:
ct->ct_error.re_errno = errno;
ct->ct_error.re_status = RPC_CANTRECV;
break;
}
return (len);
}
static int
write_vc(void *ctp, void *buf, int len)
{
struct sockaddr sa;
socklen_t sal;
struct ct_data *ct = (struct ct_data *)ctp;
int i, cnt;
sal = sizeof(sa);
if ((_getpeername(ct->ct_fd, &sa, &sal) == 0) &&
(sa.sa_family == AF_LOCAL)) {
for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
if ((i = __msgwrite(ct->ct_fd, buf,
(size_t)cnt)) == -1) {
ct->ct_error.re_errno = errno;
ct->ct_error.re_status = RPC_CANTSEND;
return (-1);
}
}
} else {
for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
if ((i = _write(ct->ct_fd, buf, (size_t)cnt)) == -1) {
ct->ct_error.re_errno = errno;
ct->ct_error.re_status = RPC_CANTSEND;
return (-1);
}
}
}
return (len);
}
static struct clnt_ops *
clnt_vc_ops(void)
{
static struct clnt_ops ops;
sigset_t mask, newmask;
/* VARIABLES PROTECTED BY ops_lock: ops */
sigfillset(&newmask);
thr_sigsetmask(SIG_SETMASK, &newmask, &mask);
mutex_lock(&ops_lock);
if (ops.cl_call == NULL) {
ops.cl_call = clnt_vc_call;
ops.cl_abort = clnt_vc_abort;
ops.cl_geterr = clnt_vc_geterr;
ops.cl_freeres = clnt_vc_freeres;
ops.cl_destroy = clnt_vc_destroy;
ops.cl_control = clnt_vc_control;
}
mutex_unlock(&ops_lock);
thr_sigsetmask(SIG_SETMASK, &(mask), NULL);
return (&ops);
}
/*
* Make sure that the time is not garbage. -1 value is disallowed.
* Note this is different from time_not_ok in clnt_dg.c
*/
static bool_t
time_not_ok(struct timeval *t)
{
return (t->tv_sec <= -1 || t->tv_sec > 100000000 ||
t->tv_usec <= -1 || t->tv_usec > 1000000);
}
static int
__msgread(int sock, void *buf, size_t cnt)
{
struct iovec iov[1];
struct msghdr msg;
union {
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
} cm;
bzero((char *)&cm, sizeof(cm));
iov[0].iov_base = buf;
iov[0].iov_len = cnt;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = (caddr_t)&cm;
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
msg.msg_flags = 0;
return(_recvmsg(sock, &msg, 0));
}
static int
__msgwrite(int sock, void *buf, size_t cnt)
{
struct iovec iov[1];
struct msghdr msg;
union {
struct cmsghdr cmsg;
char control[CMSG_SPACE(sizeof(struct cmsgcred))];
} cm;
bzero((char *)&cm, sizeof(cm));
iov[0].iov_base = buf;
iov[0].iov_len = cnt;
cm.cmsg.cmsg_type = SCM_CREDS;
cm.cmsg.cmsg_level = SOL_SOCKET;
cm.cmsg.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred));
msg.msg_iov = iov;
msg.msg_iovlen = 1;
msg.msg_name = NULL;
msg.msg_namelen = 0;
msg.msg_control = (caddr_t)&cm;
msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred));
msg.msg_flags = 0;
return(_sendmsg(sock, &msg, 0));
}
diff --git a/lib/libc/rpc/crypt_client.c b/lib/libc/rpc/crypt_client.c
index 2fe0facd6505..4173a14811f9 100644
--- a/lib/libc/rpc/crypt_client.c
+++ b/lib/libc/rpc/crypt_client.c
@@ -1,99 +1,98 @@
/*-
* SPDX-License-Identifier: BSD-4-Clause
*
* Copyright (c) 1996
* Bill Paul <wpaul@ctr.columbia.edu>. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Bill Paul.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Bill Paul OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <err.h>
#include <sys/types.h>
#include <rpc/des_crypt.h>
#include <rpc/des.h>
#include <string.h>
#include <rpcsvc/crypt.h>
#include "un-namespace.h"
int
_des_crypt_call(char *buf, int len, struct desparams *dparms)
{
CLIENT *clnt;
desresp *result_1;
desargs des_crypt_1_arg;
struct netconfig *nconf;
void *localhandle;
int stat;
nconf = NULL;
localhandle = setnetconfig();
while ((nconf = getnetconfig(localhandle)) != NULL) {
if (nconf->nc_protofmly != NULL &&
strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
break;
}
if (nconf == NULL) {
warnx("getnetconfig: %s", nc_sperror());
endnetconfig(localhandle);
return(DESERR_HWERROR);
}
clnt = clnt_tp_create(NULL, CRYPT_PROG, CRYPT_VERS, nconf);
if (clnt == (CLIENT *) NULL) {
endnetconfig(localhandle);
return(DESERR_HWERROR);
}
endnetconfig(localhandle);
des_crypt_1_arg.desbuf.desbuf_len = len;
des_crypt_1_arg.desbuf.desbuf_val = buf;
des_crypt_1_arg.des_dir = (dparms->des_dir == ENCRYPT) ? ENCRYPT_DES : DECRYPT_DES;
des_crypt_1_arg.des_mode = (dparms->des_mode == CBC) ? CBC_DES : ECB_DES;
bcopy(dparms->des_ivec, des_crypt_1_arg.des_ivec, 8);
bcopy(dparms->des_key, des_crypt_1_arg.des_key, 8);
result_1 = des_crypt_1(&des_crypt_1_arg, clnt);
if (result_1 == (desresp *) NULL) {
clnt_destroy(clnt);
return(DESERR_HWERROR);
}
stat = result_1->stat;
if (result_1->stat == DESERR_NONE ||
result_1->stat == DESERR_NOHWDEVICE) {
bcopy(result_1->desbuf.desbuf_val, buf, len);
bcopy(result_1->des_ivec, dparms->des_ivec, 8);
}
clnt_freeres(clnt, (xdrproc_t)xdr_desresp, result_1);
clnt_destroy(clnt);
return(stat);
}
diff --git a/lib/libc/rpc/des_crypt.c b/lib/libc/rpc/des_crypt.c
index 3202aeef3604..a6e693be0c8b 100644
--- a/lib/libc/rpc/des_crypt.c
+++ b/lib/libc/rpc/des_crypt.c
@@ -1,140 +1,139 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* des_crypt.c, DES encryption library routines
* Copyright (C) 1986, Sun Microsystems, Inc.
*/
#include <sys/types.h>
#include <rpc/des_crypt.h>
#include <rpc/des.h>
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)des_crypt.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI";
#endif
-#include <sys/cdefs.h>
static int common_crypt( char *, char *, unsigned, unsigned, struct desparams * );
int (*__des_crypt_LOCAL)(char *, unsigned, struct desparams *) = 0;
extern int _des_crypt_call(char *, int, struct desparams *);
/*
* Copy 8 bytes
*/
#define COPY8(src, dst) { \
char *a = (char *) dst; \
char *b = (char *) src; \
*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
}
/*
* Copy multiple of 8 bytes
*/
#define DESCOPY(src, dst, len) { \
char *a = (char *) dst; \
char *b = (char *) src; \
int i; \
for (i = (int) len; i > 0; i -= 8) { \
*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
*a++ = *b++; *a++ = *b++; *a++ = *b++; *a++ = *b++; \
} \
}
/*
* CBC mode encryption
*/
int
cbc_crypt(char *key, char *buf, unsigned len, unsigned mode, char *ivec)
{
int err;
struct desparams dp;
#ifdef BROKEN_DES
dp.UDES.UDES_buf = buf;
dp.des_mode = ECB;
#else
dp.des_mode = CBC;
#endif
COPY8(ivec, dp.des_ivec);
err = common_crypt(key, buf, len, mode, &dp);
COPY8(dp.des_ivec, ivec);
return(err);
}
/*
* ECB mode encryption
*/
int
ecb_crypt(char *key, char *buf, unsigned len, unsigned mode)
{
struct desparams dp;
#ifdef BROKEN_DES
dp.UDES.UDES_buf = buf;
dp.des_mode = CBC;
#else
dp.des_mode = ECB;
#endif
return(common_crypt(key, buf, len, mode, &dp));
}
/*
* Common code to cbc_crypt() & ecb_crypt()
*/
static int
common_crypt(char *key, char *buf, unsigned len, unsigned mode,
struct desparams *desp)
{
int desdev;
if ((len % 8) != 0 || len > DES_MAXDATA) {
return(DESERR_BADPARAM);
}
desp->des_dir =
((mode & DES_DIRMASK) == DES_ENCRYPT) ? ENCRYPT : DECRYPT;
desdev = mode & DES_DEVMASK;
COPY8(key, desp->des_key);
/*
* software
*/
if (__des_crypt_LOCAL != NULL) {
if (!__des_crypt_LOCAL(buf, len, desp)) {
return (DESERR_HWERROR);
}
} else {
if (!_des_crypt_call(buf, len, desp)) {
return (DESERR_HWERROR);
}
}
return(desdev == DES_SW ? DESERR_NONE : DESERR_NOHWDEVICE);
}
diff --git a/lib/libc/rpc/des_soft.c b/lib/libc/rpc/des_soft.c
index c97a4686b70d..e6649d458b49 100644
--- a/lib/libc/rpc/des_soft.c
+++ b/lib/libc/rpc/des_soft.c
@@ -1,69 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)des_soft.c 2.2 88/08/10 4.0 RPCSRC; from 1.13 88/02/08 SMI";
#endif
-#include <sys/cdefs.h>
/*
* Table giving odd parity in the low bit for ASCII characters
*/
static char partab[128] = {
0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x07, 0x07,
0x08, 0x08, 0x0b, 0x0b, 0x0d, 0x0d, 0x0e, 0x0e,
0x10, 0x10, 0x13, 0x13, 0x15, 0x15, 0x16, 0x16,
0x19, 0x19, 0x1a, 0x1a, 0x1c, 0x1c, 0x1f, 0x1f,
0x20, 0x20, 0x23, 0x23, 0x25, 0x25, 0x26, 0x26,
0x29, 0x29, 0x2a, 0x2a, 0x2c, 0x2c, 0x2f, 0x2f,
0x31, 0x31, 0x32, 0x32, 0x34, 0x34, 0x37, 0x37,
0x38, 0x38, 0x3b, 0x3b, 0x3d, 0x3d, 0x3e, 0x3e,
0x40, 0x40, 0x43, 0x43, 0x45, 0x45, 0x46, 0x46,
0x49, 0x49, 0x4a, 0x4a, 0x4c, 0x4c, 0x4f, 0x4f,
0x51, 0x51, 0x52, 0x52, 0x54, 0x54, 0x57, 0x57,
0x58, 0x58, 0x5b, 0x5b, 0x5d, 0x5d, 0x5e, 0x5e,
0x61, 0x61, 0x62, 0x62, 0x64, 0x64, 0x67, 0x67,
0x68, 0x68, 0x6b, 0x6b, 0x6d, 0x6d, 0x6e, 0x6e,
0x70, 0x70, 0x73, 0x73, 0x75, 0x75, 0x76, 0x76,
0x79, 0x79, 0x7a, 0x7a, 0x7c, 0x7c, 0x7f, 0x7f,
};
/*
* Add odd parity to low bit of 8 byte key
*/
void
des_setparity(char *p)
{
int i;
for (i = 0; i < 8; i++) {
*p = partab[*p & 0x7f];
p++;
}
}
diff --git a/lib/libc/rpc/getnetconfig.c b/lib/libc/rpc/getnetconfig.c
index 100aef435512..0b1cc757ed50 100644
--- a/lib/libc/rpc/getnetconfig.c
+++ b/lib/libc/rpc/getnetconfig.c
@@ -1,732 +1,731 @@
/* $NetBSD: getnetconfig.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getnetconfig.c 1.12 91/12/19 SMI";
#endif
-#include <sys/cdefs.h>
/*
* Copyright (c) 1989 by Sun Microsystems, Inc.
*/
#include "namespace.h"
#include "reentrant.h"
#include <stdio.h>
#include <errno.h>
#include <netconfig.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/rpc.h>
#include <unistd.h>
#include "un-namespace.h"
#include "rpc_com.h"
/*
* The five library routines in this file provide application access to the
* system network configuration database, /etc/netconfig. In addition to the
* netconfig database and the routines for accessing it, the environment
* variable NETPATH and its corresponding routines in getnetpath.c may also be
* used to specify the network transport to be used.
*/
/*
* netconfig errors
*/
#define NC_NONETCONFIG ENOENT
#define NC_NOMEM ENOMEM
#define NC_NOTINIT EINVAL /* setnetconfig was not called first */
#define NC_BADFILE EBADF /* format for netconfig file is bad */
#define NC_NOTFOUND ENOPROTOOPT /* specified netid was not found */
/*
* semantics as strings (should be in netconfig.h)
*/
#define NC_TPI_CLTS_S "tpi_clts"
#define NC_TPI_COTS_S "tpi_cots"
#define NC_TPI_COTS_ORD_S "tpi_cots_ord"
#define NC_TPI_RAW_S "tpi_raw"
/*
* flags as characters (also should be in netconfig.h)
*/
#define NC_NOFLAG_C '-'
#define NC_VISIBLE_C 'v'
#define NC_BROADCAST_C 'b'
/*
* Character used to indicate there is no name-to-address lookup library
*/
#define NC_NOLOOKUP "-"
static const char * const _nc_errors[] = {
"Netconfig database not found",
"Not enough memory",
"Not initialized",
"Netconfig database has invalid format",
"Netid not found in netconfig database"
};
struct netconfig_info {
int eof; /* all entries has been read */
int ref; /* # of times setnetconfig() has been called */
struct netconfig_list *head; /* head of the list */
struct netconfig_list *tail; /* last of the list */
};
struct netconfig_list {
char *linep; /* hold line read from netconfig */
struct netconfig *ncp;
struct netconfig_list *next;
};
struct netconfig_vars {
int valid; /* token that indicates a valid netconfig_vars */
int flag; /* first time flag */
struct netconfig_list *nc_configs; /* pointer to the current netconfig entry */
};
#define NC_VALID 0xfeed
#define NC_STORAGE 0xf00d
#define NC_INVALID 0
static int *__nc_error(void);
static int parse_ncp(char *, struct netconfig *);
static struct netconfig *dup_ncp(struct netconfig *);
static FILE *nc_file; /* for netconfig db */
static mutex_t nc_file_lock = MUTEX_INITIALIZER;
static struct netconfig_info ni = { 0, 0, NULL, NULL};
static mutex_t ni_lock = MUTEX_INITIALIZER;
static thread_key_t nc_key;
static once_t nc_once = ONCE_INITIALIZER;
static int nc_key_error;
static void
nc_key_init(void)
{
nc_key_error = thr_keycreate(&nc_key, free);
}
#define MAXNETCONFIGLINE 1000
static int *
__nc_error(void)
{
static int nc_error = 0;
int *nc_addr;
/*
* Use the static `nc_error' if we are the main thread
* (including non-threaded programs), or if an allocation
* fails.
*/
if (thr_main())
return (&nc_error);
if (thr_once(&nc_once, nc_key_init) != 0 || nc_key_error != 0)
return (&nc_error);
if ((nc_addr = (int *)thr_getspecific(nc_key)) == NULL) {
nc_addr = (int *)malloc(sizeof (int));
if (thr_setspecific(nc_key, (void *) nc_addr) != 0) {
free(nc_addr);
return (&nc_error);
}
*nc_addr = 0;
}
return (nc_addr);
}
#define nc_error (*(__nc_error()))
/*
* A call to setnetconfig() establishes a /etc/netconfig "session". A session
* "handle" is returned on a successful call. At the start of a session (after
* a call to setnetconfig()) searches through the /etc/netconfig database will
* proceed from the start of the file. The session handle must be passed to
* getnetconfig() to parse the file. Each call to getnetconfig() using the
* current handle will process one subsequent entry in /etc/netconfig.
* setnetconfig() must be called before the first call to getnetconfig().
* (Handles are used to allow for nested calls to setnetpath()).
*
* A new session is established with each call to setnetconfig(), with a new
* handle being returned on each call. Previously established sessions remain
* active until endnetconfig() is called with that session's handle as an
* argument.
*
* setnetconfig() need *not* be called before a call to getnetconfigent().
* setnetconfig() returns a NULL pointer on failure (for example, if
* the netconfig database is not present).
*/
void *
setnetconfig(void)
{
struct netconfig_vars *nc_vars;
if ((nc_vars = (struct netconfig_vars *)malloc(sizeof
(struct netconfig_vars))) == NULL) {
return(NULL);
}
/*
* For multiple calls, i.e. nc_file is not NULL, we just return the
* handle without reopening the netconfig db.
*/
mutex_lock(&ni_lock);
ni.ref++;
mutex_unlock(&ni_lock);
mutex_lock(&nc_file_lock);
if ((nc_file != NULL) || (nc_file = fopen(NETCONFIG, "r")) != NULL) {
nc_vars->valid = NC_VALID;
nc_vars->flag = 0;
nc_vars->nc_configs = ni.head;
mutex_unlock(&nc_file_lock);
return ((void *)nc_vars);
}
mutex_unlock(&nc_file_lock);
mutex_lock(&ni_lock);
ni.ref--;
mutex_unlock(&ni_lock);
nc_error = NC_NONETCONFIG;
free(nc_vars);
return (NULL);
}
/*
* When first called, getnetconfig() returns a pointer to the first entry in
* the netconfig database, formatted as a struct netconfig. On each subsequent
* call, getnetconfig() returns a pointer to the next entry in the database.
* getnetconfig() can thus be used to search the entire netconfig file.
* getnetconfig() returns NULL at end of file.
*/
struct netconfig *
getnetconfig(void *handlep)
{
struct netconfig_vars *ncp = (struct netconfig_vars *)handlep;
char *stringp; /* tmp string pointer */
struct netconfig_list *list;
struct netconfig *np;
struct netconfig *result;
/*
* Verify that handle is valid
*/
mutex_lock(&nc_file_lock);
if (ncp == NULL || nc_file == NULL) {
nc_error = NC_NOTINIT;
mutex_unlock(&nc_file_lock);
return (NULL);
}
mutex_unlock(&nc_file_lock);
switch (ncp->valid) {
case NC_VALID:
/*
* If entry has already been read into the list,
* we return the entry in the linked list.
* If this is the first time call, check if there are any entries in
* linked list. If no entries, we need to read the netconfig db.
* If we have been here and the next entry is there, we just return
* it.
*/
if (ncp->flag == 0) { /* first time */
ncp->flag = 1;
mutex_lock(&ni_lock);
ncp->nc_configs = ni.head;
mutex_unlock(&ni_lock);
if (ncp->nc_configs != NULL) /* entry already exist */
return(ncp->nc_configs->ncp);
}
else if (ncp->nc_configs != NULL && ncp->nc_configs->next != NULL) {
ncp->nc_configs = ncp->nc_configs->next;
return(ncp->nc_configs->ncp);
}
/*
* If we cannot find the entry in the list and is end of file,
* we give up.
*/
mutex_lock(&ni_lock);
if (ni.eof == 1) {
mutex_unlock(&ni_lock);
return(NULL);
}
mutex_unlock(&ni_lock);
break;
default:
nc_error = NC_NOTINIT;
return (NULL);
}
stringp = (char *) malloc(MAXNETCONFIGLINE);
if (stringp == NULL)
return (NULL);
#ifdef MEM_CHK
if (malloc_verify() == 0) {
fprintf(stderr, "memory heap corrupted in getnetconfig\n");
exit(1);
}
#endif
/*
* Read a line from netconfig file.
*/
mutex_lock(&nc_file_lock);
do {
if (fgets(stringp, MAXNETCONFIGLINE, nc_file) == NULL) {
free(stringp);
mutex_lock(&ni_lock);
ni.eof = 1;
mutex_unlock(&ni_lock);
mutex_unlock(&nc_file_lock);
return (NULL);
}
} while (*stringp == '#');
mutex_unlock(&nc_file_lock);
list = (struct netconfig_list *) malloc(sizeof (struct netconfig_list));
if (list == NULL) {
free(stringp);
return(NULL);
}
np = (struct netconfig *) malloc(sizeof (struct netconfig));
if (np == NULL) {
free(stringp);
free(list);
return(NULL);
}
list->ncp = np;
list->next = NULL;
list->ncp->nc_lookups = NULL;
list->linep = stringp;
if (parse_ncp(stringp, list->ncp) == -1) {
free(stringp);
free(np);
free(list);
return (NULL);
}
else {
/*
* If this is the first entry that's been read, it is the head of
* the list. If not, put the entry at the end of the list.
* Reposition the current pointer of the handle to the last entry
* in the list.
*/
mutex_lock(&ni_lock);
if (ni.head == NULL) { /* first entry */
ni.head = ni.tail = list;
}
else {
ni.tail->next = list;
ni.tail = ni.tail->next;
}
ncp->nc_configs = ni.tail;
result = ni.tail->ncp;
mutex_unlock(&ni_lock);
return(result);
}
}
/*
* endnetconfig() may be called to "unbind" or "close" the netconfig database
* when processing is complete, releasing resources for reuse. endnetconfig()
* may not be called before setnetconfig(). endnetconfig() returns 0 on
* success and -1 on failure (for example, if setnetconfig() was not called
* previously).
*/
int
endnetconfig(void *handlep)
{
struct netconfig_vars *nc_handlep = (struct netconfig_vars *)handlep;
struct netconfig_list *q, *p;
/*
* Verify that handle is valid
*/
if (nc_handlep == NULL || (nc_handlep->valid != NC_VALID &&
nc_handlep->valid != NC_STORAGE)) {
nc_error = NC_NOTINIT;
return (-1);
}
/*
* Return 0 if anyone still needs it.
*/
nc_handlep->valid = NC_INVALID;
nc_handlep->flag = 0;
nc_handlep->nc_configs = NULL;
mutex_lock(&ni_lock);
if (--ni.ref > 0) {
mutex_unlock(&ni_lock);
free(nc_handlep);
return(0);
}
/*
* No one needs these entries anymore, then frees them.
* Make sure all info in netconfig_info structure has been reinitialized.
*/
q = ni.head;
ni.eof = ni.ref = 0;
ni.head = NULL;
ni.tail = NULL;
mutex_unlock(&ni_lock);
while (q != NULL) {
p = q->next;
free(q->ncp->nc_lookups);
free(q->ncp);
free(q->linep);
free(q);
q = p;
}
free(nc_handlep);
mutex_lock(&nc_file_lock);
fclose(nc_file);
nc_file = NULL;
mutex_unlock(&nc_file_lock);
return (0);
}
/*
* getnetconfigent(netid) returns a pointer to the struct netconfig structure
* corresponding to netid. It returns NULL if netid is invalid (that is, does
* not name an entry in the netconfig database). It returns NULL and sets
* errno in case of failure (for example, if the netconfig database cannot be
* opened).
*/
struct netconfig *
getnetconfigent(const char *netid)
{
FILE *file; /* NETCONFIG db's file pointer */
char *linep; /* holds current netconfig line */
char *stringp; /* temporary string pointer */
struct netconfig *ncp = NULL; /* returned value */
struct netconfig_list *list; /* pointer to cache list */
nc_error = NC_NOTFOUND; /* default error. */
if (netid == NULL || strlen(netid) == 0) {
return (NULL);
}
/*
* Look up table if the entries have already been read and parsed in
* getnetconfig(), then copy this entry into a buffer and return it.
* If we cannot find the entry in the current list and there are more
* entries in the netconfig db that has not been read, we then read the
* db and try find the match netid.
* If all the netconfig db has been read and placed into the list and
* there is no match for the netid, return NULL.
*/
mutex_lock(&ni_lock);
if (ni.head != NULL) {
for (list = ni.head; list; list = list->next) {
if (strcmp(list->ncp->nc_netid, netid) == 0) {
mutex_unlock(&ni_lock);
return(dup_ncp(list->ncp));
}
}
if (ni.eof == 1) { /* that's all the entries */
mutex_unlock(&ni_lock);
return(NULL);
}
}
mutex_unlock(&ni_lock);
if ((file = fopen(NETCONFIG, "r")) == NULL) {
nc_error = NC_NONETCONFIG;
return (NULL);
}
if ((linep = malloc(MAXNETCONFIGLINE)) == NULL) {
fclose(file);
nc_error = NC_NOMEM;
return (NULL);
}
do {
ptrdiff_t len;
char *tmpp; /* tmp string pointer */
do {
if ((stringp = fgets(linep, MAXNETCONFIGLINE, file)) == NULL) {
break;
}
} while (*stringp == '#');
if (stringp == NULL) { /* eof */
break;
}
if ((tmpp = strpbrk(stringp, "\t ")) == NULL) { /* can't parse file */
nc_error = NC_BADFILE;
break;
}
if (strlen(netid) == (size_t) (len = tmpp - stringp) && /* a match */
strncmp(stringp, netid, (size_t)len) == 0) {
if ((ncp = (struct netconfig *)
malloc(sizeof (struct netconfig))) == NULL) {
break;
}
ncp->nc_lookups = NULL;
if (parse_ncp(linep, ncp) == -1) {
free(ncp);
ncp = NULL;
}
break;
}
} while (stringp != NULL);
if (ncp == NULL) {
free(linep);
}
fclose(file);
return(ncp);
}
/*
* freenetconfigent(netconfigp) frees the netconfig structure pointed to by
* netconfigp (previously returned by getnetconfigent()).
*/
void
freenetconfigent(struct netconfig *netconfigp)
{
if (netconfigp != NULL) {
free(netconfigp->nc_netid); /* holds all netconfigp's strings */
free(netconfigp->nc_lookups);
free(netconfigp);
}
return;
}
/*
* Parse line and stuff it in a struct netconfig
* Typical line might look like:
* udp tpi_cots vb inet udp /dev/udp /usr/lib/ip.so,/usr/local/ip.so
*
* We return -1 if any of the tokens don't parse, or malloc fails.
*
* Note that we modify stringp (putting NULLs after tokens) and
* we set the ncp's string field pointers to point to these tokens within
* stringp.
*
* stringp - string to parse
* ncp - where to put results
*/
static int
parse_ncp(char *stringp, struct netconfig *ncp)
{
char *tokenp; /* for processing tokens */
char *lasts;
char **nc_lookups;
nc_error = NC_BADFILE; /* nearly anything that breaks is for this reason */
stringp[strlen(stringp)-1] = '\0'; /* get rid of newline */
/* netid */
if ((ncp->nc_netid = strtok_r(stringp, "\t ", &lasts)) == NULL) {
return (-1);
}
/* semantics */
if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
return (-1);
}
if (strcmp(tokenp, NC_TPI_COTS_ORD_S) == 0)
ncp->nc_semantics = NC_TPI_COTS_ORD;
else if (strcmp(tokenp, NC_TPI_COTS_S) == 0)
ncp->nc_semantics = NC_TPI_COTS;
else if (strcmp(tokenp, NC_TPI_CLTS_S) == 0)
ncp->nc_semantics = NC_TPI_CLTS;
else if (strcmp(tokenp, NC_TPI_RAW_S) == 0)
ncp->nc_semantics = NC_TPI_RAW;
else
return (-1);
/* flags */
if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
return (-1);
}
for (ncp->nc_flag = NC_NOFLAG; *tokenp != '\0';
tokenp++) {
switch (*tokenp) {
case NC_NOFLAG_C:
break;
case NC_VISIBLE_C:
ncp->nc_flag |= NC_VISIBLE;
break;
case NC_BROADCAST_C:
ncp->nc_flag |= NC_BROADCAST;
break;
default:
return (-1);
}
}
/* protocol family */
if ((ncp->nc_protofmly = strtok_r(NULL, "\t ", &lasts)) == NULL) {
return (-1);
}
/* protocol name */
if ((ncp->nc_proto = strtok_r(NULL, "\t ", &lasts)) == NULL) {
return (-1);
}
/* network device */
if ((ncp->nc_device = strtok_r(NULL, "\t ", &lasts)) == NULL) {
return (-1);
}
if ((tokenp = strtok_r(NULL, "\t ", &lasts)) == NULL) {
return (-1);
}
if (strcmp(tokenp, NC_NOLOOKUP) == 0) {
ncp->nc_nlookups = 0;
ncp->nc_lookups = NULL;
} else {
char *cp; /* tmp string */
free(ncp->nc_lookups); /* from last visit */
ncp->nc_lookups = NULL;
ncp->nc_nlookups = 0;
while ((cp = tokenp) != NULL) {
if ((nc_lookups = reallocarray(ncp->nc_lookups,
ncp->nc_nlookups + 1, sizeof(*ncp->nc_lookups))) == NULL) {
free(ncp->nc_lookups);
ncp->nc_lookups = NULL;
return (-1);
}
tokenp = _get_next_token(cp, ',');
ncp->nc_lookups = nc_lookups;
ncp->nc_lookups[ncp->nc_nlookups++] = cp;
}
}
return (0);
}
/*
* Returns a string describing the reason for failure.
*/
char *
nc_sperror(void)
{
const char *message;
switch(nc_error) {
case NC_NONETCONFIG:
message = _nc_errors[0];
break;
case NC_NOMEM:
message = _nc_errors[1];
break;
case NC_NOTINIT:
message = _nc_errors[2];
break;
case NC_BADFILE:
message = _nc_errors[3];
break;
case NC_NOTFOUND:
message = _nc_errors[4];
break;
default:
message = "Unknown network selection error";
}
/* LINTED const castaway */
return ((char *)message);
}
/*
* Prints a message onto standard error describing the reason for failure.
*/
void
nc_perror(const char *s)
{
fprintf(stderr, "%s: %s\n", s, nc_sperror());
}
/*
* Duplicates the matched netconfig buffer.
*/
static struct netconfig *
dup_ncp(struct netconfig *ncp)
{
struct netconfig *p;
char *tmp;
u_int i;
if ((tmp=malloc(MAXNETCONFIGLINE)) == NULL)
return(NULL);
if ((p=(struct netconfig *)malloc(sizeof(struct netconfig))) == NULL) {
free(tmp);
return(NULL);
}
/*
* First we dup all the data from matched netconfig buffer. Then we
* adjust some of the member pointer to a pre-allocated buffer where
* contains part of the data.
* To follow the convention used in parse_ncp(), we store all the
* necessary information in the pre-allocated buffer and let each
* of the netconfig char pointer member point to the right address
* in the buffer.
*/
*p = *ncp;
p->nc_netid = (char *)strcpy(tmp,ncp->nc_netid);
tmp = strchr(tmp, '\0') + 1;
p->nc_protofmly = (char *)strcpy(tmp,ncp->nc_protofmly);
tmp = strchr(tmp, '\0') + 1;
p->nc_proto = (char *)strcpy(tmp,ncp->nc_proto);
tmp = strchr(tmp, '\0') + 1;
p->nc_device = (char *)strcpy(tmp,ncp->nc_device);
p->nc_lookups = (char **)malloc((size_t)(p->nc_nlookups+1) * sizeof(char *));
if (p->nc_lookups == NULL) {
free(p->nc_netid);
free(p);
return(NULL);
}
for (i=0; i < p->nc_nlookups; i++) {
tmp = strchr(tmp, '\0') + 1;
p->nc_lookups[i] = (char *)strcpy(tmp,ncp->nc_lookups[i]);
}
return(p);
}
diff --git a/lib/libc/rpc/getnetpath.c b/lib/libc/rpc/getnetpath.c
index 4ae32a8783e2..02713f6c6c71 100644
--- a/lib/libc/rpc/getnetpath.c
+++ b/lib/libc/rpc/getnetpath.c
@@ -1,271 +1,270 @@
/* $NetBSD: getnetpath.c,v 1.3 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getnetpath.c 1.11 91/12/19 SMI";
#endif
-#include <sys/cdefs.h>
/*
* Copyright (c) 1989 by Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <stdio.h>
#include <errno.h>
#include <netconfig.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include "un-namespace.h"
/*
* internal structure to keep track of a netpath "session"
*/
struct netpath_chain {
struct netconfig *ncp; /* an nconf entry */
struct netpath_chain *nchain_next; /* next nconf entry allocated */
};
struct netpath_vars {
int valid; /* token that indicates a valid netpath_vars */
void *nc_handlep; /* handle for current netconfig "session" */
char *netpath; /* pointer to current view-point in NETPATH */
char *netpath_start; /* pointer to start of our copy of NETPATH */
struct netpath_chain *ncp_list; /* list of nconfs allocated this session*/
};
#define NP_VALID 0xf00d
#define NP_INVALID 0
char *_get_next_token(char *, int);
/*
* A call to setnetpath() establishes a NETPATH "session". setnetpath()
* must be called before the first call to getnetpath(). A "handle" is
* returned to distinguish the session; this handle should be passed
* subsequently to getnetpath(). (Handles are used to allow for nested calls
* to setnetpath()).
* If setnetpath() is unable to establish a session (due to lack of memory
* resources, or the absence of the /etc/netconfig file), a NULL pointer is
* returned.
*/
void *
setnetpath(void)
{
struct netpath_vars *np_sessionp; /* this session's variables */
char *npp; /* NETPATH env variable */
#ifdef MEM_CHK
malloc_debug(1);
#endif
if ((np_sessionp =
(struct netpath_vars *)malloc(sizeof (struct netpath_vars))) == NULL) {
return (NULL);
}
if ((np_sessionp->nc_handlep = setnetconfig()) == NULL) {
syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
goto failed;
}
np_sessionp->valid = NP_VALID;
np_sessionp->ncp_list = NULL;
if ((npp = getenv(NETPATH)) == NULL) {
np_sessionp->netpath = NULL;
} else {
(void) endnetconfig(np_sessionp->nc_handlep);/* won't need nc session*/
np_sessionp->nc_handlep = NULL;
if ((np_sessionp->netpath = malloc(strlen(npp)+1)) == NULL)
goto failed;
else {
(void) strcpy(np_sessionp->netpath, npp);
}
}
np_sessionp->netpath_start = np_sessionp->netpath;
return ((void *)np_sessionp);
failed:
free(np_sessionp);
return (NULL);
}
/*
* When first called, getnetpath() returns a pointer to the netconfig
* database entry corresponding to the first valid NETPATH component. The
* netconfig entry is formatted as a struct netconfig.
* On each subsequent call, getnetpath returns a pointer to the netconfig
* entry that corresponds to the next valid NETPATH component. getnetpath
* can thus be used to search the netconfig database for all networks
* included in the NETPATH variable.
* When NETPATH has been exhausted, getnetpath() returns NULL. It returns
* NULL and sets errno in case of an error (e.g., setnetpath was not called
* previously).
* getnetpath() silently ignores invalid NETPATH components. A NETPATH
* component is invalid if there is no corresponding entry in the netconfig
* database.
* If the NETPATH variable is unset, getnetpath() behaves as if NETPATH
* were set to the sequence of default or visible networks in the netconfig
* database, in the order in which they are listed.
*/
struct netconfig *
getnetpath(void *handlep)
{
struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
struct netconfig *ncp = NULL; /* temp. holds a netconfig session */
struct netpath_chain *chainp; /* holds chain of ncp's we alloc */
char *npp; /* holds current NETPATH */
if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
errno = EINVAL;
return (NULL);
}
if (np_sessionp->netpath_start == NULL) { /* NETPATH was not set */
do { /* select next visible network */
if (np_sessionp->nc_handlep == NULL) {
np_sessionp->nc_handlep = setnetconfig();
if (np_sessionp->nc_handlep == NULL)
syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
}
if ((ncp = getnetconfig(np_sessionp->nc_handlep)) == NULL) {
return(NULL);
}
} while ((ncp->nc_flag & NC_VISIBLE) == 0);
return (ncp);
}
/*
* Find first valid network ID in netpath.
*/
while ((npp = np_sessionp->netpath) != NULL && strlen(npp) != 0) {
np_sessionp->netpath = _get_next_token(npp, ':');
/*
* npp is a network identifier.
*/
if ((ncp = getnetconfigent(npp)) != NULL) {
chainp = (struct netpath_chain *) /* cobble alloc chain entry */
malloc(sizeof (struct netpath_chain));
chainp->ncp = ncp;
chainp->nchain_next = NULL;
if (np_sessionp->ncp_list == NULL) {
np_sessionp->ncp_list = chainp;
} else {
np_sessionp->ncp_list->nchain_next = chainp;
}
return (ncp);
}
/* couldn't find this token in the database; go to next one. */
}
return (NULL);
}
/*
* endnetpath() may be called to unbind NETPATH when processing is complete,
* releasing resources for reuse. It returns 0 on success and -1 on failure
* (e.g. if setnetpath() was not called previously.
*/
int
endnetpath(void *handlep)
{
struct netpath_vars *np_sessionp = (struct netpath_vars *)handlep;
struct netpath_chain *chainp, *lastp;
if (np_sessionp == NULL || np_sessionp->valid != NP_VALID) {
errno = EINVAL;
return (-1);
}
if (np_sessionp->nc_handlep != NULL)
endnetconfig(np_sessionp->nc_handlep);
if (np_sessionp->netpath_start != NULL)
free(np_sessionp->netpath_start);
for (chainp = np_sessionp->ncp_list; chainp != NULL;
lastp=chainp, chainp=chainp->nchain_next, free(lastp)) {
freenetconfigent(chainp->ncp);
}
free(np_sessionp);
#ifdef MEM_CHK
if (malloc_verify() == 0) {
fprintf(stderr, "memory heap corrupted in endnetpath\n");
exit(1);
}
#endif
return (0);
}
/*
* Returns pointer to the rest-of-the-string after the current token.
* The token itself starts at arg, and we null terminate it. We return NULL
* if either the arg is empty, or if this is the last token.
*
* npp - string
* token - char to parse string for
*/
char *
_get_next_token(char *npp, int token)
{
char *cp; /* char pointer */
char *np; /* netpath pointer */
char *ep; /* escape pointer */
if ((cp = strchr(npp, token)) == NULL) {
return (NULL);
}
/*
* did find a token, but it might be escaped.
*/
if ((cp > npp) && (cp[-1] == '\\')) {
/* if slash was also escaped, carry on, otherwise find next token */
if ((cp > npp + 1) && (cp[-2] != '\\')) {
/* shift r-o-s onto the escaped token */
strcpy(&cp[-1], cp); /* XXX: overlapping string copy */
/*
* Do a recursive call.
* We don't know how many escaped tokens there might be.
*/
return (_get_next_token(cp, token));
}
}
*cp++ = '\0'; /* null-terminate token */
/* get rid of any backslash escapes */
ep = npp;
while ((np = strchr(ep, '\\')) != NULL) {
if (np[1] == '\\')
np++;
strcpy(np, (ep = &np[1])); /* XXX: overlapping string copy */
}
return (cp); /* return ptr to r-o-s */
}
diff --git a/lib/libc/rpc/getpublickey.c b/lib/libc/rpc/getpublickey.c
index 76f8258d45c1..d2994bbcc400 100644
--- a/lib/libc/rpc/getpublickey.c
+++ b/lib/libc/rpc/getpublickey.c
@@ -1,171 +1,170 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)publickey.c 1.10 91/03/11 Copyr 1986 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* publickey.c
* Copyright (C) 1986, Sun Microsystems, Inc.
*/
/*
* Public key lookup routines
*/
#include "namespace.h"
#include <stdio.h>
#include <pwd.h>
#include <rpc/rpc.h>
#include <rpc/key_prot.h>
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#include <string.h>
#include <stdlib.h>
#include "un-namespace.h"
#define PKFILE "/etc/publickey"
/*
* Hack to let ypserv/rpc.nisd use AUTH_DES.
*/
int (*__getpublickey_LOCAL)(const char *, char *) = 0;
/*
* Get somebody's public key
*/
static int
__getpublickey_real(const char *netname, char *publickey)
{
char lookup[3 * HEXKEYBYTES];
char *p;
if (publickey == NULL)
return (0);
if (!getpublicandprivatekey(netname, lookup))
return (0);
p = strchr(lookup, ':');
if (p == NULL) {
return (0);
}
*p = '\0';
(void) strncpy(publickey, lookup, HEXKEYBYTES);
publickey[HEXKEYBYTES] = '\0';
return (1);
}
/*
* reads the file /etc/publickey looking for a + to optionally go to the
* yellow pages
*/
int
getpublicandprivatekey(const char *key, char *ret)
{
char buf[1024]; /* big enough */
char *res;
FILE *fd;
char *mkey;
char *mval;
fd = fopen(PKFILE, "r");
if (fd == NULL)
return (0);
for (;;) {
res = fgets(buf, sizeof(buf), fd);
if (res == NULL) {
fclose(fd);
return (0);
}
if (res[0] == '#')
continue;
else if (res[0] == '+') {
#ifdef YP
char *PKMAP = "publickey.byname";
char *lookup;
char *domain;
int err;
int len;
err = yp_get_default_domain(&domain);
if (err) {
continue;
}
lookup = NULL;
err = yp_match(domain, PKMAP, key, strlen(key), &lookup, &len);
if (err) {
#ifdef DEBUG
fprintf(stderr, "match failed error %d\n", err);
#endif
continue;
}
lookup[len] = 0;
strcpy(ret, lookup);
fclose(fd);
free(lookup);
return (2);
#else /* YP */
#ifdef DEBUG
fprintf(stderr,
"Bad record in %s '+' -- NIS not supported in this library copy\n", PKFILE);
#endif /* DEBUG */
continue;
#endif /* YP */
} else {
mkey = strsep(&res, "\t ");
if (mkey == NULL) {
fprintf(stderr,
"Bad record in %s -- %s", PKFILE, buf);
continue;
}
do {
mval = strsep(&res, " \t#\n");
} while (mval != NULL && !*mval);
if (mval == NULL) {
fprintf(stderr,
"Bad record in %s val problem - %s", PKFILE, buf);
continue;
}
if (strcmp(mkey, key) == 0) {
strcpy(ret, mval);
fclose(fd);
return (1);
}
}
}
}
int getpublickey(const char *netname, char *publickey)
{
if (__getpublickey_LOCAL != NULL)
return(__getpublickey_LOCAL(netname, publickey));
else
return(__getpublickey_real(netname, publickey));
}
diff --git a/lib/libc/rpc/getrpcent.c b/lib/libc/rpc/getrpcent.c
index c980aaee5d83..42d6ced5327f 100644
--- a/lib/libc/rpc/getrpcent.c
+++ b/lib/libc/rpc/getrpcent.c
@@ -1,1055 +1,1054 @@
/* $NetBSD: getrpcent.c,v 1.17 2000/01/22 22:19:17 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid = "@(#)getrpcent.c 1.14 91/03/11 Copyr 1984 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* Copyright (c) 1984 by Sun Microsystems, Inc.
*/
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <nsswitch.h>
#include <netinet/in.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <rpc/rpc.h>
#ifdef YP
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include <unistd.h>
#include "namespace.h"
#include "reentrant.h"
#include "un-namespace.h"
#include "libc_private.h"
#include "nss_tls.h"
#ifdef NS_CACHING
#include "nscache.h"
#endif
#define RPCDB "/etc/rpc"
/* nsswitch declarations */
enum constants
{
SETRPCENT = 1,
ENDRPCENT = 2,
RPCENT_STORAGE_INITIAL = 1 << 10, /* 1 KByte */
RPCENT_STORAGE_MAX = 1 << 20, /* 1 MByte */
};
static const ns_src defaultsrc[] = {
{ NSSRC_FILES, NS_SUCCESS },
#ifdef YP
{ NSSRC_NIS, NS_SUCCESS },
#endif
{ NULL, 0 }
};
/* files backend declarations */
struct files_state {
FILE *fp;
int stayopen;
};
static int files_rpcent(void *, void *, va_list);
static int files_setrpcent(void *, void *, va_list);
static void files_endstate(void *);
NSS_TLS_HANDLING(files);
/* nis backend declarations */
#ifdef YP
struct nis_state {
char domain[MAXHOSTNAMELEN];
char *current;
int currentlen;
int stepping;
int no_name_map;
};
static int nis_rpcent(void *, void *, va_list);
static int nis_setrpcent(void *, void *, va_list);
static void nis_endstate(void *);
NSS_TLS_HANDLING(nis);
#endif
/* get** wrappers for get**_r functions declarations */
struct rpcent_state {
struct rpcent rpc;
char *buffer;
size_t bufsize;
};
static void rpcent_endstate(void *);
NSS_TLS_HANDLING(rpcent);
union key {
const char *name;
int number;
};
static int wrap_getrpcbyname_r(union key, struct rpcent *, char *,
size_t, struct rpcent **);
static int wrap_getrpcbynumber_r(union key, struct rpcent *, char *,
size_t, struct rpcent **);
static int wrap_getrpcent_r(union key, struct rpcent *, char *,
size_t, struct rpcent **);
static struct rpcent *getrpc(int (*fn)(union key, struct rpcent *, char *,
size_t, struct rpcent **), union key);
#ifdef NS_CACHING
static int rpc_id_func(char *, size_t *, va_list, void *);
static int rpc_marshal_func(char *, size_t *, void *, va_list, void *);
static int rpc_unmarshal_func(char *, size_t, void *, va_list, void *);
#endif
static int
rpcent_unpack(char *p, struct rpcent *rpc, char **r_aliases,
size_t aliases_size, int *errnop)
{
char *cp, **q;
assert(p != NULL);
if (*p == '#')
return (-1);
cp = strpbrk(p, "#\n");
if (cp == NULL)
return (-1);
*cp = '\0';
cp = strpbrk(p, " \t");
if (cp == NULL)
return (-1);
*cp++ = '\0';
/* THIS STUFF IS INTERNET SPECIFIC */
rpc->r_name = p;
while (*cp == ' ' || *cp == '\t')
cp++;
rpc->r_number = atoi(cp);
q = rpc->r_aliases = r_aliases;
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
while (cp && *cp) {
if (*cp == ' ' || *cp == '\t') {
cp++;
continue;
}
if (q < &(r_aliases[aliases_size - 1]))
*q++ = cp;
else {
*errnop = ERANGE;
return -1;
}
cp = strpbrk(cp, " \t");
if (cp != NULL)
*cp++ = '\0';
}
*q = NULL;
return 0;
}
/* files backend implementation */
static void
files_endstate(void *p)
{
FILE * f;
if (p == NULL)
return;
f = ((struct files_state *)p)->fp;
if (f != NULL)
fclose(f);
free(p);
}
static int
files_rpcent(void *retval, void *mdata, va_list ap)
{
char *name;
int number;
struct rpcent *rpc;
char *buffer;
size_t bufsize;
int *errnop;
char *line;
size_t linesize;
char **aliases;
int aliases_size;
char **rp;
struct files_state *st;
int rv;
int stayopen;
enum nss_lookup_type how;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how)
{
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
number = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
return (NS_NOTFOUND);
}
rpc = va_arg(ap, struct rpcent *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = files_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->fp == NULL && (st->fp = fopen(RPCDB, "r")) == NULL) {
*errnop = errno;
return (NS_UNAVAIL);
}
if (how == nss_lt_all)
stayopen = 1;
else {
rewind(st->fp);
stayopen = st->stayopen;
}
do {
if ((line = fgetln(st->fp, &linesize)) == NULL) {
*errnop = errno;
rv = NS_RETURN;
break;
}
if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) {
*errnop = ERANGE;
rv = NS_RETURN;
break;
}
aliases = (char **)_ALIGN(&buffer[linesize+1]);
aliases_size = (buffer + bufsize -
(char *)aliases)/sizeof(char *);
if (aliases_size < 1) {
*errnop = ERANGE;
rv = NS_RETURN;
break;
}
memcpy(buffer, line, linesize);
buffer[linesize] = '\0';
rv = rpcent_unpack(buffer, rpc, aliases, aliases_size, errnop);
if (rv != 0) {
if (*errnop == 0) {
rv = NS_NOTFOUND;
continue;
}
else {
rv = NS_RETURN;
break;
}
}
switch (how)
{
case nss_lt_name:
if (strcmp(rpc->r_name, name) == 0)
goto done;
for (rp = rpc->r_aliases; *rp != NULL; rp++) {
if (strcmp(*rp, name) == 0)
goto done;
}
rv = NS_NOTFOUND;
continue;
done:
rv = NS_SUCCESS;
break;
case nss_lt_id:
rv = (rpc->r_number == number) ? NS_SUCCESS :
NS_NOTFOUND;
break;
case nss_lt_all:
rv = NS_SUCCESS;
break;
}
} while (!(rv & NS_TERMINATE));
if (!stayopen && st->fp!=NULL) {
fclose(st->fp);
st->fp = NULL;
}
if ((rv == NS_SUCCESS) && (retval != NULL))
*((struct rpcent **)retval) = rpc;
return (rv);
}
static int
files_setrpcent(void *retval, void *mdata, va_list ap)
{
struct files_state *st;
int rv;
int f;
rv = files_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata)
{
case SETRPCENT:
f = va_arg(ap,int);
if (st->fp == NULL)
st->fp = fopen(RPCDB, "r");
else
rewind(st->fp);
st->stayopen |= f;
break;
case ENDRPCENT:
if (st->fp != NULL) {
fclose(st->fp);
st->fp = NULL;
}
st->stayopen = 0;
break;
default:
break;
}
return (NS_UNAVAIL);
}
/* nis backend implementation */
#ifdef YP
static void
nis_endstate(void *p)
{
if (p == NULL)
return;
free(((struct nis_state *)p)->current);
free(p);
}
static int
nis_rpcent(void *retval, void *mdata, va_list ap)
{
char *name;
int number;
struct rpcent *rpc;
char *buffer;
size_t bufsize;
int *errnop;
char **rp;
char **aliases;
int aliases_size;
char *lastkey;
char *resultbuf;
int resultbuflen;
char *buf;
struct nis_state *st;
int rv;
enum nss_lookup_type how;
int no_name_active;
how = (enum nss_lookup_type)(uintptr_t)mdata;
switch (how)
{
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
number = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
return (NS_NOTFOUND);
}
buf = NULL;
rpc = va_arg(ap, struct rpcent *);
buffer = va_arg(ap, char *);
bufsize = va_arg(ap, size_t);
errnop = va_arg(ap, int *);
*errnop = nis_getstate(&st);
if (*errnop != 0)
return (NS_UNAVAIL);
if (st->domain[0] == '\0') {
if (getdomainname(st->domain, sizeof(st->domain)) != 0) {
*errnop = errno;
return (NS_UNAVAIL);
}
}
no_name_active = 0;
do {
switch (how)
{
case nss_lt_name:
if (!st->no_name_map)
{
free(buf);
asprintf(&buf, "%s", name);
if (buf == NULL)
return (NS_TRYAGAIN);
rv = yp_match(st->domain, "rpc.byname", buf,
strlen(buf), &resultbuf, &resultbuflen);
switch (rv) {
case 0:
break;
case YPERR_MAP:
st->stepping = 0;
no_name_active = 1;
how = nss_lt_all;
rv = NS_NOTFOUND;
continue;
default:
rv = NS_NOTFOUND;
goto fin;
}
} else {
st->stepping = 0;
no_name_active = 1;
how = nss_lt_all;
rv = NS_NOTFOUND;
continue;
}
break;
case nss_lt_id:
free(buf);
asprintf(&buf, "%d", number);
if (buf == NULL)
return (NS_TRYAGAIN);
if (yp_match(st->domain, "rpc.bynumber", buf,
strlen(buf), &resultbuf, &resultbuflen)) {
rv = NS_NOTFOUND;
goto fin;
}
break;
case nss_lt_all:
if (!st->stepping) {
rv = yp_first(st->domain, "rpc.bynumber",
&st->current,
&st->currentlen, &resultbuf,
&resultbuflen);
if (rv) {
rv = NS_NOTFOUND;
goto fin;
}
st->stepping = 1;
} else {
lastkey = st->current;
rv = yp_next(st->domain, "rpc.bynumber",
st->current,
st->currentlen, &st->current,
&st->currentlen,
&resultbuf, &resultbuflen);
free(lastkey);
if (rv) {
st->stepping = 0;
rv = NS_NOTFOUND;
goto fin;
}
}
break;
}
/* we need a room for additional \n symbol */
if (bufsize <= resultbuflen + 1 + _ALIGNBYTES +
sizeof(char *)) {
*errnop = ERANGE;
rv = NS_RETURN;
free(resultbuf);
break;
}
aliases=(char **)_ALIGN(&buffer[resultbuflen+2]);
aliases_size = (buffer + bufsize - (char *)aliases) /
sizeof(char *);
if (aliases_size < 1) {
*errnop = ERANGE;
rv = NS_RETURN;
free(resultbuf);
break;
}
/*
* rpcent_unpack expects lines terminated with \n -- make it happy
*/
memcpy(buffer, resultbuf, resultbuflen);
buffer[resultbuflen] = '\n';
buffer[resultbuflen+1] = '\0';
free(resultbuf);
if (rpcent_unpack(buffer, rpc, aliases, aliases_size,
errnop) != 0) {
if (*errnop == 0)
rv = NS_NOTFOUND;
else
rv = NS_RETURN;
} else {
if ((how == nss_lt_all) && (no_name_active != 0)) {
if (strcmp(rpc->r_name, name) == 0)
goto done;
for (rp = rpc->r_aliases; *rp != NULL; rp++) {
if (strcmp(*rp, name) == 0)
goto done;
}
rv = NS_NOTFOUND;
continue;
done:
rv = NS_SUCCESS;
} else
rv = NS_SUCCESS;
}
} while (!(rv & NS_TERMINATE) && (how == nss_lt_all));
fin:
free(buf);
if ((rv == NS_SUCCESS) && (retval != NULL))
*((struct rpcent **)retval) = rpc;
return (rv);
}
static int
nis_setrpcent(void *retval, void *mdata, va_list ap)
{
struct nis_state *st;
int rv;
rv = nis_getstate(&st);
if (rv != 0)
return (NS_UNAVAIL);
switch ((enum constants)(uintptr_t)mdata)
{
case SETRPCENT:
case ENDRPCENT:
free(st->current);
st->current = NULL;
st->stepping = 0;
break;
default:
break;
}
return (NS_UNAVAIL);
}
#endif
#ifdef NS_CACHING
static int
rpc_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata)
{
char *name;
int rpc;
size_t desired_size, size;
enum nss_lookup_type lookup_type;
int res = NS_UNAVAIL;
lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata;
switch (lookup_type) {
case nss_lt_name:
name = va_arg(ap, char *);
size = strlen(name);
desired_size = sizeof(enum nss_lookup_type) + size + 1;
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1);
res = NS_SUCCESS;
break;
case nss_lt_id:
rpc = va_arg(ap, int);
desired_size = sizeof(enum nss_lookup_type) + sizeof(int);
if (desired_size > *buffer_size) {
res = NS_RETURN;
goto fin;
}
memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type));
memcpy(buffer + sizeof(enum nss_lookup_type), &rpc,
sizeof(int));
res = NS_SUCCESS;
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
fin:
*buffer_size = desired_size;
return (res);
}
static int
rpc_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
int num __unused;
struct rpcent *rpc;
char *orig_buf __unused;
size_t orig_buf_size __unused;
struct rpcent new_rpc;
size_t desired_size, size, aliases_size;
char *p;
char **alias;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
num = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
rpc = va_arg(ap, struct rpcent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
desired_size = _ALIGNBYTES + sizeof(struct rpcent) + sizeof(char *);
if (rpc->r_name != NULL)
desired_size += strlen(rpc->r_name) + 1;
if (rpc->r_aliases != NULL) {
aliases_size = 0;
for (alias = rpc->r_aliases; *alias; ++alias) {
desired_size += strlen(*alias) + 1;
++aliases_size;
}
desired_size += _ALIGNBYTES + (aliases_size + 1) *
sizeof(char *);
}
if (*buffer_size < desired_size) {
/* this assignment is here for future use */
*buffer_size = desired_size;
return (NS_RETURN);
}
new_rpc = *rpc;
*buffer_size = desired_size;
memset(buffer, 0, desired_size);
p = buffer + sizeof(struct rpcent) + sizeof(char *);
memcpy(buffer + sizeof(struct rpcent), &p, sizeof(char *));
p = (char *)_ALIGN(p);
if (new_rpc.r_name != NULL) {
size = strlen(new_rpc.r_name);
memcpy(p, new_rpc.r_name, size);
new_rpc.r_name = p;
p += size + 1;
}
if (new_rpc.r_aliases != NULL) {
p = (char *)_ALIGN(p);
memcpy(p, new_rpc.r_aliases, sizeof(char *) * aliases_size);
new_rpc.r_aliases = (char **)p;
p += sizeof(char *) * (aliases_size + 1);
for (alias = new_rpc.r_aliases; *alias; ++alias) {
size = strlen(*alias);
memcpy(p, *alias, size);
*alias = p;
p += size + 1;
}
}
memcpy(buffer, &new_rpc, sizeof(struct rpcent));
return (NS_SUCCESS);
}
static int
rpc_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap,
void *cache_mdata)
{
char *name __unused;
int num __unused;
struct rpcent *rpc;
char *orig_buf;
size_t orig_buf_size;
int *ret_errno;
char *p;
char **alias;
switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) {
case nss_lt_name:
name = va_arg(ap, char *);
break;
case nss_lt_id:
num = va_arg(ap, int);
break;
case nss_lt_all:
break;
default:
/* should be unreachable */
return (NS_UNAVAIL);
}
rpc = va_arg(ap, struct rpcent *);
orig_buf = va_arg(ap, char *);
orig_buf_size = va_arg(ap, size_t);
ret_errno = va_arg(ap, int *);
if (orig_buf_size <
buffer_size - sizeof(struct rpcent) - sizeof(char *)) {
*ret_errno = ERANGE;
return (NS_RETURN);
}
memcpy(rpc, buffer, sizeof(struct rpcent));
memcpy(&p, buffer + sizeof(struct rpcent), sizeof(char *));
orig_buf = (char *)_ALIGN(orig_buf);
memcpy(orig_buf, buffer + sizeof(struct rpcent) + sizeof(char *) +
_ALIGN(p) - (size_t)p,
buffer_size - sizeof(struct rpcent) - sizeof(char *) -
_ALIGN(p) + (size_t)p);
p = (char *)_ALIGN(p);
NS_APPLY_OFFSET(rpc->r_name, orig_buf, p, char *);
if (rpc->r_aliases != NULL) {
NS_APPLY_OFFSET(rpc->r_aliases, orig_buf, p, char **);
for (alias = rpc->r_aliases ; *alias; ++alias)
NS_APPLY_OFFSET(*alias, orig_buf, p, char *);
}
if (retval != NULL)
*((struct rpcent **)retval) = rpc;
return (NS_SUCCESS);
}
NSS_MP_CACHE_HANDLING(rpc);
#endif /* NS_CACHING */
/* get**_r functions implementation */
static int
getrpcbyname_r(const char *name, struct rpcent *rpc, char *buffer,
size_t bufsize, struct rpcent **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
rpc, (void *)nss_lt_name,
rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_rpcent, (void *)nss_lt_name },
#ifdef YP
{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_name },
#endif
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbyname_r", defaultsrc,
name, rpc, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
static int
getrpcbynumber_r(int number, struct rpcent *rpc, char *buffer,
size_t bufsize, struct rpcent **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info =
NS_COMMON_CACHE_INFO_INITIALIZER(
rpc, (void *)nss_lt_id,
rpc_id_func, rpc_marshal_func, rpc_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_rpcent, (void *)nss_lt_id },
#ifdef YP
{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_id },
#endif
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcbynumber_r", defaultsrc,
number, rpc, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
static int
getrpcent_r(struct rpcent *rpc, char *buffer, size_t bufsize,
struct rpcent **result)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
rpc, (void *)nss_lt_all,
rpc_marshal_func, rpc_unmarshal_func);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_rpcent, (void *)nss_lt_all },
#ifdef YP
{ NSSRC_NIS, nis_rpcent, (void *)nss_lt_all },
#endif
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
int rv, ret_errno;
ret_errno = 0;
*result = NULL;
rv = nsdispatch(result, dtab, NSDB_RPC, "getrpcent_r", defaultsrc,
rpc, buffer, bufsize, &ret_errno);
if (rv == NS_SUCCESS)
return (0);
else
return (ret_errno);
}
/* get** wrappers for get**_r functions implementation */
static void
rpcent_endstate(void *p)
{
if (p == NULL)
return;
free(((struct rpcent_state *)p)->buffer);
free(p);
}
static int
wrap_getrpcbyname_r(union key key, struct rpcent *rpc, char *buffer,
size_t bufsize, struct rpcent **res)
{
return (getrpcbyname_r(key.name, rpc, buffer, bufsize, res));
}
static int
wrap_getrpcbynumber_r(union key key, struct rpcent *rpc, char *buffer,
size_t bufsize, struct rpcent **res)
{
return (getrpcbynumber_r(key.number, rpc, buffer, bufsize, res));
}
static int
wrap_getrpcent_r(union key key __unused, struct rpcent *rpc, char *buffer,
size_t bufsize, struct rpcent **res)
{
return (getrpcent_r(rpc, buffer, bufsize, res));
}
static struct rpcent *
getrpc(int (*fn)(union key, struct rpcent *, char *, size_t, struct rpcent **),
union key key)
{
int rv;
struct rpcent *res;
struct rpcent_state * st;
rv=rpcent_getstate(&st);
if (rv != 0) {
errno = rv;
return NULL;
}
if (st->buffer == NULL) {
st->buffer = malloc(RPCENT_STORAGE_INITIAL);
if (st->buffer == NULL)
return (NULL);
st->bufsize = RPCENT_STORAGE_INITIAL;
}
do {
rv = fn(key, &st->rpc, st->buffer, st->bufsize, &res);
if (res == NULL && rv == ERANGE) {
free(st->buffer);
if ((st->bufsize << 1) > RPCENT_STORAGE_MAX) {
st->buffer = NULL;
errno = ERANGE;
return (NULL);
}
st->bufsize <<= 1;
st->buffer = malloc(st->bufsize);
if (st->buffer == NULL)
return (NULL);
}
} while (res == NULL && rv == ERANGE);
if (rv != 0)
errno = rv;
return (res);
}
struct rpcent *
getrpcbyname(const char *name)
{
union key key;
key.name = name;
return (getrpc(wrap_getrpcbyname_r, key));
}
struct rpcent *
getrpcbynumber(int number)
{
union key key;
key.number = number;
return (getrpc(wrap_getrpcbynumber_r, key));
}
struct rpcent *
getrpcent(void)
{
union key key;
key.number = 0; /* not used */
return (getrpc(wrap_getrpcent_r, key));
}
void
setrpcent(int stayopen)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
rpc, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setrpcent, (void *)SETRPCENT },
#ifdef YP
{ NSSRC_NIS, nis_setrpcent, (void *)SETRPCENT },
#endif
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)nsdispatch(NULL, dtab, NSDB_RPC, "setrpcent", defaultsrc,
stayopen);
}
void
endrpcent(void)
{
#ifdef NS_CACHING
static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER(
rpc, (void *)nss_lt_all,
NULL, NULL);
#endif
static const ns_dtab dtab[] = {
{ NSSRC_FILES, files_setrpcent, (void *)ENDRPCENT },
#ifdef YP
{ NSSRC_NIS, nis_setrpcent, (void *)ENDRPCENT },
#endif
#ifdef NS_CACHING
NS_CACHE_CB(&cache_info)
#endif
{ NULL, NULL, NULL }
};
(void)nsdispatch(NULL, dtab, NSDB_RPC, "endrpcent", defaultsrc);
}
diff --git a/lib/libc/rpc/getrpcport.c b/lib/libc/rpc/getrpcport.c
index a6143ef0a8ba..ff636166990f 100644
--- a/lib/libc/rpc/getrpcport.c
+++ b/lib/libc/rpc/getrpcport.c
@@ -1,75 +1,74 @@
/* $NetBSD: getrpcport.c,v 1.16 2000/01/22 22:19:18 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)getrpcport.c 1.3 87/08/11 SMI";
static char *sccsid = "@(#)getrpcport.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* Copyright (c) 1985 by Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <assert.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include "un-namespace.h"
int
getrpcport(char *host, int prognum, int versnum, int proto)
{
struct sockaddr_in addr;
struct hostent *hp;
assert(host != NULL);
if ((hp = gethostbyname2(host, AF_INET)) == NULL)
return (0);
memset(&addr, 0, sizeof(addr));
addr.sin_len = sizeof(struct sockaddr_in);
addr.sin_family = AF_INET;
addr.sin_port = 0;
if (hp->h_length > sizeof(addr.sin_addr.s_addr))
hp->h_length = sizeof(addr.sin_addr.s_addr);
memcpy(&addr.sin_addr.s_addr, hp->h_addr, (size_t)hp->h_length);
/* Inconsistent interfaces need casts! :-( */
return (pmap_getport(&addr, (u_long)prognum, (u_long)versnum,
(u_int)proto));
}
diff --git a/lib/libc/rpc/key_call.c b/lib/libc/rpc/key_call.c
index 4af7ca9609ce..78710533655f 100644
--- a/lib/libc/rpc/key_call.c
+++ b/lib/libc/rpc/key_call.c
@@ -1,459 +1,458 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#ident "@(#)key_call.c 1.25 94/04/24 SMI"
-#include <sys/cdefs.h>
/*
* key_call.c, Interface to keyserver
*
* setsecretkey(key) - set your secret key
* encryptsessionkey(agent, deskey) - encrypt a session key to talk to agent
* decryptsessionkey(agent, deskey) - decrypt ditto
* gendeskey(deskey) - generate a secure des key
*/
#include "namespace.h"
#include "reentrant.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <rpc/auth.h>
#include <rpc/auth_unix.h>
#include <rpc/key_prot.h>
#include <string.h>
#include <netconfig.h>
#include <sys/utsname.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/fcntl.h>
#include "un-namespace.h"
#include "mt_misc.h"
#define KEY_TIMEOUT 5 /* per-try timeout in seconds */
#define KEY_NRETRY 12 /* number of retries */
#ifdef DEBUG
#define debug(msg) (void) fprintf(stderr, "%s\n", msg);
#else
#define debug(msg)
#endif /* DEBUG */
/*
* Hack to allow the keyserver to use AUTH_DES (for authenticated
* NIS+ calls, for example). The only functions that get called
* are key_encryptsession_pk, key_decryptsession_pk, and key_gendes.
*
* The approach is to have the keyserver fill in pointers to local
* implementations of these functions, and to call those in key_call().
*/
cryptkeyres *(*__key_encryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
cryptkeyres *(*__key_decryptsession_pk_LOCAL)(uid_t, void *arg) = 0;
des_block *(*__key_gendes_LOCAL)(uid_t, void *) = 0;
static int key_call( u_long, xdrproc_t, void *, xdrproc_t, void *);
int
key_setsecret(const char *secretkey)
{
keystatus status;
if (!key_call((u_long) KEY_SET, (xdrproc_t)xdr_keybuf,
(void *)secretkey,
(xdrproc_t)xdr_keystatus, &status)) {
return (-1);
}
if (status != KEY_SUCCESS) {
debug("set status is nonzero");
return (-1);
}
return (0);
}
/* key_secretkey_is_set() returns 1 if the keyserver has a secret key
* stored for the caller's effective uid; it returns 0 otherwise
*
* N.B.: The KEY_NET_GET key call is undocumented. Applications shouldn't
* be using it, because it allows them to get the user's secret key.
*/
int
key_secretkey_is_set(void)
{
struct key_netstres kres;
memset((void*)&kres, 0, sizeof (kres));
if (key_call((u_long) KEY_NET_GET, (xdrproc_t)xdr_void, NULL,
(xdrproc_t)xdr_key_netstres, &kres) &&
(kres.status == KEY_SUCCESS) &&
(kres.key_netstres_u.knet.st_priv_key[0] != 0)) {
/* avoid leaving secret key in memory */
memset(kres.key_netstres_u.knet.st_priv_key, 0, HEXKEYBYTES);
return (1);
}
return (0);
}
int
key_encryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
{
cryptkeyarg2 arg;
cryptkeyres res;
arg.remotename = remotename;
arg.remotekey = *remotekey;
arg.deskey = *deskey;
if (!key_call((u_long)KEY_ENCRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
(xdrproc_t)xdr_cryptkeyres, &res)) {
return (-1);
}
if (res.status != KEY_SUCCESS) {
debug("encrypt status is nonzero");
return (-1);
}
*deskey = res.cryptkeyres_u.deskey;
return (0);
}
int
key_decryptsession_pk(char *remotename, netobj *remotekey, des_block *deskey)
{
cryptkeyarg2 arg;
cryptkeyres res;
arg.remotename = remotename;
arg.remotekey = *remotekey;
arg.deskey = *deskey;
if (!key_call((u_long)KEY_DECRYPT_PK, (xdrproc_t)xdr_cryptkeyarg2, &arg,
(xdrproc_t)xdr_cryptkeyres, &res)) {
return (-1);
}
if (res.status != KEY_SUCCESS) {
debug("decrypt status is nonzero");
return (-1);
}
*deskey = res.cryptkeyres_u.deskey;
return (0);
}
int
key_encryptsession(const char *remotename, des_block *deskey)
{
cryptkeyarg arg;
cryptkeyres res;
arg.remotename = (char *) remotename;
arg.deskey = *deskey;
if (!key_call((u_long)KEY_ENCRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
(xdrproc_t)xdr_cryptkeyres, &res)) {
return (-1);
}
if (res.status != KEY_SUCCESS) {
debug("encrypt status is nonzero");
return (-1);
}
*deskey = res.cryptkeyres_u.deskey;
return (0);
}
int
key_decryptsession(const char *remotename, des_block *deskey)
{
cryptkeyarg arg;
cryptkeyres res;
arg.remotename = (char *) remotename;
arg.deskey = *deskey;
if (!key_call((u_long)KEY_DECRYPT, (xdrproc_t)xdr_cryptkeyarg, &arg,
(xdrproc_t)xdr_cryptkeyres, &res)) {
return (-1);
}
if (res.status != KEY_SUCCESS) {
debug("decrypt status is nonzero");
return (-1);
}
*deskey = res.cryptkeyres_u.deskey;
return (0);
}
int
key_gendes(des_block *key)
{
if (!key_call((u_long)KEY_GEN, (xdrproc_t)xdr_void, NULL,
(xdrproc_t)xdr_des_block, key)) {
return (-1);
}
return (0);
}
int
key_setnet(struct key_netstarg *arg)
{
keystatus status;
if (!key_call((u_long) KEY_NET_PUT, (xdrproc_t)xdr_key_netstarg, arg,
(xdrproc_t)xdr_keystatus, &status)){
return (-1);
}
if (status != KEY_SUCCESS) {
debug("key_setnet status is nonzero");
return (-1);
}
return (1);
}
int
key_get_conv(char *pkey, des_block *deskey)
{
cryptkeyres res;
if (!key_call((u_long) KEY_GET_CONV, (xdrproc_t)xdr_keybuf, pkey,
(xdrproc_t)xdr_cryptkeyres, &res)) {
return (-1);
}
if (res.status != KEY_SUCCESS) {
debug("get_conv status is nonzero");
return (-1);
}
*deskey = res.cryptkeyres_u.deskey;
return (0);
}
struct key_call_private {
CLIENT *client; /* Client handle */
pid_t pid; /* process-id at moment of creation */
uid_t uid; /* user-id at last authorization */
};
static struct key_call_private *key_call_private_main = NULL;
static thread_key_t key_call_key;
static once_t key_call_once = ONCE_INITIALIZER;
static int key_call_key_error;
static void
key_call_destroy(void *vp)
{
struct key_call_private *kcp = (struct key_call_private *)vp;
if (kcp) {
if (kcp->client)
clnt_destroy(kcp->client);
free(kcp);
}
}
static void
key_call_init(void)
{
key_call_key_error = thr_keycreate(&key_call_key, key_call_destroy);
}
/*
* Keep the handle cached. This call may be made quite often.
*/
static CLIENT *
getkeyserv_handle(int vers)
{
void *localhandle;
struct netconfig *nconf;
struct netconfig *tpconf;
struct key_call_private *kcp;
struct timeval wait_time;
struct utsname u;
int main_thread;
int fd;
#define TOTAL_TIMEOUT 30 /* total timeout talking to keyserver */
#define TOTAL_TRIES 5 /* Number of tries */
if ((main_thread = thr_main())) {
kcp = key_call_private_main;
} else {
if (thr_once(&key_call_once, key_call_init) != 0 ||
key_call_key_error != 0)
return ((CLIENT *) NULL);
kcp = (struct key_call_private *)thr_getspecific(key_call_key);
}
if (kcp == (struct key_call_private *)NULL) {
kcp = (struct key_call_private *)malloc(sizeof (*kcp));
if (kcp == (struct key_call_private *)NULL) {
return ((CLIENT *) NULL);
}
if (main_thread)
key_call_private_main = kcp;
else
thr_setspecific(key_call_key, (void *) kcp);
kcp->client = NULL;
}
/* if pid has changed, destroy client and rebuild */
if (kcp->client != NULL && kcp->pid != getpid()) {
clnt_destroy(kcp->client);
kcp->client = NULL;
}
if (kcp->client != NULL) {
/* if uid has changed, build client handle again */
if (kcp->uid != geteuid()) {
kcp->uid = geteuid();
auth_destroy(kcp->client->cl_auth);
kcp->client->cl_auth =
authsys_create("", kcp->uid, 0, 0, NULL);
if (kcp->client->cl_auth == NULL) {
clnt_destroy(kcp->client);
kcp->client = NULL;
return ((CLIENT *) NULL);
}
}
/* Change the version number to the new one */
clnt_control(kcp->client, CLSET_VERS, (void *)&vers);
return (kcp->client);
}
if (!(localhandle = setnetconfig())) {
return ((CLIENT *) NULL);
}
tpconf = NULL;
#if defined(__FreeBSD__)
if (uname(&u) == -1)
#else
#if defined(i386)
if (_nuname(&u) == -1)
#elif defined(sparc)
if (_uname(&u) == -1)
#else
#error Unknown architecture!
#endif
#endif
{
endnetconfig(localhandle);
return ((CLIENT *) NULL);
}
while ((nconf = getnetconfig(localhandle)) != NULL) {
if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
/*
* We use COTS_ORD here so that the caller can
* find out immediately if the server is dead.
*/
if (nconf->nc_semantics == NC_TPI_COTS_ORD) {
kcp->client = clnt_tp_create(u.nodename,
KEY_PROG, vers, nconf);
if (kcp->client)
break;
} else {
tpconf = nconf;
}
}
}
if ((kcp->client == (CLIENT *) NULL) && (tpconf))
/* Now, try the CLTS or COTS loopback transport */
kcp->client = clnt_tp_create(u.nodename,
KEY_PROG, vers, tpconf);
endnetconfig(localhandle);
if (kcp->client == (CLIENT *) NULL) {
return ((CLIENT *) NULL);
}
kcp->uid = geteuid();
kcp->pid = getpid();
kcp->client->cl_auth = authsys_create("", kcp->uid, 0, 0, NULL);
if (kcp->client->cl_auth == NULL) {
clnt_destroy(kcp->client);
kcp->client = NULL;
return ((CLIENT *) NULL);
}
wait_time.tv_sec = TOTAL_TIMEOUT/TOTAL_TRIES;
wait_time.tv_usec = 0;
(void) clnt_control(kcp->client, CLSET_RETRY_TIMEOUT,
(char *)&wait_time);
if (clnt_control(kcp->client, CLGET_FD, (char *)&fd))
_fcntl(fd, F_SETFD, 1); /* make it "close on exec" */
return (kcp->client);
}
/* returns 0 on failure, 1 on success */
static int
key_call(u_long proc, xdrproc_t xdr_arg, void *arg, xdrproc_t xdr_rslt,
void *rslt)
{
CLIENT *clnt;
struct timeval wait_time;
if (proc == KEY_ENCRYPT_PK && __key_encryptsession_pk_LOCAL) {
cryptkeyres *res;
res = (*__key_encryptsession_pk_LOCAL)(geteuid(), arg);
*(cryptkeyres*)rslt = *res;
return (1);
} else if (proc == KEY_DECRYPT_PK && __key_decryptsession_pk_LOCAL) {
cryptkeyres *res;
res = (*__key_decryptsession_pk_LOCAL)(geteuid(), arg);
*(cryptkeyres*)rslt = *res;
return (1);
} else if (proc == KEY_GEN && __key_gendes_LOCAL) {
des_block *res;
res = (*__key_gendes_LOCAL)(geteuid(), 0);
*(des_block*)rslt = *res;
return (1);
}
if ((proc == KEY_ENCRYPT_PK) || (proc == KEY_DECRYPT_PK) ||
(proc == KEY_NET_GET) || (proc == KEY_NET_PUT) ||
(proc == KEY_GET_CONV))
clnt = getkeyserv_handle(2); /* talk to version 2 */
else
clnt = getkeyserv_handle(1); /* talk to version 1 */
if (clnt == NULL) {
return (0);
}
wait_time.tv_sec = TOTAL_TIMEOUT;
wait_time.tv_usec = 0;
if (clnt_call(clnt, proc, xdr_arg, arg, xdr_rslt, rslt,
wait_time) == RPC_SUCCESS) {
return (1);
} else {
return (0);
}
}
diff --git a/lib/libc/rpc/key_prot_xdr.c b/lib/libc/rpc/key_prot_xdr.c
index b98d1c432e3f..0d65e35faabc 100644
--- a/lib/libc/rpc/key_prot_xdr.c
+++ b/lib/libc/rpc/key_prot_xdr.c
@@ -1,177 +1,176 @@
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#include "namespace.h"
#include <rpc/key_prot.h>
#include "un-namespace.h"
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* Copyright (c) 1990, 1991 Sun Microsystems, Inc. */
/* #pragma ident "@(#)key_prot.x 1.7 94/04/29 SMI" */
-#include <sys/cdefs.h>
/*
* Compiled from key_prot.x using rpcgen.
* DO NOT EDIT THIS FILE!
* This is NOT source code!
*/
bool_t
xdr_keystatus(register XDR *xdrs, keystatus *objp)
{
if (!xdr_enum(xdrs, (enum_t *)objp))
return (FALSE);
return (TRUE);
}
bool_t
xdr_keybuf(register XDR *xdrs, keybuf objp)
{
if (!xdr_opaque(xdrs, objp, HEXKEYBYTES))
return (FALSE);
return (TRUE);
}
bool_t
xdr_netnamestr(register XDR *xdrs, netnamestr *objp)
{
if (!xdr_string(xdrs, objp, MAXNETNAMELEN))
return (FALSE);
return (TRUE);
}
bool_t
xdr_cryptkeyarg(register XDR *xdrs, cryptkeyarg *objp)
{
if (!xdr_netnamestr(xdrs, &objp->remotename))
return (FALSE);
if (!xdr_des_block(xdrs, &objp->deskey))
return (FALSE);
return (TRUE);
}
bool_t
xdr_cryptkeyarg2(register XDR *xdrs, cryptkeyarg2 *objp)
{
if (!xdr_netnamestr(xdrs, &objp->remotename))
return (FALSE);
if (!xdr_netobj(xdrs, &objp->remotekey))
return (FALSE);
if (!xdr_des_block(xdrs, &objp->deskey))
return (FALSE);
return (TRUE);
}
bool_t
xdr_cryptkeyres(register XDR *xdrs, cryptkeyres *objp)
{
if (!xdr_keystatus(xdrs, &objp->status))
return (FALSE);
switch (objp->status) {
case KEY_SUCCESS:
if (!xdr_des_block(xdrs, &objp->cryptkeyres_u.deskey))
return (FALSE);
break;
default:
break;
}
return (TRUE);
}
bool_t
xdr_unixcred(register XDR *xdrs, unixcred *objp)
{
u_int **pgids_val;
if (!xdr_u_int(xdrs, &objp->uid))
return (FALSE);
if (!xdr_u_int(xdrs, &objp->gid))
return (FALSE);
pgids_val = &objp->gids.gids_val;
if (!xdr_array(xdrs, (char **) pgids_val, (u_int *) &objp->gids.gids_len, MAXGIDS,
sizeof (u_int), (xdrproc_t) xdr_u_int))
return (FALSE);
return (TRUE);
}
bool_t
xdr_getcredres(register XDR *xdrs, getcredres *objp)
{
if (!xdr_keystatus(xdrs, &objp->status))
return (FALSE);
switch (objp->status) {
case KEY_SUCCESS:
if (!xdr_unixcred(xdrs, &objp->getcredres_u.cred))
return (FALSE);
break;
default:
break;
}
return (TRUE);
}
bool_t
xdr_key_netstarg(register XDR *xdrs, key_netstarg *objp)
{
if (!xdr_keybuf(xdrs, objp->st_priv_key))
return (FALSE);
if (!xdr_keybuf(xdrs, objp->st_pub_key))
return (FALSE);
if (!xdr_netnamestr(xdrs, &objp->st_netname))
return (FALSE);
return (TRUE);
}
bool_t
xdr_key_netstres(register XDR *xdrs, key_netstres *objp)
{
if (!xdr_keystatus(xdrs, &objp->status))
return (FALSE);
switch (objp->status) {
case KEY_SUCCESS:
if (!xdr_key_netstarg(xdrs, &objp->key_netstres_u.knet))
return (FALSE);
break;
default:
break;
}
return (TRUE);
}
diff --git a/lib/libc/rpc/mt_misc.c b/lib/libc/rpc/mt_misc.c
index 93c242953d1b..9c420ac0877f 100644
--- a/lib/libc/rpc/mt_misc.c
+++ b/lib/libc/rpc/mt_misc.c
@@ -1,114 +1,113 @@
/* $NetBSD: mt_misc.c,v 1.1 2000/06/02 23:11:11 fvdl Exp $ */
/* #pragma ident "@(#)mt_misc.c 1.24 93/04/29 SMI" */
-#include <sys/cdefs.h>
#include "namespace.h"
#include "reentrant.h"
#include <rpc/rpc.h>
#include <sys/time.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#include "mt_misc.h"
/* Take these objects out of the application namespace. */
#define svc_lock __svc_lock
#define svc_fd_lock __svc_fd_lock
#define rpcbaddr_cache_lock __rpcbaddr_cache_lock
#define authdes_ops_lock __authdes_ops_lock
#define authnone_lock __authnone_lock
#define authsvc_lock __authsvc_lock
#define clnt_fd_lock __clnt_fd_lock
#define clntraw_lock __clntraw_lock
#define dupreq_lock __dupreq_lock
#define loopnconf_lock __loopnconf_lock
#define ops_lock __ops_lock
#define proglst_lock __proglst_lock
#define rpcsoc_lock __rpcsoc_lock
#define svcraw_lock __svcraw_lock
#define xprtlist_lock __xprtlist_lock
/* protects the services list (svc.c) */
pthread_rwlock_t svc_lock = PTHREAD_RWLOCK_INITIALIZER;
/* protects svc_fdset and the xports[] array */
pthread_rwlock_t svc_fd_lock = PTHREAD_RWLOCK_INITIALIZER;
/* protects the RPCBIND address cache */
pthread_rwlock_t rpcbaddr_cache_lock = PTHREAD_RWLOCK_INITIALIZER;
/* serializes authdes ops initializations */
pthread_mutex_t authdes_ops_lock = PTHREAD_MUTEX_INITIALIZER;
/* protects des stats list */
pthread_mutex_t svcauthdesstats_lock = PTHREAD_MUTEX_INITIALIZER;
/* auth_none.c serialization */
pthread_mutex_t authnone_lock = PTHREAD_MUTEX_INITIALIZER;
/* protects the Auths list (svc_auth.c) */
pthread_mutex_t authsvc_lock = PTHREAD_MUTEX_INITIALIZER;
/* protects client-side fd lock array */
pthread_mutex_t clnt_fd_lock = PTHREAD_MUTEX_INITIALIZER;
/* clnt_raw.c serialization */
pthread_mutex_t clntraw_lock = PTHREAD_MUTEX_INITIALIZER;
/* dupreq variables (svc_dg.c) */
pthread_mutex_t dupreq_lock = PTHREAD_MUTEX_INITIALIZER;
/* loopnconf (rpcb_clnt.c) */
pthread_mutex_t loopnconf_lock = PTHREAD_MUTEX_INITIALIZER;
/* serializes ops initializations */
pthread_mutex_t ops_lock = PTHREAD_MUTEX_INITIALIZER;
/* protects proglst list (svc_simple.c) */
pthread_mutex_t proglst_lock = PTHREAD_MUTEX_INITIALIZER;
/* serializes clnt_com_create() (rpc_soc.c) */
pthread_mutex_t rpcsoc_lock = PTHREAD_MUTEX_INITIALIZER;
/* svc_raw.c serialization */
pthread_mutex_t svcraw_lock = PTHREAD_MUTEX_INITIALIZER;
/* xprtlist (svc_generic.c) */
pthread_mutex_t xprtlist_lock = PTHREAD_MUTEX_INITIALIZER;
#undef rpc_createerr
struct rpc_createerr rpc_createerr;
static thread_key_t rce_key;
static once_t rce_once = ONCE_INITIALIZER;
static int rce_key_error;
static void
rce_key_init(void)
{
rce_key_error = thr_keycreate(&rce_key, free);
}
struct rpc_createerr *
__rpc_createerr(void)
{
struct rpc_createerr *rce_addr = NULL;
if (thr_main())
return (&rpc_createerr);
if (thr_once(&rce_once, rce_key_init) != 0 || rce_key_error != 0)
return (&rpc_createerr);
rce_addr = (struct rpc_createerr *)thr_getspecific(rce_key);
if (!rce_addr) {
rce_addr = (struct rpc_createerr *)
malloc(sizeof (struct rpc_createerr));
if (thr_setspecific(rce_key, (void *) rce_addr) != 0) {
free(rce_addr);
return (&rpc_createerr);
}
memset(rce_addr, 0, sizeof (struct rpc_createerr));
return (rce_addr);
}
return (rce_addr);
}
diff --git a/lib/libc/rpc/netname.c b/lib/libc/rpc/netname.c
index bfb925f25335..849653816666 100644
--- a/lib/libc/rpc/netname.c
+++ b/lib/libc/rpc/netname.c
@@ -1,141 +1,140 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)netname.c 1.8 91/03/11 Copyr 1986 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* netname utility routines
* convert from unix names to network names and vice-versa
* This module is operating system dependent!
* What we define here will work with any unix system that has adopted
* the sun NIS domain architecture.
*/
#include "namespace.h"
#include <sys/param.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#ifdef YP
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#ifndef MAXHOSTNAMELEN
#define MAXHOSTNAMELEN 256
#endif
#define TYPE_BIT(type) (sizeof (type) * CHAR_BIT)
#define TYPE_SIGNED(type) (((type) -1) < 0)
/*
** 302 / 1000 is log10(2.0) rounded up.
** Subtract one for the sign bit if the type is signed;
** add one for integer division truncation;
** add one more for a minus sign if the type is signed.
*/
#define INT_STRLEN_MAXIMUM(type) \
((TYPE_BIT(type) - TYPE_SIGNED(type)) * 302 / 1000 + 1 + TYPE_SIGNED(type))
static char *OPSYS = "unix";
/*
* Figure out my fully qualified network name
*/
int
getnetname(char name[MAXNETNAMELEN+1])
{
uid_t uid;
uid = geteuid();
if (uid == 0) {
return (host2netname(name, (char *) NULL, (char *) NULL));
} else {
return (user2netname(name, uid, (char *) NULL));
}
}
/*
* Convert unix cred to network-name
*/
int
user2netname(char netname[MAXNETNAMELEN + 1], const uid_t uid, const char *domain)
{
char *dfltdom;
if (domain == NULL) {
if (__rpc_get_default_domain(&dfltdom) != 0) {
return (0);
}
domain = dfltdom;
}
if (strlen(domain) + 1 + INT_STRLEN_MAXIMUM(u_long) + 1 + strlen(OPSYS) > MAXNETNAMELEN) {
return (0);
}
(void) sprintf(netname, "%s.%ld@%s", OPSYS, (u_long)uid, domain);
return (1);
}
/*
* Convert host to network-name
*/
int
host2netname(char netname[MAXNETNAMELEN + 1], const char *host, const char *domain)
{
char *dfltdom;
char hostname[MAXHOSTNAMELEN+1];
if (domain == NULL) {
if (__rpc_get_default_domain(&dfltdom) != 0) {
return (0);
}
domain = dfltdom;
}
if (host == NULL) {
(void) gethostname(hostname, sizeof(hostname));
host = hostname;
}
if (strlen(domain) + 1 + strlen(host) + 1 + strlen(OPSYS) > MAXNETNAMELEN) {
return (0);
}
(void) sprintf(netname, "%s.%s@%s", OPSYS, host, domain);
return (1);
}
diff --git a/lib/libc/rpc/netnamer.c b/lib/libc/rpc/netnamer.c
index 94b386bcdf63..5a62e8008e42 100644
--- a/lib/libc/rpc/netnamer.c
+++ b/lib/libc/rpc/netnamer.c
@@ -1,323 +1,322 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)netnamer.c 1.13 91/03/11 Copyr 1986 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* netname utility routines convert from unix names to network names and
* vice-versa This module is operating system dependent! What we define here
* will work with any unix system that has adopted the sun NIS domain
* architecture.
*/
#include "namespace.h"
#include <sys/param.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#ifdef YP
#include <rpcsvc/yp_prot.h>
#include <rpcsvc/ypclnt.h>
#endif
#include <ctype.h>
#include <stdio.h>
#include <grp.h>
#include <pwd.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include "un-namespace.h"
static char *OPSYS = "unix";
#ifdef YP
static char *NETID = "netid.byname";
#endif
static char *NETIDFILE = "/etc/netid";
static int getnetid( char *, char * );
static int _getgroups( char *, gid_t [NGRPS] );
/*
* Convert network-name into unix credential
*/
int
netname2user(char netname[MAXNETNAMELEN + 1], uid_t *uidp, gid_t *gidp,
int *gidlenp, gid_t *gidlist)
{
char *p;
int gidlen;
uid_t uid;
long luid;
struct passwd *pwd;
char val[1024];
char *val1, *val2;
char *domain;
int vallen;
int err;
if (getnetid(netname, val)) {
char *res = val;
p = strsep(&res, ":");
if (p == NULL)
return (0);
*uidp = (uid_t) atol(p);
p = strsep(&res, "\n,");
if (p == NULL) {
return (0);
}
*gidp = (gid_t) atol(p);
for (gidlen = 0; gidlen < NGRPS; gidlen++) {
p = strsep(&res, "\n,");
if (p == NULL)
break;
gidlist[gidlen] = (gid_t) atol(p);
}
*gidlenp = gidlen;
return (1);
}
val1 = strchr(netname, '.');
if (val1 == NULL)
return (0);
if (strncmp(netname, OPSYS, (val1-netname)))
return (0);
val1++;
val2 = strchr(val1, '@');
if (val2 == NULL)
return (0);
vallen = val2 - val1;
if (vallen > (1024 - 1))
vallen = 1024 - 1;
(void) strncpy(val, val1, 1024);
val[vallen] = 0;
err = __rpc_get_default_domain(&domain); /* change to rpc */
if (err)
return (0);
if (strcmp(val2 + 1, domain))
return (0); /* wrong domain */
if (sscanf(val, "%ld", &luid) != 1)
return (0);
uid = luid;
/* use initgroups method */
pwd = getpwuid(uid);
if (pwd == NULL)
return (0);
*uidp = pwd->pw_uid;
*gidp = pwd->pw_gid;
*gidlenp = _getgroups(pwd->pw_name, gidlist);
return (1);
}
/*
* initgroups
*/
static int
_getgroups(char *uname, gid_t groups[NGRPS])
{
gid_t ngroups = 0;
struct group *grp;
int i;
int j;
int filter;
setgrent();
while ((grp = getgrent())) {
for (i = 0; grp->gr_mem[i]; i++)
if (!strcmp(grp->gr_mem[i], uname)) {
if (ngroups == NGRPS) {
#ifdef DEBUG
fprintf(stderr,
"initgroups: %s is in too many groups\n", uname);
#endif
goto toomany;
}
/* filter out duplicate group entries */
filter = 0;
for (j = 0; j < ngroups; j++)
if (groups[j] == grp->gr_gid) {
filter++;
break;
}
if (!filter)
groups[ngroups++] = grp->gr_gid;
}
}
toomany:
endgrent();
return (ngroups);
}
/*
* Convert network-name to hostname
*/
int
netname2host(char netname[MAXNETNAMELEN + 1], char *hostname, int hostlen)
{
int err;
char valbuf[1024];
char *val;
char *val2;
int vallen;
char *domain;
if (getnetid(netname, valbuf)) {
val = valbuf;
if ((*val == '0') && (val[1] == ':')) {
(void) strncpy(hostname, val + 2, hostlen);
return (1);
}
}
val = strchr(netname, '.');
if (val == NULL)
return (0);
if (strncmp(netname, OPSYS, (val - netname)))
return (0);
val++;
val2 = strchr(val, '@');
if (val2 == NULL)
return (0);
vallen = val2 - val;
if (vallen > (hostlen - 1))
vallen = hostlen - 1;
(void) strncpy(hostname, val, vallen);
hostname[vallen] = 0;
err = __rpc_get_default_domain(&domain); /* change to rpc */
if (err)
return (0);
if (strcmp(val2 + 1, domain))
return (0); /* wrong domain */
else
return (1);
}
/*
* reads the file /etc/netid looking for a + to optionally go to the
* network information service.
*/
int
getnetid(char *key, char *ret)
{
char buf[1024]; /* big enough */
char *res;
char *mkey;
char *mval;
FILE *fd;
#ifdef YP
char *domain;
int err;
char *lookup;
int len;
#endif
int rv;
rv = 0;
fd = fopen(NETIDFILE, "r");
if (fd == NULL) {
#ifdef YP
res = "+";
goto getnetidyp;
#else
return (0);
#endif
}
while (fd != NULL) {
res = fgets(buf, sizeof(buf), fd);
if (res == NULL) {
rv = 0;
goto done;
}
if (res[0] == '#')
continue;
else if (res[0] == '+') {
#ifdef YP
getnetidyp:
err = yp_get_default_domain(&domain);
if (err) {
continue;
}
lookup = NULL;
err = yp_match(domain, NETID, key,
strlen(key), &lookup, &len);
if (err) {
#ifdef DEBUG
fprintf(stderr, "match failed error %d\n", err);
#endif
continue;
}
lookup[len] = 0;
strcpy(ret, lookup);
free(lookup);
rv = 2;
goto done;
#else /* YP */
#ifdef DEBUG
fprintf(stderr,
"Bad record in %s '+' -- NIS not supported in this library copy\n",
NETIDFILE);
#endif
continue;
#endif /* YP */
} else {
mkey = strsep(&res, "\t ");
if (mkey == NULL) {
fprintf(stderr,
"Bad record in %s -- %s", NETIDFILE, buf);
continue;
}
do {
mval = strsep(&res, " \t#\n");
} while (mval != NULL && !*mval);
if (mval == NULL) {
fprintf(stderr,
"Bad record in %s val problem - %s", NETIDFILE, buf);
continue;
}
if (strcmp(mkey, key) == 0) {
strcpy(ret, mval);
rv = 1;
goto done;
}
}
}
done:
if (fd != NULL)
fclose(fd);
return (rv);
}
diff --git a/lib/libc/rpc/pmap_clnt.c b/lib/libc/rpc/pmap_clnt.c
index 4e33ed21bd2d..9abce6087283 100644
--- a/lib/libc/rpc/pmap_clnt.c
+++ b/lib/libc/rpc/pmap_clnt.c
@@ -1,119 +1,118 @@
/* $NetBSD: pmap_clnt.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)pmap_clnt.c 1.37 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)pmap_clnt.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* pmap_clnt.c
* Client interface to pmap rpc service.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <rpc/nettype.h>
#include <netinet/in.h>
#include "un-namespace.h"
#include <stdio.h>
#include <stdlib.h>
#include "rpc_com.h"
bool_t
pmap_set(u_long program, u_long version, int protocol, int port)
{
bool_t rslt;
struct netbuf *na;
struct netconfig *nconf;
char buf[32];
if ((protocol != IPPROTO_UDP) && (protocol != IPPROTO_TCP)) {
return (FALSE);
}
nconf = __rpc_getconfip(protocol == IPPROTO_UDP ? "udp" : "tcp");
if (nconf == NULL) {
return (FALSE);
}
snprintf(buf, sizeof buf, "0.0.0.0.%d.%d",
(((u_int32_t)port) >> 8) & 0xff, port & 0xff);
na = uaddr2taddr(nconf, buf);
if (na == NULL) {
freenetconfigent(nconf);
return (FALSE);
}
rslt = rpcb_set((rpcprog_t)program, (rpcvers_t)version, nconf, na);
free(na);
freenetconfigent(nconf);
return (rslt);
}
/*
* Remove the mapping between program, version and port.
* Calls the pmap service remotely to do the un-mapping.
*/
bool_t
pmap_unset(u_long program, u_long version)
{
struct netconfig *nconf;
bool_t udp_rslt = FALSE;
bool_t tcp_rslt = FALSE;
nconf = __rpc_getconfip("udp");
if (nconf != NULL) {
udp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version,
nconf);
freenetconfigent(nconf);
}
nconf = __rpc_getconfip("tcp");
if (nconf != NULL) {
tcp_rslt = rpcb_unset((rpcprog_t)program, (rpcvers_t)version,
nconf);
freenetconfigent(nconf);
}
/*
* XXX: The call may still succeed even if only one of the
* calls succeeded. This was the best that could be
* done for backward compatibility.
*/
return (tcp_rslt || udp_rslt);
}
diff --git a/lib/libc/rpc/pmap_getmaps.c b/lib/libc/rpc/pmap_getmaps.c
index 3ecd51044797..c8bbc63d9af6 100644
--- a/lib/libc/rpc/pmap_getmaps.c
+++ b/lib/libc/rpc/pmap_getmaps.c
@@ -1,98 +1,97 @@
/* $NetBSD: pmap_getmaps.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)pmap_getmaps.c 1.10 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)pmap_getmaps.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* pmap_getmap.c
* Client interface to pmap rpc service.
* contains pmap_getmaps, which is only tcp service involved
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include "un-namespace.h"
#define NAMELEN 255
#define MAX_BROADCAST_SIZE 1400
/*
* Get a copy of the current port maps.
* Calls the pmap service remotely to do get the maps.
*/
struct pmaplist *
pmap_getmaps(struct sockaddr_in *address)
{
struct pmaplist *head = NULL;
int sock = -1;
struct timeval minutetimeout;
CLIENT *client;
assert(address != NULL);
minutetimeout.tv_sec = 60;
minutetimeout.tv_usec = 0;
address->sin_port = htons(PMAPPORT);
client = clnttcp_create(address, PMAPPROG,
PMAPVERS, &sock, 50, 500);
if (client != NULL) {
if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_DUMP,
(xdrproc_t)xdr_void, NULL,
(xdrproc_t)xdr_pmaplist, &head, minutetimeout) !=
RPC_SUCCESS) {
clnt_perror(client, "pmap_getmaps rpc problem");
}
CLNT_DESTROY(client);
}
address->sin_port = 0;
return (head);
}
diff --git a/lib/libc/rpc/pmap_getport.c b/lib/libc/rpc/pmap_getport.c
index 9610f7625001..9124bb2521c0 100644
--- a/lib/libc/rpc/pmap_getport.c
+++ b/lib/libc/rpc/pmap_getport.c
@@ -1,100 +1,99 @@
/* $NetBSD: pmap_getport.c,v 1.16 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "from: @(#)pmap_getport.c 1.9 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "from: @(#)pmap_getport.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* pmap_getport.c
* Client interface to pmap rpc service.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <assert.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include "un-namespace.h"
static const struct timeval timeout = { 5, 0 };
static const struct timeval tottimeout = { 60, 0 };
/*
* Find the mapped port for program,version.
* Calls the pmap service remotely to do the lookup.
* Returns 0 if no map exists.
*/
u_short
pmap_getport(struct sockaddr_in *address, u_long program, u_long version,
u_int protocol)
{
u_short port = 0;
int sock = -1;
CLIENT *client;
struct pmap parms;
assert(address != NULL);
address->sin_port = htons(PMAPPORT);
client = clntudp_bufcreate(address, PMAPPROG,
PMAPVERS, timeout, &sock, RPCSMALLMSGSIZE, RPCSMALLMSGSIZE);
if (client != NULL) {
parms.pm_prog = program;
parms.pm_vers = version;
parms.pm_prot = protocol;
parms.pm_port = 0; /* not needed or used */
if (CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
(xdrproc_t)xdr_pmap,
&parms, (xdrproc_t)xdr_u_short, &port, tottimeout) !=
RPC_SUCCESS){
rpc_createerr.cf_stat = RPC_PMAPFAILURE;
clnt_geterr(client, &rpc_createerr.cf_error);
} else if (port == 0) {
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
}
CLNT_DESTROY(client);
}
address->sin_port = 0;
return (port);
}
diff --git a/lib/libc/rpc/pmap_prot.c b/lib/libc/rpc/pmap_prot.c
index 596b3699ba86..ed75e9533576 100644
--- a/lib/libc/rpc/pmap_prot.c
+++ b/lib/libc/rpc/pmap_prot.c
@@ -1,66 +1,65 @@
/* $NetBSD: pmap_prot.c,v 1.10 2000/01/22 22:19:18 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)pmap_prot.c 1.17 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)pmap_prot.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* pmap_prot.c
* Protocol for the local binder service, or pmap.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <assert.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/pmap_prot.h>
#include "un-namespace.h"
bool_t
xdr_pmap(XDR *xdrs, struct pmap *regs)
{
assert(xdrs != NULL);
assert(regs != NULL);
if (xdr_u_long(xdrs, &regs->pm_prog) &&
xdr_u_long(xdrs, &regs->pm_vers) &&
xdr_u_long(xdrs, &regs->pm_prot))
return (xdr_u_long(xdrs, &regs->pm_port));
return (FALSE);
}
diff --git a/lib/libc/rpc/pmap_prot2.c b/lib/libc/rpc/pmap_prot2.c
index 20614c44987d..5615e889547c 100644
--- a/lib/libc/rpc/pmap_prot2.c
+++ b/lib/libc/rpc/pmap_prot2.c
@@ -1,138 +1,137 @@
/* $NetBSD: pmap_prot2.c,v 1.14 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)pmap_prot2.c 1.3 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)pmap_prot2.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* pmap_prot2.c
* Protocol for the local binder service, or pmap.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <assert.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/pmap_prot.h>
#include "un-namespace.h"
/*
* What is going on with linked lists? (!)
* First recall the link list declaration from pmap_prot.h:
*
* struct pmaplist {
* struct pmap pml_map;
* struct pmaplist *pml_map;
* };
*
* Compare that declaration with a corresponding xdr declaration that
* is (a) pointer-less, and (b) recursive:
*
* typedef union switch (bool_t) {
*
* case TRUE: struct {
* struct pmap;
* pmaplist_t foo;
* };
*
* case FALSE: struct {};
* } pmaplist_t;
*
* Notice that the xdr declaration has no nxt pointer while
* the C declaration has no bool_t variable. The bool_t can be
* interpreted as ``more data follows me''; if FALSE then nothing
* follows this bool_t; if TRUE then the bool_t is followed by
* an actual struct pmap, and then (recursively) by the
* xdr union, pamplist_t.
*
* This could be implemented via the xdr_union primitive, though this
* would cause a one recursive call per element in the list. Rather than do
* that we can ``unwind'' the recursion
* into a while loop and do the union arms in-place.
*
* The head of the list is what the C programmer wishes to past around
* the net, yet is the data that the pointer points to which is interesting;
* this sounds like a job for xdr_reference!
*/
bool_t
xdr_pmaplist(XDR *xdrs, struct pmaplist **rp)
{
/*
* more_elements is pre-computed in case the direction is
* XDR_ENCODE or XDR_FREE. more_elements is overwritten by
* xdr_bool when the direction is XDR_DECODE.
*/
bool_t more_elements;
int freeing;
struct pmaplist **next = NULL; /* pacify gcc */
assert(xdrs != NULL);
assert(rp != NULL);
freeing = (xdrs->x_op == XDR_FREE);
for (;;) {
more_elements = (bool_t)(*rp != NULL);
if (! xdr_bool(xdrs, &more_elements))
return (FALSE);
if (! more_elements)
return (TRUE); /* we are done */
/*
* the unfortunate side effect of non-recursion is that in
* the case of freeing we must remember the next object
* before we free the current object ...
*/
if (freeing)
next = &((*rp)->pml_next);
if (! xdr_reference(xdrs, (caddr_t *)rp,
(u_int)sizeof(struct pmaplist), (xdrproc_t)xdr_pmap))
return (FALSE);
rp = (freeing) ? next : &((*rp)->pml_next);
}
}
/*
* xdr_pmaplist_ptr() is specified to take a PMAPLIST *, but is identical in
* functionality to xdr_pmaplist().
*/
bool_t
xdr_pmaplist_ptr(XDR *xdrs, struct pmaplist *rp)
{
return xdr_pmaplist(xdrs, (struct pmaplist **)(void *)rp);
}
diff --git a/lib/libc/rpc/pmap_rmt.c b/lib/libc/rpc/pmap_rmt.c
index ae5e2483c351..43a7831f2aa9 100644
--- a/lib/libc/rpc/pmap_rmt.c
+++ b/lib/libc/rpc/pmap_rmt.c
@@ -1,166 +1,165 @@
/* $NetBSD: pmap_rmt.c,v 1.29 2000/07/06 03:10:34 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)pmap_rmt.c 1.21 87/08/27 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)pmap_rmt.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* pmap_rmt.c
* Client interface to pmap rpc service.
* remote call and broadcast service
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/pmap_prot.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_rmt.h>
#include "un-namespace.h"
static const struct timeval timeout = { 3, 0 };
/*
* pmapper remote-call-service interface.
* This routine is used to call the pmapper remote call service
* which will look up a service program in the port maps, and then
* remotely call that routine with the given parameters. This allows
* programs to do a lookup and call in one step.
*/
enum clnt_stat
pmap_rmtcall(struct sockaddr_in *addr, u_long prog, u_long vers, u_long proc,
xdrproc_t xdrargs, caddr_t argsp, xdrproc_t xdrres, caddr_t resp,
struct timeval tout, u_long *port_ptr)
{
int sock = -1;
CLIENT *client;
struct rmtcallargs a;
struct rmtcallres r;
enum clnt_stat stat;
assert(addr != NULL);
assert(port_ptr != NULL);
addr->sin_port = htons(PMAPPORT);
client = clntudp_create(addr, PMAPPROG, PMAPVERS, timeout, &sock);
if (client != NULL) {
a.prog = prog;
a.vers = vers;
a.proc = proc;
a.args_ptr = argsp;
a.xdr_args = xdrargs;
r.port_ptr = port_ptr;
r.results_ptr = resp;
r.xdr_results = xdrres;
stat = CLNT_CALL(client, (rpcproc_t)PMAPPROC_CALLIT,
(xdrproc_t)xdr_rmtcall_args, &a, (xdrproc_t)xdr_rmtcallres,
&r, tout);
CLNT_DESTROY(client);
} else {
stat = RPC_FAILED;
}
addr->sin_port = 0;
return (stat);
}
/*
* XDR remote call arguments
* written for XDR_ENCODE direction only
*/
bool_t
xdr_rmtcall_args(XDR *xdrs, struct rmtcallargs *cap)
{
u_int lenposition, argposition, position;
assert(xdrs != NULL);
assert(cap != NULL);
if (xdr_u_long(xdrs, &(cap->prog)) &&
xdr_u_long(xdrs, &(cap->vers)) &&
xdr_u_long(xdrs, &(cap->proc))) {
lenposition = XDR_GETPOS(xdrs);
if (! xdr_u_long(xdrs, &(cap->arglen)))
return (FALSE);
argposition = XDR_GETPOS(xdrs);
if (! (*(cap->xdr_args))(xdrs, cap->args_ptr))
return (FALSE);
position = XDR_GETPOS(xdrs);
cap->arglen = (u_long)position - (u_long)argposition;
XDR_SETPOS(xdrs, lenposition);
if (! xdr_u_long(xdrs, &(cap->arglen)))
return (FALSE);
XDR_SETPOS(xdrs, position);
return (TRUE);
}
return (FALSE);
}
/*
* XDR remote call results
* written for XDR_DECODE direction only
*/
bool_t
xdr_rmtcallres(XDR *xdrs, struct rmtcallres *crp)
{
caddr_t port_ptr;
assert(xdrs != NULL);
assert(crp != NULL);
port_ptr = (caddr_t)(void *)crp->port_ptr;
if (xdr_reference(xdrs, &port_ptr, sizeof (u_long),
(xdrproc_t)xdr_u_long) && xdr_u_long(xdrs, &crp->resultslen)) {
crp->port_ptr = (u_long *)(void *)port_ptr;
return ((*(crp->xdr_results))(xdrs, crp->results_ptr));
}
return (FALSE);
}
diff --git a/lib/libc/rpc/rpc_callmsg.c b/lib/libc/rpc/rpc_callmsg.c
index d4ad098e7cea..7648a82f5ec6 100644
--- a/lib/libc/rpc/rpc_callmsg.c
+++ b/lib/libc/rpc/rpc_callmsg.c
@@ -1,204 +1,203 @@
/* $NetBSD: rpc_callmsg.c,v 1.16 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)rpc_callmsg.c 1.4 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)rpc_callmsg.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* rpc_callmsg.c
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
*/
#include "namespace.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/rpc.h>
#include "un-namespace.h"
/*
* XDR a call message
*/
bool_t
xdr_callmsg(XDR *xdrs, struct rpc_msg *cmsg)
{
enum msg_type *prm_direction;
int32_t *buf;
struct opaque_auth *oa;
assert(xdrs != NULL);
assert(cmsg != NULL);
if (xdrs->x_op == XDR_ENCODE) {
if (cmsg->rm_call.cb_cred.oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
if (cmsg->rm_call.cb_verf.oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT
+ RNDUP(cmsg->rm_call.cb_cred.oa_length)
+ 2 * BYTES_PER_XDR_UNIT
+ RNDUP(cmsg->rm_call.cb_verf.oa_length));
if (buf != NULL) {
IXDR_PUT_INT32(buf, cmsg->rm_xid);
IXDR_PUT_ENUM(buf, cmsg->rm_direction);
if (cmsg->rm_direction != CALL) {
return (FALSE);
}
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_rpcvers);
if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
return (FALSE);
}
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_prog);
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_vers);
IXDR_PUT_INT32(buf, cmsg->rm_call.cb_proc);
oa = &cmsg->rm_call.cb_cred;
IXDR_PUT_ENUM(buf, oa->oa_flavor);
IXDR_PUT_INT32(buf, oa->oa_length);
if (oa->oa_length) {
memmove(buf, oa->oa_base, oa->oa_length);
buf += RNDUP(oa->oa_length) / sizeof (int32_t);
}
oa = &cmsg->rm_call.cb_verf;
IXDR_PUT_ENUM(buf, oa->oa_flavor);
IXDR_PUT_INT32(buf, oa->oa_length);
if (oa->oa_length) {
memmove(buf, oa->oa_base, oa->oa_length);
/* no real need....
buf += RNDUP(oa->oa_length) / sizeof (int32_t);
*/
}
return (TRUE);
}
}
if (xdrs->x_op == XDR_DECODE) {
buf = XDR_INLINE(xdrs, 8 * BYTES_PER_XDR_UNIT);
if (buf != NULL) {
cmsg->rm_xid = IXDR_GET_U_INT32(buf);
cmsg->rm_direction = IXDR_GET_ENUM(buf, enum msg_type);
if (cmsg->rm_direction != CALL) {
return (FALSE);
}
cmsg->rm_call.cb_rpcvers = IXDR_GET_U_INT32(buf);
if (cmsg->rm_call.cb_rpcvers != RPC_MSG_VERSION) {
return (FALSE);
}
cmsg->rm_call.cb_prog = IXDR_GET_U_INT32(buf);
cmsg->rm_call.cb_vers = IXDR_GET_U_INT32(buf);
cmsg->rm_call.cb_proc = IXDR_GET_U_INT32(buf);
oa = &cmsg->rm_call.cb_cred;
oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
oa->oa_length = (u_int)IXDR_GET_U_INT32(buf);
if (oa->oa_length) {
if (oa->oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
if (oa->oa_base == NULL) {
oa->oa_base = (caddr_t)
mem_alloc(oa->oa_length);
if (oa->oa_base == NULL)
return (FALSE);
}
buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
if (buf == NULL) {
if (xdr_opaque(xdrs, oa->oa_base,
oa->oa_length) == FALSE) {
return (FALSE);
}
} else {
memmove(oa->oa_base, buf,
oa->oa_length);
/* no real need....
buf += RNDUP(oa->oa_length) /
sizeof (int32_t);
*/
}
}
oa = &cmsg->rm_call.cb_verf;
buf = XDR_INLINE(xdrs, 2 * BYTES_PER_XDR_UNIT);
if (buf == NULL) {
if (xdr_enum(xdrs, &oa->oa_flavor) == FALSE ||
xdr_u_int(xdrs, &oa->oa_length) == FALSE) {
return (FALSE);
}
} else {
oa->oa_flavor = IXDR_GET_ENUM(buf, enum_t);
oa->oa_length = (u_int)IXDR_GET_U_INT32(buf);
}
if (oa->oa_length) {
if (oa->oa_length > MAX_AUTH_BYTES) {
return (FALSE);
}
if (oa->oa_base == NULL) {
oa->oa_base = (caddr_t)
mem_alloc(oa->oa_length);
if (oa->oa_base == NULL)
return (FALSE);
}
buf = XDR_INLINE(xdrs, RNDUP(oa->oa_length));
if (buf == NULL) {
if (xdr_opaque(xdrs, oa->oa_base,
oa->oa_length) == FALSE) {
return (FALSE);
}
} else {
memmove(oa->oa_base, buf,
oa->oa_length);
/* no real need...
buf += RNDUP(oa->oa_length) /
sizeof (int32_t);
*/
}
}
return (TRUE);
}
}
prm_direction = &cmsg->rm_direction;
if (
xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) &&
xdr_enum(xdrs, (enum_t *) prm_direction) &&
(cmsg->rm_direction == CALL) &&
xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
(cmsg->rm_call.cb_rpcvers == RPC_MSG_VERSION) &&
xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog)) &&
xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_vers)) &&
xdr_rpcproc(xdrs, &(cmsg->rm_call.cb_proc)) &&
xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_cred)) )
return (xdr_opaque_auth(xdrs, &(cmsg->rm_call.cb_verf)));
return (FALSE);
}
diff --git a/lib/libc/rpc/rpc_com.h b/lib/libc/rpc/rpc_com.h
index 67e47af3f454..ce386e540f07 100644
--- a/lib/libc/rpc/rpc_com.h
+++ b/lib/libc/rpc/rpc_com.h
@@ -1,94 +1,93 @@
/* $NetBSD: rpc_com.h,v 1.3 2000/12/10 04:10:08 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986 - 1991 by Sun Microsystems, Inc.
*/
/*
* rpc_com.h, Common definitions for both the server and client side.
* All for the topmost layer of rpc
*
* In Sun's tirpc distribution, this was installed as <rpc/rpc_com.h>,
* but as it contains only non-exported interfaces, it was moved here.
*/
#ifndef _RPC_RPCCOM_H
#define _RPC_RPCCOM_H
-#include <sys/cdefs.h>
/* #pragma ident "@(#)rpc_com.h 1.11 93/07/05 SMI" */
/*
* The max size of the transport, if the size cannot be determined
* by other means.
*/
#define RPC_MAXDATASIZE 9000
#define RPC_MAXADDRSIZE 1024
#define __RPC_GETXID(now) ((u_int32_t)getpid() ^ (u_int32_t)(now)->tv_sec ^ \
(u_int32_t)(now)->tv_usec)
__BEGIN_DECLS
extern u_int __rpc_get_a_size(int);
extern int __rpc_dtbsize(void);
extern struct netconfig * __rpcgettp(int);
extern int __rpc_get_default_domain(char **);
char *__rpc_taddr2uaddr_af(int, const struct netbuf *);
struct netbuf *__rpc_uaddr2taddr_af(int, const char *);
int __rpc_fixup_addr(struct netbuf *, const struct netbuf *);
int __rpc_sockinfo2netid(struct __rpc_sockinfo *, const char **);
int __rpc_seman2socktype(int);
int __rpc_socktype2seman(int);
void *rpc_nullproc(CLIENT *);
int __rpc_sockisbound(int);
struct netbuf *__rpcb_findaddr_timed(rpcprog_t, rpcvers_t,
const struct netconfig *, const char *host, CLIENT **clpp,
struct timeval *tp);
bool_t __rpc_control(int,void *);
char *_get_next_token(char *, int);
bool_t __svc_clean_idle(fd_set *, int, bool_t);
bool_t __xdrrec_setnonblock(XDR *, int);
bool_t __xdrrec_getrec(XDR *, enum xprt_stat *, bool_t);
void __xprt_unregister_unlocked(SVCXPRT *);
extern SVCXPRT **__svc_xports;
extern int __svc_maxrec;
__END_DECLS
#endif /* _RPC_RPCCOM_H */
diff --git a/lib/libc/rpc/rpc_commondata.c b/lib/libc/rpc/rpc_commondata.c
index 7d7a537a396d..e44228c3ce58 100644
--- a/lib/libc/rpc/rpc_commondata.c
+++ b/lib/libc/rpc/rpc_commondata.c
@@ -1,47 +1,46 @@
/* $NetBSD: rpc_commondata.c,v 1.7 2000/06/02 23:11:13 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid = "@(#)rpc_commondata.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
#include "namespace.h"
#include <rpc/rpc.h>
#include "un-namespace.h"
/*
* This file should only contain common data (global data) that is exported
* by public interfaces
*/
struct opaque_auth _null_auth;
fd_set svc_fdset;
int svc_maxfd = -1;
diff --git a/lib/libc/rpc/rpc_dtablesize.c b/lib/libc/rpc/rpc_dtablesize.c
index e476914cefcd..2899690cd6de 100644
--- a/lib/libc/rpc/rpc_dtablesize.c
+++ b/lib/libc/rpc/rpc_dtablesize.c
@@ -1,66 +1,65 @@
/* $NetBSD: rpc_dtablesize.c,v 1.14 1998/11/15 17:32:43 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)rpc_dtablesize.c 1.2 87/08/11 Copyr 1987 Sun Micro";
static char *sccsid = "@(#)rpc_dtablesize.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
#include "namespace.h"
#include <unistd.h>
#include "un-namespace.h"
int _rpc_dtablesize(void); /* XXX */
/*
* Cache the result of getdtablesize(), so we don't have to do an
* expensive system call every time.
*/
/*
* XXX In FreeBSD 2.x, you can have the maximum number of open file
* descriptors be greater than FD_SETSIZE (which us 256 by default).
*
* Since old programs tend to use this call to determine the first arg
* for _select(), having this return > FD_SETSIZE is a Bad Idea(TM)!
*/
int
_rpc_dtablesize(void)
{
static int size;
if (size == 0) {
size = getdtablesize();
if (size > FD_SETSIZE)
size = FD_SETSIZE;
}
return (size);
}
diff --git a/lib/libc/rpc/rpc_generic.c b/lib/libc/rpc/rpc_generic.c
index 967fb6e0932c..99e3c1263c18 100644
--- a/lib/libc/rpc/rpc_generic.c
+++ b/lib/libc/rpc/rpc_generic.c
@@ -1,844 +1,843 @@
/* $NetBSD: rpc_generic.c,v 1.4 2000/09/28 09:07:04 kleink Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
/* #pragma ident "@(#)rpc_generic.c 1.17 94/04/24 SMI" */
-#include <sys/cdefs.h>
/*
* rpc_generic.c, Miscl routines for RPC.
*
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/resource.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <rpc/rpc.h>
#include <ctype.h>
#include <stddef.h>
#include <stdio.h>
#include <netdb.h>
#include <netconfig.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <rpc/nettype.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
struct handle {
NCONF_HANDLE *nhandle;
int nflag; /* Whether NETPATH or NETCONFIG */
int nettype;
};
static const struct _rpcnettype {
const char *name;
const int type;
} _rpctypelist[] = {
{ "netpath", _RPC_NETPATH },
{ "visible", _RPC_VISIBLE },
{ "circuit_v", _RPC_CIRCUIT_V },
{ "datagram_v", _RPC_DATAGRAM_V },
{ "circuit_n", _RPC_CIRCUIT_N },
{ "datagram_n", _RPC_DATAGRAM_N },
{ "tcp", _RPC_TCP },
{ "udp", _RPC_UDP },
{ 0, _RPC_NONE }
};
struct netid_af {
const char *netid;
int af;
int protocol;
};
static const struct netid_af na_cvt[] = {
{ "udp", AF_INET, IPPROTO_UDP },
{ "tcp", AF_INET, IPPROTO_TCP },
#ifdef INET6
{ "udp6", AF_INET6, IPPROTO_UDP },
{ "tcp6", AF_INET6, IPPROTO_TCP },
#endif
{ "local", AF_LOCAL, 0 }
};
#if 0
static char *strlocase(char *);
#endif
static int getnettype(const char *);
/*
* Cache the result of getrlimit(), so we don't have to do an
* expensive call every time.
*/
int
__rpc_dtbsize(void)
{
static int tbsize;
struct rlimit rl;
if (tbsize) {
return (tbsize);
}
if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
return (tbsize = (int)rl.rlim_max);
}
/*
* Something wrong. I'll try to save face by returning a
* pessimistic number.
*/
return (32);
}
/*
* Find the appropriate buffer size
*
* size - Size requested
*/
u_int
/*ARGSUSED*/
__rpc_get_t_size(int af, int proto, int size)
{
int maxsize, defsize;
maxsize = 256 * 1024; /* XXX */
switch (proto) {
case IPPROTO_TCP:
defsize = 64 * 1024; /* XXX */
break;
case IPPROTO_UDP:
defsize = UDPMSGSIZE;
break;
default:
defsize = RPC_MAXDATASIZE;
break;
}
if (size == 0)
return defsize;
/* Check whether the value is within the upper max limit */
return (size > maxsize ? (u_int)maxsize : (u_int)size);
}
/*
* Find the appropriate address buffer size
*/
u_int
__rpc_get_a_size(int af)
{
switch (af) {
case AF_INET:
return sizeof (struct sockaddr_in);
#ifdef INET6
case AF_INET6:
return sizeof (struct sockaddr_in6);
#endif
case AF_LOCAL:
return sizeof (struct sockaddr_un);
default:
break;
}
return ((u_int)RPC_MAXADDRSIZE);
}
#if 0
static char *
strlocase(char *p)
{
char *t = p;
for (; *p; p++)
if (isupper(*p))
*p = tolower(*p);
return (t);
}
#endif
/*
* Returns the type of the network as defined in <rpc/nettype.h>
* If nettype is NULL, it defaults to NETPATH.
*/
static int
getnettype(const char *nettype)
{
int i;
if ((nettype == NULL) || (nettype[0] == 0)) {
return (_RPC_NETPATH); /* Default */
}
#if 0
nettype = strlocase(nettype);
#endif
for (i = 0; _rpctypelist[i].name; i++)
if (strcasecmp(nettype, _rpctypelist[i].name) == 0) {
return (_rpctypelist[i].type);
}
return (_rpctypelist[i].type);
}
static thread_key_t tcp_key, udp_key;
static once_t keys_once = ONCE_INITIALIZER;
static int tcp_key_error, udp_key_error;
static void
keys_init(void)
{
tcp_key_error = thr_keycreate(&tcp_key, free);
udp_key_error = thr_keycreate(&udp_key, free);
}
/*
* For the given nettype (tcp or udp only), return the first structure found.
* This should be freed by calling freenetconfigent()
*/
struct netconfig *
__rpc_getconfip(const char *nettype)
{
char *netid;
char *netid_tcp = (char *) NULL;
char *netid_udp = (char *) NULL;
static char *netid_tcp_main;
static char *netid_udp_main;
struct netconfig *dummy;
int main_thread;
if ((main_thread = thr_main())) {
netid_udp = netid_udp_main;
netid_tcp = netid_tcp_main;
} else {
if (thr_once(&keys_once, keys_init) != 0 ||
tcp_key_error != 0 || udp_key_error != 0)
return (NULL);
netid_tcp = (char *)thr_getspecific(tcp_key);
netid_udp = (char *)thr_getspecific(udp_key);
}
if (!netid_udp && !netid_tcp) {
struct netconfig *nconf;
void *confighandle;
if (!(confighandle = setnetconfig())) {
syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
return (NULL);
}
while ((nconf = getnetconfig(confighandle)) != NULL) {
if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
if (strcmp(nconf->nc_proto, NC_TCP) == 0 &&
netid_tcp == NULL) {
netid_tcp = strdup(nconf->nc_netid);
if (main_thread)
netid_tcp_main = netid_tcp;
else
thr_setspecific(tcp_key,
(void *) netid_tcp);
} else
if (strcmp(nconf->nc_proto, NC_UDP) == 0 &&
netid_udp == NULL) {
netid_udp = strdup(nconf->nc_netid);
if (main_thread)
netid_udp_main = netid_udp;
else
thr_setspecific(udp_key,
(void *) netid_udp);
}
}
}
endnetconfig(confighandle);
}
if (strcmp(nettype, "udp") == 0)
netid = netid_udp;
else if (strcmp(nettype, "tcp") == 0)
netid = netid_tcp;
else {
return (NULL);
}
if ((netid == NULL) || (netid[0] == 0)) {
return (NULL);
}
dummy = getnetconfigent(netid);
return (dummy);
}
/*
* Returns the type of the nettype, which should then be used with
* __rpc_getconf().
*/
void *
__rpc_setconf(const char *nettype)
{
struct handle *handle;
handle = (struct handle *) malloc(sizeof (struct handle));
if (handle == NULL) {
return (NULL);
}
switch (handle->nettype = getnettype(nettype)) {
case _RPC_NETPATH:
case _RPC_CIRCUIT_N:
case _RPC_DATAGRAM_N:
if (!(handle->nhandle = setnetpath()))
goto failed;
handle->nflag = TRUE;
break;
case _RPC_VISIBLE:
case _RPC_CIRCUIT_V:
case _RPC_DATAGRAM_V:
case _RPC_TCP:
case _RPC_UDP:
if (!(handle->nhandle = setnetconfig())) {
syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
goto failed;
}
handle->nflag = FALSE;
break;
default:
goto failed;
}
return (handle);
failed:
free(handle);
return (NULL);
}
/*
* Returns the next netconfig struct for the given "net" type.
* __rpc_setconf() should have been called previously.
*/
struct netconfig *
__rpc_getconf(void *vhandle)
{
struct handle *handle;
struct netconfig *nconf;
handle = (struct handle *)vhandle;
if (handle == NULL) {
return (NULL);
}
for (;;) {
if (handle->nflag)
nconf = getnetpath(handle->nhandle);
else
nconf = getnetconfig(handle->nhandle);
if (nconf == NULL)
break;
if ((nconf->nc_semantics != NC_TPI_CLTS) &&
(nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD))
continue;
switch (handle->nettype) {
case _RPC_VISIBLE:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_NETPATH: /* Be happy */
break;
case _RPC_CIRCUIT_V:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_CIRCUIT_N:
if ((nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD))
continue;
break;
case _RPC_DATAGRAM_V:
if (!(nconf->nc_flag & NC_VISIBLE))
continue;
/* FALLTHROUGH */
case _RPC_DATAGRAM_N:
if (nconf->nc_semantics != NC_TPI_CLTS)
continue;
break;
case _RPC_TCP:
if (((nconf->nc_semantics != NC_TPI_COTS) &&
(nconf->nc_semantics != NC_TPI_COTS_ORD)) ||
(strcmp(nconf->nc_protofmly, NC_INET)
#ifdef INET6
&& strcmp(nconf->nc_protofmly, NC_INET6))
#else
)
#endif
||
strcmp(nconf->nc_proto, NC_TCP))
continue;
break;
case _RPC_UDP:
if ((nconf->nc_semantics != NC_TPI_CLTS) ||
(strcmp(nconf->nc_protofmly, NC_INET)
#ifdef INET6
&& strcmp(nconf->nc_protofmly, NC_INET6))
#else
)
#endif
||
strcmp(nconf->nc_proto, NC_UDP))
continue;
break;
}
break;
}
return (nconf);
}
void
__rpc_endconf(void *vhandle)
{
struct handle *handle;
handle = (struct handle *) vhandle;
if (handle == NULL) {
return;
}
if (handle->nflag) {
endnetpath(handle->nhandle);
} else {
endnetconfig(handle->nhandle);
}
free(handle);
}
/*
* Used to ping the NULL procedure for clnt handle.
* Returns NULL if fails, else a non-NULL pointer.
*/
void *
rpc_nullproc(CLIENT *clnt)
{
struct timeval TIMEOUT = {25, 0};
if (clnt_call(clnt, NULLPROC, (xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_void, NULL, TIMEOUT) != RPC_SUCCESS) {
return (NULL);
}
return ((void *) clnt);
}
/*
* Try all possible transports until
* one succeeds in finding the netconf for the given fd.
*/
struct netconfig *
__rpcgettp(int fd)
{
const char *netid;
struct __rpc_sockinfo si;
if (!__rpc_fd2sockinfo(fd, &si))
return NULL;
if (!__rpc_sockinfo2netid(&si, &netid))
return NULL;
/*LINTED const castaway*/
return getnetconfigent((char *)netid);
}
int
__rpc_fd2sockinfo(int fd, struct __rpc_sockinfo *sip)
{
socklen_t len;
int type, proto;
struct sockaddr_storage ss;
len = sizeof ss;
if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &len) < 0)
return 0;
sip->si_alen = len;
len = sizeof type;
if (_getsockopt(fd, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
return 0;
/* XXX */
if (ss.ss_family != AF_LOCAL) {
if (type == SOCK_STREAM)
proto = IPPROTO_TCP;
else if (type == SOCK_DGRAM)
proto = IPPROTO_UDP;
else
return 0;
} else
proto = 0;
sip->si_af = ss.ss_family;
sip->si_proto = proto;
sip->si_socktype = type;
return 1;
}
/*
* Linear search, but the number of entries is small.
*/
int
__rpc_nconf2sockinfo(const struct netconfig *nconf, struct __rpc_sockinfo *sip)
{
int i;
for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++)
if (strcmp(na_cvt[i].netid, nconf->nc_netid) == 0 || (
strcmp(nconf->nc_netid, "unix") == 0 &&
strcmp(na_cvt[i].netid, "local") == 0)) {
sip->si_af = na_cvt[i].af;
sip->si_proto = na_cvt[i].protocol;
sip->si_socktype =
__rpc_seman2socktype((int)nconf->nc_semantics);
if (sip->si_socktype == -1)
return 0;
sip->si_alen = __rpc_get_a_size(sip->si_af);
return 1;
}
return 0;
}
int
__rpc_nconf2fd(const struct netconfig *nconf)
{
struct __rpc_sockinfo si;
if (!__rpc_nconf2sockinfo(nconf, &si))
return 0;
return _socket(si.si_af, si.si_socktype, si.si_proto);
}
int
__rpc_sockinfo2netid(struct __rpc_sockinfo *sip, const char **netid)
{
int i;
struct netconfig *nconf;
nconf = getnetconfigent("local");
for (i = 0; i < (sizeof na_cvt) / (sizeof (struct netid_af)); i++) {
if (na_cvt[i].af == sip->si_af &&
na_cvt[i].protocol == sip->si_proto) {
if (strcmp(na_cvt[i].netid, "local") == 0 && nconf == NULL) {
if (netid)
*netid = "unix";
} else {
if (netid)
*netid = na_cvt[i].netid;
}
if (nconf != NULL)
freenetconfigent(nconf);
return 1;
}
}
if (nconf != NULL)
freenetconfigent(nconf);
return 0;
}
char *
taddr2uaddr(const struct netconfig *nconf, const struct netbuf *nbuf)
{
struct __rpc_sockinfo si;
if (!__rpc_nconf2sockinfo(nconf, &si))
return NULL;
return __rpc_taddr2uaddr_af(si.si_af, nbuf);
}
struct netbuf *
uaddr2taddr(const struct netconfig *nconf, const char *uaddr)
{
struct __rpc_sockinfo si;
if (!__rpc_nconf2sockinfo(nconf, &si))
return NULL;
return __rpc_uaddr2taddr_af(si.si_af, uaddr);
}
char *
__rpc_taddr2uaddr_af(int af, const struct netbuf *nbuf)
{
char *ret;
struct sockaddr_in *sin;
struct sockaddr_un *sun;
char namebuf[INET_ADDRSTRLEN];
#ifdef INET6
struct sockaddr_in6 *sin6;
char namebuf6[INET6_ADDRSTRLEN];
#endif
u_int16_t port;
switch (af) {
case AF_INET:
if (nbuf->len < sizeof(*sin))
return NULL;
sin = nbuf->buf;
if (inet_ntop(af, &sin->sin_addr, namebuf, sizeof namebuf)
== NULL)
return NULL;
port = ntohs(sin->sin_port);
if (asprintf(&ret, "%s.%u.%u", namebuf, ((u_int32_t)port) >> 8,
port & 0xff) < 0)
return NULL;
break;
#ifdef INET6
case AF_INET6:
if (nbuf->len < sizeof(*sin6))
return NULL;
sin6 = nbuf->buf;
if (inet_ntop(af, &sin6->sin6_addr, namebuf6, sizeof namebuf6)
== NULL)
return NULL;
port = ntohs(sin6->sin6_port);
if (asprintf(&ret, "%s.%u.%u", namebuf6, ((u_int32_t)port) >> 8,
port & 0xff) < 0)
return NULL;
break;
#endif
case AF_LOCAL:
sun = nbuf->buf;
if (asprintf(&ret, "%.*s", (int)(sun->sun_len -
offsetof(struct sockaddr_un, sun_path)),
sun->sun_path) < 0)
return (NULL);
break;
default:
return NULL;
}
return ret;
}
struct netbuf *
__rpc_uaddr2taddr_af(int af, const char *uaddr)
{
struct netbuf *ret = NULL;
char *addrstr, *p;
unsigned port, portlo, porthi;
struct sockaddr_in *sin;
#ifdef INET6
struct sockaddr_in6 *sin6;
#endif
struct sockaddr_un *sun;
port = 0;
sin = NULL;
if (uaddr == NULL)
return NULL;
addrstr = strdup(uaddr);
if (addrstr == NULL)
return NULL;
/*
* AF_LOCAL addresses are expected to be absolute
* pathnames, anything else will be AF_INET or AF_INET6.
*/
if (*addrstr != '/') {
p = strrchr(addrstr, '.');
if (p == NULL)
goto out;
portlo = (unsigned)atoi(p + 1);
*p = '\0';
p = strrchr(addrstr, '.');
if (p == NULL)
goto out;
porthi = (unsigned)atoi(p + 1);
*p = '\0';
port = (porthi << 8) | portlo;
}
ret = (struct netbuf *)malloc(sizeof *ret);
if (ret == NULL)
goto out;
switch (af) {
case AF_INET:
sin = (struct sockaddr_in *)malloc(sizeof *sin);
if (sin == NULL)
goto out;
memset(sin, 0, sizeof *sin);
sin->sin_family = AF_INET;
sin->sin_port = htons(port);
if (inet_pton(AF_INET, addrstr, &sin->sin_addr) <= 0) {
free(sin);
free(ret);
ret = NULL;
goto out;
}
sin->sin_len = ret->maxlen = ret->len = sizeof *sin;
ret->buf = sin;
break;
#ifdef INET6
case AF_INET6:
sin6 = (struct sockaddr_in6 *)malloc(sizeof *sin6);
if (sin6 == NULL)
goto out;
memset(sin6, 0, sizeof *sin6);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons(port);
if (inet_pton(AF_INET6, addrstr, &sin6->sin6_addr) <= 0) {
free(sin6);
free(ret);
ret = NULL;
goto out;
}
sin6->sin6_len = ret->maxlen = ret->len = sizeof *sin6;
ret->buf = sin6;
break;
#endif
case AF_LOCAL:
sun = (struct sockaddr_un *)malloc(sizeof *sun);
if (sun == NULL)
goto out;
memset(sun, 0, sizeof *sun);
sun->sun_family = AF_LOCAL;
strncpy(sun->sun_path, addrstr, sizeof(sun->sun_path) - 1);
ret->len = ret->maxlen = sun->sun_len = SUN_LEN(sun);
ret->buf = sun;
break;
default:
break;
}
out:
free(addrstr);
return ret;
}
int
__rpc_seman2socktype(int semantics)
{
switch (semantics) {
case NC_TPI_CLTS:
return SOCK_DGRAM;
case NC_TPI_COTS_ORD:
return SOCK_STREAM;
case NC_TPI_RAW:
return SOCK_RAW;
default:
break;
}
return -1;
}
int
__rpc_socktype2seman(int socktype)
{
switch (socktype) {
case SOCK_DGRAM:
return NC_TPI_CLTS;
case SOCK_STREAM:
return NC_TPI_COTS_ORD;
case SOCK_RAW:
return NC_TPI_RAW;
default:
break;
}
return -1;
}
/*
* XXXX - IPv6 scope IDs can't be handled in universal addresses.
* Here, we compare the original server address to that of the RPC
* service we just received back from a call to rpcbind on the remote
* machine. If they are both "link local" or "site local", copy
* the scope id of the server address over to the service address.
*/
int
__rpc_fixup_addr(struct netbuf *new, const struct netbuf *svc)
{
#ifdef INET6
struct sockaddr *sa_new, *sa_svc;
struct sockaddr_in6 *sin6_new, *sin6_svc;
sa_svc = (struct sockaddr *)svc->buf;
sa_new = (struct sockaddr *)new->buf;
if (sa_new->sa_family == sa_svc->sa_family &&
sa_new->sa_family == AF_INET6) {
sin6_new = (struct sockaddr_in6 *)new->buf;
sin6_svc = (struct sockaddr_in6 *)svc->buf;
if ((IN6_IS_ADDR_LINKLOCAL(&sin6_new->sin6_addr) &&
IN6_IS_ADDR_LINKLOCAL(&sin6_svc->sin6_addr)) ||
(IN6_IS_ADDR_SITELOCAL(&sin6_new->sin6_addr) &&
IN6_IS_ADDR_SITELOCAL(&sin6_svc->sin6_addr))) {
sin6_new->sin6_scope_id = sin6_svc->sin6_scope_id;
}
}
#endif
return 1;
}
int
__rpc_sockisbound(int fd)
{
struct sockaddr_storage ss;
socklen_t slen;
slen = sizeof (struct sockaddr_storage);
if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0)
return 0;
switch (ss.ss_family) {
case AF_INET:
return (((struct sockaddr_in *)
(void *)&ss)->sin_port != 0);
#ifdef INET6
case AF_INET6:
return (((struct sockaddr_in6 *)
(void *)&ss)->sin6_port != 0);
#endif
case AF_LOCAL:
/* XXX check this */
return (((struct sockaddr_un *)
(void *)&ss)->sun_path[0] != '\0');
default:
break;
}
return 0;
}
diff --git a/lib/libc/rpc/rpc_prot.c b/lib/libc/rpc/rpc_prot.c
index 6cd854efa943..a64a13a76339 100644
--- a/lib/libc/rpc/rpc_prot.c
+++ b/lib/libc/rpc/rpc_prot.c
@@ -1,353 +1,352 @@
/* $NetBSD: rpc_prot.c,v 1.16 2000/06/02 23:11:13 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)rpc_prot.c 1.36 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)rpc_prot.c 2.3 88/08/07 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* rpc_prot.c
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*
* This set of routines implements the rpc message definition,
* its serializer and some common rpc utility routines.
* The routines are meant for various implementations of rpc -
* they are NOT for the rpc client or rpc service implementations!
* Because authentication stuff is easy and is part of rpc, the opaque
* routines are also in this program.
*/
#include "namespace.h"
#include <sys/param.h>
#include <assert.h>
#include <rpc/rpc.h>
#include "un-namespace.h"
static void accepted(enum accept_stat, struct rpc_err *);
static void rejected(enum reject_stat, struct rpc_err *);
/* * * * * * * * * * * * * * XDR Authentication * * * * * * * * * * * */
extern struct opaque_auth _null_auth;
/*
* XDR an opaque authentication struct
* (see auth.h)
*/
bool_t
xdr_opaque_auth(XDR *xdrs, struct opaque_auth *ap)
{
assert(xdrs != NULL);
assert(ap != NULL);
if (xdr_enum(xdrs, &(ap->oa_flavor)))
return (xdr_bytes(xdrs, &ap->oa_base,
&ap->oa_length, MAX_AUTH_BYTES));
return (FALSE);
}
/*
* XDR a DES block
*/
bool_t
xdr_des_block(XDR *xdrs, des_block *blkp)
{
assert(xdrs != NULL);
assert(blkp != NULL);
return (xdr_opaque(xdrs, (caddr_t)(void *)blkp, sizeof(des_block)));
}
/* * * * * * * * * * * * * * XDR RPC MESSAGE * * * * * * * * * * * * * * * */
/*
* XDR the MSG_ACCEPTED part of a reply message union
*/
bool_t
xdr_accepted_reply(XDR *xdrs, struct accepted_reply *ar)
{
enum accept_stat *par_stat;
assert(xdrs != NULL);
assert(ar != NULL);
par_stat = &ar->ar_stat;
/* personalized union, rather than calling xdr_union */
if (! xdr_opaque_auth(xdrs, &(ar->ar_verf)))
return (FALSE);
if (! xdr_enum(xdrs, (enum_t *) par_stat))
return (FALSE);
switch (ar->ar_stat) {
case SUCCESS:
return ((*(ar->ar_results.proc))(xdrs, ar->ar_results.where));
case PROG_MISMATCH:
if (!xdr_rpcvers(xdrs, &(ar->ar_vers.low)))
return (FALSE);
return (xdr_rpcvers(xdrs, &(ar->ar_vers.high)));
case GARBAGE_ARGS:
case SYSTEM_ERR:
case PROC_UNAVAIL:
case PROG_UNAVAIL:
break;
}
return (TRUE); /* TRUE => open ended set of problems */
}
/*
* XDR the MSG_DENIED part of a reply message union
*/
bool_t
xdr_rejected_reply(XDR *xdrs, struct rejected_reply *rr)
{
enum reject_stat *prj_stat;
enum auth_stat *prj_why;
assert(xdrs != NULL);
assert(rr != NULL);
prj_stat = &rr->rj_stat;
/* personalized union, rather than calling xdr_union */
if (! xdr_enum(xdrs, (enum_t *) prj_stat))
return (FALSE);
switch (rr->rj_stat) {
case RPC_MISMATCH:
if (! xdr_rpcvers(xdrs, &(rr->rj_vers.low)))
return (FALSE);
return (xdr_rpcvers(xdrs, &(rr->rj_vers.high)));
case AUTH_ERROR:
prj_why = &rr->rj_why;
return (xdr_enum(xdrs, (enum_t *) prj_why));
}
/* NOTREACHED */
assert(0);
return (FALSE);
}
static const struct xdr_discrim reply_dscrm[3] = {
{ (int)MSG_ACCEPTED, (xdrproc_t)xdr_accepted_reply },
{ (int)MSG_DENIED, (xdrproc_t)xdr_rejected_reply },
{ __dontcare__, NULL_xdrproc_t } };
/*
* XDR a reply message
*/
bool_t
xdr_replymsg(XDR *xdrs, struct rpc_msg *rmsg)
{
enum msg_type *prm_direction;
enum reply_stat *prp_stat;
assert(xdrs != NULL);
assert(rmsg != NULL);
prm_direction = &rmsg->rm_direction;
prp_stat = &rmsg->rm_reply.rp_stat;
if (
xdr_u_int32_t(xdrs, &(rmsg->rm_xid)) &&
xdr_enum(xdrs, (enum_t *) prm_direction) &&
(rmsg->rm_direction == REPLY) )
return (xdr_union(xdrs, (enum_t *) prp_stat,
(caddr_t)(void *)&(rmsg->rm_reply.ru), reply_dscrm,
NULL_xdrproc_t));
return (FALSE);
}
/*
* Serializes the "static part" of a call message header.
* The fields include: rm_xid, rm_direction, rpcvers, prog, and vers.
* The rm_xid is not really static, but the user can easily munge on the fly.
*/
bool_t
xdr_callhdr(XDR *xdrs, struct rpc_msg *cmsg)
{
enum msg_type *prm_direction;
assert(xdrs != NULL);
assert(cmsg != NULL);
prm_direction = &cmsg->rm_direction;
cmsg->rm_direction = CALL;
cmsg->rm_call.cb_rpcvers = RPC_MSG_VERSION;
if (
(xdrs->x_op == XDR_ENCODE) &&
xdr_u_int32_t(xdrs, &(cmsg->rm_xid)) &&
xdr_enum(xdrs, (enum_t *) prm_direction) &&
xdr_rpcvers(xdrs, &(cmsg->rm_call.cb_rpcvers)) &&
xdr_rpcprog(xdrs, &(cmsg->rm_call.cb_prog)) )
return (xdr_u_int32_t(xdrs, &(cmsg->rm_call.cb_vers)));
return (FALSE);
}
/* ************************** Client utility routine ************* */
static void
accepted(enum accept_stat acpt_stat, struct rpc_err *error)
{
assert(error != NULL);
switch (acpt_stat) {
case PROG_UNAVAIL:
error->re_status = RPC_PROGUNAVAIL;
return;
case PROG_MISMATCH:
error->re_status = RPC_PROGVERSMISMATCH;
return;
case PROC_UNAVAIL:
error->re_status = RPC_PROCUNAVAIL;
return;
case GARBAGE_ARGS:
error->re_status = RPC_CANTDECODEARGS;
return;
case SYSTEM_ERR:
error->re_status = RPC_SYSTEMERROR;
return;
case SUCCESS:
error->re_status = RPC_SUCCESS;
return;
}
/* NOTREACHED */
/* something's wrong, but we don't know what ... */
error->re_status = RPC_FAILED;
error->re_lb.s1 = (int32_t)MSG_ACCEPTED;
error->re_lb.s2 = (int32_t)acpt_stat;
}
static void
rejected(enum reject_stat rjct_stat, struct rpc_err *error)
{
assert(error != NULL);
switch (rjct_stat) {
case RPC_MISMATCH:
error->re_status = RPC_VERSMISMATCH;
return;
case AUTH_ERROR:
error->re_status = RPC_AUTHERROR;
return;
}
/* something's wrong, but we don't know what ... */
/* NOTREACHED */
error->re_status = RPC_FAILED;
error->re_lb.s1 = (int32_t)MSG_DENIED;
error->re_lb.s2 = (int32_t)rjct_stat;
}
/*
* given a reply message, fills in the error
*/
void
_seterr_reply(struct rpc_msg *msg, struct rpc_err *error)
{
assert(msg != NULL);
assert(error != NULL);
/* optimized for normal, SUCCESSful case */
switch (msg->rm_reply.rp_stat) {
case MSG_ACCEPTED:
if (msg->acpted_rply.ar_stat == SUCCESS) {
error->re_status = RPC_SUCCESS;
return;
}
accepted(msg->acpted_rply.ar_stat, error);
break;
case MSG_DENIED:
rejected(msg->rjcted_rply.rj_stat, error);
break;
default:
error->re_status = RPC_FAILED;
error->re_lb.s1 = (int32_t)(msg->rm_reply.rp_stat);
break;
}
switch (error->re_status) {
case RPC_VERSMISMATCH:
error->re_vers.low = msg->rjcted_rply.rj_vers.low;
error->re_vers.high = msg->rjcted_rply.rj_vers.high;
break;
case RPC_AUTHERROR:
error->re_why = msg->rjcted_rply.rj_why;
break;
case RPC_PROGVERSMISMATCH:
error->re_vers.low = msg->acpted_rply.ar_vers.low;
error->re_vers.high = msg->acpted_rply.ar_vers.high;
break;
case RPC_FAILED:
case RPC_SUCCESS:
case RPC_PROGNOTREGISTERED:
case RPC_PMAPFAILURE:
case RPC_UNKNOWNPROTO:
case RPC_UNKNOWNHOST:
case RPC_SYSTEMERROR:
case RPC_CANTDECODEARGS:
case RPC_PROCUNAVAIL:
case RPC_PROGUNAVAIL:
case RPC_TIMEDOUT:
case RPC_CANTRECV:
case RPC_CANTSEND:
case RPC_CANTDECODERES:
case RPC_CANTENCODEARGS:
default:
break;
}
}
diff --git a/lib/libc/rpc/rpc_soc.c b/lib/libc/rpc/rpc_soc.c
index 1350da14d42b..5c8c09d82c75 100644
--- a/lib/libc/rpc/rpc_soc.c
+++ b/lib/libc/rpc/rpc_soc.c
@@ -1,533 +1,532 @@
/* $NetBSD: rpc_soc.c,v 1.6 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* #ident "@(#)rpc_soc.c 1.17 94/04/24 SMI" */
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
* In addition, portions of such source code were derived from Berkeley
* 4.3 BSD under license from the Regents of the University of
* California.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rpc_soc.c 1.41 89/05/02 Copyr 1988 Sun Micro";
#endif
-#include <sys/cdefs.h>
#ifdef PORTMAP
/*
* rpc_soc.c
*
* The backward compatibility routines for the earlier implementation
* of RPC, where the only transports supported were tcp/ip and udp/ip.
* Based on berkeley socket abstraction, now implemented on the top
* of TLI/Streams
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <rpc/rpc.h>
#include <rpc/pmap_clnt.h>
#include <rpc/pmap_prot.h>
#include <rpc/nettype.h>
#include <syslog.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <syslog.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
static CLIENT *clnt_com_create(struct sockaddr_in *, rpcprog_t, rpcvers_t,
int *, u_int, u_int, char *);
static SVCXPRT *svc_com_create(int, u_int, u_int, char *);
static bool_t rpc_wrap_bcast(char *, struct netbuf *, struct netconfig *);
/* XXX */
#define IN4_LOCALHOST_STRING "127.0.0.1"
#define IN6_LOCALHOST_STRING "::1"
/*
* A common clnt create routine
*/
static CLIENT *
clnt_com_create(struct sockaddr_in *raddr, rpcprog_t prog, rpcvers_t vers, int *sockp,
u_int sendsz, u_int recvsz, char *tp)
{
CLIENT *cl;
int madefd = FALSE;
int fd = *sockp;
struct netconfig *nconf;
struct netbuf bindaddr;
mutex_lock(&rpcsoc_lock);
if ((nconf = __rpc_getconfip(tp)) == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
mutex_unlock(&rpcsoc_lock);
return (NULL);
}
if (fd == RPC_ANYSOCK) {
fd = __rpc_nconf2fd(nconf);
if (fd == -1)
goto syserror;
madefd = TRUE;
}
if (raddr->sin_port == 0) {
u_int proto;
u_short sport;
mutex_unlock(&rpcsoc_lock); /* pmap_getport is recursive */
proto = strcmp(tp, "udp") == 0 ? IPPROTO_UDP : IPPROTO_TCP;
sport = pmap_getport(raddr, (u_long)prog, (u_long)vers,
proto);
mutex_lock(&rpcsoc_lock); /* pmap_getport is recursive */
if (sport == 0) {
goto err;
}
raddr->sin_port = htons(sport);
}
/* Transform sockaddr_in to netbuf */
bindaddr.maxlen = bindaddr.len = sizeof (struct sockaddr_in);
bindaddr.buf = raddr;
bindresvport(fd, NULL);
cl = clnt_tli_create(fd, nconf, &bindaddr, prog, vers,
sendsz, recvsz);
if (cl) {
if (madefd == TRUE) {
/*
* The fd should be closed while destroying the handle.
*/
(void) CLNT_CONTROL(cl, CLSET_FD_CLOSE, NULL);
*sockp = fd;
}
(void) freenetconfigent(nconf);
mutex_unlock(&rpcsoc_lock);
return (cl);
}
goto err;
syserror:
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
err: if (madefd == TRUE)
(void)_close(fd);
(void) freenetconfigent(nconf);
mutex_unlock(&rpcsoc_lock);
return (NULL);
}
CLIENT *
clntudp_bufcreate(struct sockaddr_in *raddr, u_long prog, u_long vers,
struct timeval wait, int *sockp, u_int sendsz, u_int recvsz)
{
CLIENT *cl;
cl = clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
sendsz, recvsz, "udp");
if (cl == NULL) {
return (NULL);
}
(void) CLNT_CONTROL(cl, CLSET_RETRY_TIMEOUT, &wait);
return (cl);
}
CLIENT *
clntudp_create(struct sockaddr_in *raddr, u_long program, u_long version,
struct timeval wait, int *sockp)
{
return clntudp_bufcreate(raddr, program, version, wait, sockp,
UDPMSGSIZE, UDPMSGSIZE);
}
CLIENT *
clnttcp_create(struct sockaddr_in *raddr, u_long prog, u_long vers, int *sockp,
u_int sendsz, u_int recvsz)
{
return clnt_com_create(raddr, (rpcprog_t)prog, (rpcvers_t)vers, sockp,
sendsz, recvsz, "tcp");
}
CLIENT *
clntraw_create(u_long prog, u_long vers)
{
return clnt_raw_create((rpcprog_t)prog, (rpcvers_t)vers);
}
/*
* A common server create routine
*/
static SVCXPRT *
svc_com_create(int fd, u_int sendsize, u_int recvsize, char *netid)
{
struct netconfig *nconf;
SVCXPRT *svc;
int madefd = FALSE;
int port;
struct sockaddr_in sin;
if ((nconf = __rpc_getconfip(netid)) == NULL) {
(void) syslog(LOG_ERR, "Could not get %s transport", netid);
return (NULL);
}
if (fd == RPC_ANYSOCK) {
fd = __rpc_nconf2fd(nconf);
if (fd == -1) {
(void) freenetconfigent(nconf);
(void) syslog(LOG_ERR,
"svc%s_create: could not open connection", netid);
return (NULL);
}
madefd = TRUE;
}
memset(&sin, 0, sizeof sin);
sin.sin_family = AF_INET;
bindresvport(fd, &sin);
_listen(fd, SOMAXCONN);
svc = svc_tli_create(fd, nconf, NULL, sendsize, recvsize);
(void) freenetconfigent(nconf);
if (svc == NULL) {
if (madefd)
(void)_close(fd);
return (NULL);
}
port = (((struct sockaddr_in *)svc->xp_ltaddr.buf)->sin_port);
svc->xp_port = ntohs(port);
return (svc);
}
SVCXPRT *
svctcp_create(int fd, u_int sendsize, u_int recvsize)
{
return svc_com_create(fd, sendsize, recvsize, "tcp");
}
SVCXPRT *
svcudp_bufcreate(int fd, u_int sendsz, u_int recvsz)
{
return svc_com_create(fd, sendsz, recvsz, "udp");
}
SVCXPRT *
svcfd_create(int fd, u_int sendsize, u_int recvsize)
{
return svc_fd_create(fd, sendsize, recvsize);
}
SVCXPRT *
svcudp_create(int fd)
{
return svc_com_create(fd, UDPMSGSIZE, UDPMSGSIZE, "udp");
}
SVCXPRT *
svcraw_create(void)
{
return svc_raw_create();
}
int
get_myaddress(struct sockaddr_in *addr)
{
memset((void *) addr, 0, sizeof(*addr));
addr->sin_family = AF_INET;
addr->sin_port = htons(PMAPPORT);
addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
return (0);
}
/*
* For connectionless "udp" transport. Obsoleted by rpc_call().
*/
int
callrpc(const char *host, int prognum, int versnum, int procnum,
xdrproc_t inproc, void *in, xdrproc_t outproc, void *out)
{
return (int)rpc_call(host, (rpcprog_t)prognum, (rpcvers_t)versnum,
(rpcproc_t)procnum, inproc, in, outproc, out, "udp");
}
/*
* For connectionless kind of transport. Obsoleted by rpc_reg()
*/
int
registerrpc(int prognum, int versnum, int procnum,
char *(*progname)(char [UDPMSGSIZE]),
xdrproc_t inproc, xdrproc_t outproc)
{
return rpc_reg((rpcprog_t)prognum, (rpcvers_t)versnum,
(rpcproc_t)procnum, progname, inproc, outproc, "udp");
}
/*
* All the following clnt_broadcast stuff is convulated; it supports
* the earlier calling style of the callback function
*/
static thread_key_t clnt_broadcast_key;
static resultproc_t clnt_broadcast_result_main;
static once_t clnt_broadcast_once = ONCE_INITIALIZER;
static void
clnt_broadcast_key_init(void)
{
thr_keycreate(&clnt_broadcast_key, free);
}
/*
* Need to translate the netbuf address into sockaddr_in address.
* Dont care about netid here.
*/
/* ARGSUSED */
static bool_t
rpc_wrap_bcast(char *resultp, struct netbuf *addr, struct netconfig *nconf)
/*
* char *resultp; // results of the call
* struct netbuf *addr; // address of the guy who responded
* struct netconfig *nconf; // Netconf of the transport
*/
{
resultproc_t clnt_broadcast_result;
if (strcmp(nconf->nc_netid, "udp"))
return (FALSE);
if (thr_main())
clnt_broadcast_result = clnt_broadcast_result_main;
else
clnt_broadcast_result = (resultproc_t)thr_getspecific(clnt_broadcast_key);
return (*clnt_broadcast_result)(resultp,
(struct sockaddr_in *)addr->buf);
}
/*
* Broadcasts on UDP transport. Obsoleted by rpc_broadcast().
*/
enum clnt_stat
clnt_broadcast(u_long prog, u_long vers, u_long proc, xdrproc_t xargs,
void *argsp, xdrproc_t xresults, void *resultsp, resultproc_t eachresult)
/*
* u_long prog; // program number
* u_long vers; // version number
* u_long proc; // procedure number
* xdrproc_t xargs; // xdr routine for args
* void *argsp; // pointer to args
* xdrproc_t xresults; // xdr routine for results
* void *resultsp; // pointer to results
* resultproc_t eachresult; // call with each result obtained
*/
{
if (thr_main())
clnt_broadcast_result_main = eachresult;
else {
thr_once(&clnt_broadcast_once, clnt_broadcast_key_init);
thr_setspecific(clnt_broadcast_key, (void *) eachresult);
}
return rpc_broadcast((rpcprog_t)prog, (rpcvers_t)vers,
(rpcproc_t)proc, xargs, argsp, xresults, resultsp,
(resultproc_t) rpc_wrap_bcast, "udp");
}
/*
* Create the client des authentication object. Obsoleted by
* authdes_seccreate().
*/
AUTH *
authdes_create(char *servername, u_int window, struct sockaddr *syncaddr,
des_block *ckey)
/*
* char *servername; // network name of server
* u_int window; // time to live
* struct sockaddr *syncaddr; // optional hostaddr to sync with
* des_block *ckey; // optional conversation key to use
*/
{
AUTH *dummy;
AUTH *nauth;
char hostname[NI_MAXHOST];
if (syncaddr) {
/*
* Change addr to hostname, because that is the way
* new interface takes it.
*/
if (getnameinfo(syncaddr, syncaddr->sa_len, hostname,
sizeof hostname, NULL, 0, 0) != 0)
goto fallback;
nauth = authdes_seccreate(servername, window, hostname, ckey);
return (nauth);
}
fallback:
dummy = authdes_seccreate(servername, window, NULL, ckey);
return (dummy);
}
/*
* Create a client handle for a unix connection. Obsoleted by clnt_vc_create()
*/
CLIENT *
clntunix_create(struct sockaddr_un *raddr, u_long prog, u_long vers, int *sockp,
u_int sendsz, u_int recvsz)
{
struct netbuf *svcaddr;
CLIENT *cl;
int len;
cl = NULL;
svcaddr = NULL;
if ((raddr->sun_len == 0) ||
((svcaddr = malloc(sizeof(struct netbuf))) == NULL ) ||
((svcaddr->buf = malloc(sizeof(struct sockaddr_un))) == NULL)) {
free(svcaddr);
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
return(cl);
}
if (*sockp < 0) {
*sockp = _socket(AF_LOCAL, SOCK_STREAM, 0);
len = raddr->sun_len = SUN_LEN(raddr);
if ((*sockp < 0) || (_connect(*sockp,
(struct sockaddr *)raddr, len) < 0)) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
rpc_createerr.cf_error.re_errno = errno;
if (*sockp != -1)
(void)_close(*sockp);
goto done;
}
}
svcaddr->buf = raddr;
svcaddr->len = raddr->sun_len;
svcaddr->maxlen = sizeof (struct sockaddr_un);
cl = clnt_vc_create(*sockp, svcaddr, prog,
vers, sendsz, recvsz);
done:
free(svcaddr->buf);
free(svcaddr);
return(cl);
}
/*
* Creates, registers, and returns a (rpc) unix based transporter.
* Obsoleted by svc_vc_create().
*/
SVCXPRT *
svcunix_create(int sock, u_int sendsize, u_int recvsize, char *path)
{
struct netconfig *nconf;
void *localhandle;
struct sockaddr_un sun;
struct sockaddr *sa;
struct t_bind taddr;
SVCXPRT *xprt;
int addrlen;
xprt = (SVCXPRT *)NULL;
localhandle = setnetconfig();
while ((nconf = getnetconfig(localhandle)) != NULL) {
if (nconf->nc_protofmly != NULL &&
strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
break;
}
if (nconf == NULL)
goto done;
if ((sock = __rpc_nconf2fd(nconf)) < 0)
goto done;
memset(&sun, 0, sizeof sun);
sun.sun_family = AF_LOCAL;
if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=
sizeof(sun.sun_path))
goto done;
sun.sun_len = SUN_LEN(&sun);
addrlen = sizeof (struct sockaddr_un);
sa = (struct sockaddr *)&sun;
if (_bind(sock, sa, addrlen) < 0)
goto done;
taddr.addr.len = taddr.addr.maxlen = addrlen;
taddr.addr.buf = malloc(addrlen);
if (taddr.addr.buf == NULL)
goto done;
memcpy(taddr.addr.buf, sa, addrlen);
if (nconf->nc_semantics != NC_TPI_CLTS) {
if (_listen(sock, SOMAXCONN) < 0) {
free(taddr.addr.buf);
goto done;
}
}
xprt = (SVCXPRT *)svc_tli_create(sock, nconf, &taddr, sendsize, recvsize);
done:
endnetconfig(localhandle);
return(xprt);
}
/*
* Like svunix_create(), except the routine takes any *open* UNIX file
* descriptor as its first input. Obsoleted by svc_fd_create();
*/
SVCXPRT *
svcunixfd_create(int fd, u_int sendsize, u_int recvsize)
{
return (svc_fd_create(fd, sendsize, recvsize));
}
#endif /* PORTMAP */
diff --git a/lib/libc/rpc/rpcb_clnt.c b/lib/libc/rpc/rpcb_clnt.c
index 10e7b0cce046..7d7eed538f17 100644
--- a/lib/libc/rpc/rpcb_clnt.c
+++ b/lib/libc/rpc/rpcb_clnt.c
@@ -1,1314 +1,1313 @@
/* $NetBSD: rpcb_clnt.c,v 1.6 2000/07/16 06:41:43 itojun Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/* #ident "@(#)rpcb_clnt.c 1.27 94/04/24 SMI" */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rpcb_clnt.c 1.30 89/06/21 Copyr 1988 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* rpcb_clnt.c
* interface to rpcbind rpc service.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/utsname.h>
#include <rpc/rpc.h>
#include <rpc/rpcb_prot.h>
#include <rpc/nettype.h>
#include <netconfig.h>
#ifdef PORTMAP
#include <netinet/in.h> /* FOR IPPROTO_TCP/UDP definitions */
#include <rpc/pmap_prot.h>
#endif /* PORTMAP */
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <syslog.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
static struct timeval tottimeout = { 60, 0 };
static const struct timeval rmttimeout = { 3, 0 };
static struct timeval rpcbrmttime = { 15, 0 };
extern bool_t xdr_wrapstring(XDR *, char **);
static const char nullstring[] = "\000";
#define CACHESIZE 6
struct address_cache {
char *ac_host;
char *ac_netid;
char *ac_uaddr;
struct netbuf *ac_taddr;
struct address_cache *ac_next;
};
static struct address_cache *front;
static int cachesize;
#define CLCR_GET_RPCB_TIMEOUT 1
#define CLCR_SET_RPCB_TIMEOUT 2
extern int __rpc_lowvers;
static struct address_cache *check_cache(const char *, const char *);
static void delete_cache(struct netbuf *);
static void add_cache(const char *, const char *, struct netbuf *, char *);
static CLIENT *getclnthandle(const char *, const struct netconfig *, char **);
static CLIENT *local_rpcb(void);
static struct netbuf *got_entry(rpcb_entry_list_ptr, const struct netconfig *);
/*
* This routine adjusts the timeout used for calls to the remote rpcbind.
* Also, this routine can be used to set the use of portmapper version 2
* only when doing rpc_broadcasts
* These are private routines that may not be provided in future releases.
*/
bool_t
__rpc_control(int request, void *info)
{
switch (request) {
case CLCR_GET_RPCB_TIMEOUT:
*(struct timeval *)info = tottimeout;
break;
case CLCR_SET_RPCB_TIMEOUT:
tottimeout = *(struct timeval *)info;
break;
case CLCR_SET_LOWVERS:
__rpc_lowvers = *(int *)info;
break;
case CLCR_GET_LOWVERS:
*(int *)info = __rpc_lowvers;
break;
default:
return (FALSE);
}
return (TRUE);
}
/*
* It might seem that a reader/writer lock would be more reasonable here.
* However because getclnthandle(), the only user of the cache functions,
* may do a delete_cache() operation if a check_cache() fails to return an
* address useful to clnt_tli_create(), we may as well use a mutex.
*/
/*
* As it turns out, if the cache lock is *not* a reader/writer lock, we will
* block all clnt_create's if we are trying to connect to a host that's down,
* since the lock will be held all during that time.
*/
/*
* The routines check_cache(), add_cache(), delete_cache() manage the
* cache of rpcbind addresses for (host, netid).
*/
static struct address_cache *
check_cache(const char *host, const char *netid)
{
struct address_cache *cptr;
/* READ LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
if (!strcmp(cptr->ac_host, host) &&
!strcmp(cptr->ac_netid, netid)) {
#ifdef ND_DEBUG
fprintf(stderr, "Found cache entry for %s: %s\n",
host, netid);
#endif
return (cptr);
}
}
return ((struct address_cache *) NULL);
}
static void
delete_cache(struct netbuf *addr)
{
struct address_cache *cptr, *prevptr = NULL;
/* WRITE LOCK HELD ON ENTRY: rpcbaddr_cache_lock */
for (cptr = front; cptr != NULL; cptr = cptr->ac_next) {
if (!memcmp(cptr->ac_taddr->buf, addr->buf, addr->len)) {
free(cptr->ac_host);
free(cptr->ac_netid);
free(cptr->ac_taddr->buf);
free(cptr->ac_taddr);
free(cptr->ac_uaddr);
if (prevptr)
prevptr->ac_next = cptr->ac_next;
else
front = cptr->ac_next;
free(cptr);
cachesize--;
break;
}
prevptr = cptr;
}
}
static void
add_cache(const char *host, const char *netid, struct netbuf *taddr,
char *uaddr)
{
struct address_cache *ad_cache, *cptr, *prevptr;
ad_cache = (struct address_cache *)
malloc(sizeof (struct address_cache));
if (!ad_cache) {
return;
}
ad_cache->ac_host = strdup(host);
ad_cache->ac_netid = strdup(netid);
ad_cache->ac_uaddr = uaddr ? strdup(uaddr) : NULL;
ad_cache->ac_taddr = (struct netbuf *)malloc(sizeof (struct netbuf));
if (!ad_cache->ac_host || !ad_cache->ac_netid || !ad_cache->ac_taddr ||
(uaddr && !ad_cache->ac_uaddr)) {
goto out;
}
ad_cache->ac_taddr->len = ad_cache->ac_taddr->maxlen = taddr->len;
ad_cache->ac_taddr->buf = (char *) malloc(taddr->len);
if (ad_cache->ac_taddr->buf == NULL) {
out:
free(ad_cache->ac_host);
free(ad_cache->ac_netid);
free(ad_cache->ac_uaddr);
free(ad_cache->ac_taddr);
free(ad_cache);
return;
}
memcpy(ad_cache->ac_taddr->buf, taddr->buf, taddr->len);
#ifdef ND_DEBUG
fprintf(stderr, "Added to cache: %s : %s\n", host, netid);
#endif
/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: cptr */
rwlock_wrlock(&rpcbaddr_cache_lock);
if (cachesize < CACHESIZE) {
ad_cache->ac_next = front;
front = ad_cache;
cachesize++;
} else {
/* Free the last entry */
cptr = front;
prevptr = NULL;
while (cptr->ac_next) {
prevptr = cptr;
cptr = cptr->ac_next;
}
#ifdef ND_DEBUG
fprintf(stderr, "Deleted from cache: %s : %s\n",
cptr->ac_host, cptr->ac_netid);
#endif
free(cptr->ac_host);
free(cptr->ac_netid);
free(cptr->ac_taddr->buf);
free(cptr->ac_taddr);
free(cptr->ac_uaddr);
if (prevptr) {
prevptr->ac_next = NULL;
ad_cache->ac_next = front;
front = ad_cache;
} else {
front = ad_cache;
ad_cache->ac_next = NULL;
}
free(cptr);
}
rwlock_unlock(&rpcbaddr_cache_lock);
}
/*
* This routine will return a client handle that is connected to the
* rpcbind. If targaddr is non-NULL, the "universal address" of the
* host will be stored in *targaddr; the caller is responsible for
* freeing this string.
* On error, returns NULL and free's everything.
*/
static CLIENT *
getclnthandle(const char *host, const struct netconfig *nconf, char **targaddr)
{
CLIENT *client;
struct netbuf *addr, taddr;
struct netbuf addr_to_delete;
struct __rpc_sockinfo si;
struct addrinfo hints, *res, *tres;
struct address_cache *ad_cache;
char *tmpaddr;
/* VARIABLES PROTECTED BY rpcbaddr_cache_lock: ad_cache */
/* Get the address of the rpcbind. Check cache first */
client = NULL;
addr_to_delete.len = 0;
rwlock_rdlock(&rpcbaddr_cache_lock);
ad_cache = NULL;
if (host != NULL)
ad_cache = check_cache(host, nconf->nc_netid);
if (ad_cache != NULL) {
addr = ad_cache->ac_taddr;
client = clnt_tli_create(RPC_ANYFD, nconf, addr,
(rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
if (client != NULL) {
if (targaddr)
*targaddr = strdup(ad_cache->ac_uaddr);
rwlock_unlock(&rpcbaddr_cache_lock);
return (client);
}
addr_to_delete.len = addr->len;
addr_to_delete.buf = (char *)malloc(addr->len);
if (addr_to_delete.buf == NULL) {
addr_to_delete.len = 0;
} else {
memcpy(addr_to_delete.buf, addr->buf, addr->len);
}
}
rwlock_unlock(&rpcbaddr_cache_lock);
if (addr_to_delete.len != 0) {
/*
* Assume this may be due to cache data being
* outdated
*/
rwlock_wrlock(&rpcbaddr_cache_lock);
delete_cache(&addr_to_delete);
rwlock_unlock(&rpcbaddr_cache_lock);
free(addr_to_delete.buf);
}
if (!__rpc_nconf2sockinfo(nconf, &si)) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return NULL;
}
memset(&hints, 0, sizeof hints);
hints.ai_family = si.si_af;
hints.ai_socktype = si.si_socktype;
hints.ai_protocol = si.si_proto;
#ifdef CLNT_DEBUG
printf("trying netid %s family %d proto %d socktype %d\n",
nconf->nc_netid, si.si_af, si.si_proto, si.si_socktype);
#endif
if (nconf->nc_protofmly != NULL && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
client = local_rpcb();
if (! client) {
#ifdef ND_DEBUG
clnt_pcreateerror("rpcbind clnt interface");
#endif
return (NULL);
} else {
struct sockaddr_un sun;
if (targaddr) {
*targaddr = malloc(sizeof(sun.sun_path));
if (*targaddr == NULL) {
CLNT_DESTROY(client);
return (NULL);
}
strncpy(*targaddr, _PATH_RPCBINDSOCK,
sizeof(sun.sun_path));
}
return (client);
}
} else {
if (getaddrinfo(host, "sunrpc", &hints, &res) != 0) {
rpc_createerr.cf_stat = RPC_UNKNOWNHOST;
return NULL;
}
}
for (tres = res; tres != NULL; tres = tres->ai_next) {
taddr.buf = tres->ai_addr;
taddr.len = taddr.maxlen = tres->ai_addrlen;
#ifdef ND_DEBUG
{
char *ua;
ua = taddr2uaddr(nconf, &taddr);
fprintf(stderr, "Got it [%s]\n", ua);
free(ua);
}
#endif
#ifdef ND_DEBUG
{
int i;
fprintf(stderr, "\tnetbuf len = %d, maxlen = %d\n",
taddr.len, taddr.maxlen);
fprintf(stderr, "\tAddress is ");
for (i = 0; i < taddr.len; i++)
fprintf(stderr, "%u.", ((char *)(taddr.buf))[i]);
fprintf(stderr, "\n");
}
#endif
client = clnt_tli_create(RPC_ANYFD, nconf, &taddr,
(rpcprog_t)RPCBPROG, (rpcvers_t)RPCBVERS4, 0, 0);
#ifdef ND_DEBUG
if (! client) {
clnt_pcreateerror("rpcbind clnt interface");
}
#endif
if (client) {
tmpaddr = targaddr ? taddr2uaddr(nconf, &taddr) : NULL;
add_cache(host, nconf->nc_netid, &taddr, tmpaddr);
if (targaddr)
*targaddr = tmpaddr;
break;
}
}
if (res)
freeaddrinfo(res);
return (client);
}
/* XXX */
#define IN4_LOCALHOST_STRING "127.0.0.1"
#define IN6_LOCALHOST_STRING "::1"
/*
* This routine will return a client handle that is connected to the local
* rpcbind. Returns NULL on error and free's everything.
*/
static CLIENT *
local_rpcb(void)
{
CLIENT *client;
static struct netconfig *loopnconf;
static char *hostname;
int sock;
size_t tsize;
struct netbuf nbuf;
struct sockaddr_un sun;
/*
* Try connecting to the local rpcbind through a local socket
* first. If this doesn't work, try all transports defined in
* the netconfig file.
*/
memset(&sun, 0, sizeof sun);
sock = _socket(AF_LOCAL, SOCK_STREAM, 0);
if (sock < 0)
goto try_nconf;
sun.sun_family = AF_LOCAL;
strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
nbuf.len = sun.sun_len = SUN_LEN(&sun);
nbuf.maxlen = sizeof (struct sockaddr_un);
nbuf.buf = &sun;
tsize = __rpc_get_t_size(AF_LOCAL, 0, 0);
client = clnt_vc_create(sock, &nbuf, (rpcprog_t)RPCBPROG,
(rpcvers_t)RPCBVERS, tsize, tsize);
if (client != NULL) {
/* Mark the socket to be closed in destructor */
(void) CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL);
return client;
}
/* Nobody needs this socket anymore; free the descriptor. */
_close(sock);
try_nconf:
/* VARIABLES PROTECTED BY loopnconf_lock: loopnconf */
mutex_lock(&loopnconf_lock);
if (loopnconf == NULL) {
struct netconfig *nconf, *tmpnconf = NULL;
void *nc_handle;
int fd;
nc_handle = setnetconfig();
if (nc_handle == NULL) {
/* fails to open netconfig file */
syslog (LOG_ERR, "rpc: failed to open " NETCONFIG);
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
mutex_unlock(&loopnconf_lock);
return (NULL);
}
while ((nconf = getnetconfig(nc_handle)) != NULL) {
#ifdef INET6
if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0 ||
#else
if ((
#endif
strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
(nconf->nc_semantics == NC_TPI_COTS ||
nconf->nc_semantics == NC_TPI_COTS_ORD)) {
fd = __rpc_nconf2fd(nconf);
/*
* Can't create a socket, assume that
* this family isn't configured in the kernel.
*/
if (fd < 0)
continue;
_close(fd);
tmpnconf = nconf;
if (!strcmp(nconf->nc_protofmly, NC_INET))
hostname = IN4_LOCALHOST_STRING;
else
hostname = IN6_LOCALHOST_STRING;
}
}
if (tmpnconf == NULL) {
endnetconfig(nc_handle);
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
mutex_unlock(&loopnconf_lock);
return (NULL);
}
loopnconf = getnetconfigent(tmpnconf->nc_netid);
/* loopnconf is never freed */
endnetconfig(nc_handle);
}
mutex_unlock(&loopnconf_lock);
client = getclnthandle(hostname, loopnconf, NULL);
return (client);
}
/*
* Set a mapping between program, version and address.
* Calls the rpcbind service to do the mapping.
*
* nconf - Network structure of transport
* address - Services netconfig address
*/
bool_t
rpcb_set(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf,
const struct netbuf *address)
{
CLIENT *client;
bool_t rslt = FALSE;
RPCB parms;
char uidbuf[32];
/* parameter checking */
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (FALSE);
}
if (address == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
return (FALSE);
}
client = local_rpcb();
if (! client) {
return (FALSE);
}
/* convert to universal */
/*LINTED const castaway*/
parms.r_addr = taddr2uaddr((struct netconfig *) nconf,
(struct netbuf *)address);
if (!parms.r_addr) {
CLNT_DESTROY(client);
rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
return (FALSE); /* no universal address */
}
parms.r_prog = program;
parms.r_vers = version;
parms.r_netid = nconf->nc_netid;
/*
* Though uid is not being used directly, we still send it for
* completeness. For non-unix platforms, perhaps some other
* string or an empty string can be sent.
*/
(void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
parms.r_owner = uidbuf;
CLNT_CALL(client, (rpcproc_t)RPCBPROC_SET, (xdrproc_t) xdr_rpcb,
(char *)(void *)&parms, (xdrproc_t) xdr_bool,
(char *)(void *)&rslt, tottimeout);
CLNT_DESTROY(client);
free(parms.r_addr);
return (rslt);
}
/*
* Remove the mapping between program, version and netbuf address.
* Calls the rpcbind service to do the un-mapping.
* If netbuf is NULL, unset for all the transports, otherwise unset
* only for the given transport.
*/
bool_t
rpcb_unset(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf)
{
CLIENT *client;
bool_t rslt = FALSE;
RPCB parms;
char uidbuf[32];
client = local_rpcb();
if (! client) {
return (FALSE);
}
parms.r_prog = program;
parms.r_vers = version;
if (nconf)
parms.r_netid = nconf->nc_netid;
else {
/*LINTED const castaway*/
parms.r_netid = (char *) &nullstring[0]; /* unsets all */
}
/*LINTED const castaway*/
parms.r_addr = (char *) &nullstring[0];
(void) snprintf(uidbuf, sizeof uidbuf, "%d", geteuid());
parms.r_owner = uidbuf;
CLNT_CALL(client, (rpcproc_t)RPCBPROC_UNSET, (xdrproc_t) xdr_rpcb,
(char *)(void *)&parms, (xdrproc_t) xdr_bool,
(char *)(void *)&rslt, tottimeout);
CLNT_DESTROY(client);
return (rslt);
}
/*
* From the merged list, find the appropriate entry
*/
static struct netbuf *
got_entry(rpcb_entry_list_ptr relp, const struct netconfig *nconf)
{
struct netbuf *na = NULL;
rpcb_entry_list_ptr sp;
rpcb_entry *rmap;
for (sp = relp; sp != NULL; sp = sp->rpcb_entry_next) {
rmap = &sp->rpcb_entry_map;
if ((strcmp(nconf->nc_proto, rmap->r_nc_proto) == 0) &&
(strcmp(nconf->nc_protofmly, rmap->r_nc_protofmly) == 0) &&
(nconf->nc_semantics == rmap->r_nc_semantics) &&
(rmap->r_maddr != NULL) && (rmap->r_maddr[0] != 0)) {
na = uaddr2taddr(nconf, rmap->r_maddr);
#ifdef ND_DEBUG
fprintf(stderr, "\tRemote address is [%s].\n",
rmap->r_maddr);
if (!na)
fprintf(stderr,
"\tCouldn't resolve remote address!\n");
#endif
break;
}
}
return (na);
}
/*
* Quick check to see if rpcbind is up. Tries to connect over
* local transport.
*/
static bool_t
__rpcbind_is_up(void)
{
struct netconfig *nconf;
struct sockaddr_un sun;
void *localhandle;
int sock;
nconf = NULL;
localhandle = setnetconfig();
while ((nconf = getnetconfig(localhandle)) != NULL) {
if (nconf->nc_protofmly != NULL &&
strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0)
break;
}
endnetconfig(localhandle);
if (nconf == NULL)
return (FALSE);
memset(&sun, 0, sizeof sun);
sock = _socket(AF_LOCAL, SOCK_STREAM, 0);
if (sock < 0)
return (FALSE);
sun.sun_family = AF_LOCAL;
strncpy(sun.sun_path, _PATH_RPCBINDSOCK, sizeof(sun.sun_path));
sun.sun_len = SUN_LEN(&sun);
if (_connect(sock, (struct sockaddr *)&sun, sun.sun_len) < 0) {
_close(sock);
return (FALSE);
}
_close(sock);
return (TRUE);
}
/*
* An internal function which optimizes rpcb_getaddr function. It also
* returns the client handle that it uses to contact the remote rpcbind.
*
* The algorithm used: If the transports is TCP or UDP, it first tries
* version 2 (portmap), 4 and then 3 (svr4). This order should be
* changed in the next OS release to 4, 2 and 3. We are assuming that by
* that time, version 4 would be available on many machines on the network.
* With this algorithm, we get performance as well as a plan for
* obsoleting version 2.
*
* For all other transports, the algorithm remains as 4 and then 3.
*
* XXX: Due to some problems with t_connect(), we do not reuse the same client
* handle for COTS cases and hence in these cases we do not return the
* client handle. This code will change if t_connect() ever
* starts working properly. Also look under clnt_vc.c.
*/
struct netbuf *
__rpcb_findaddr_timed(rpcprog_t program, rpcvers_t version,
const struct netconfig *nconf, const char *host,
CLIENT **clpp, struct timeval *tp)
{
static bool_t check_rpcbind = TRUE;
CLIENT *client = NULL;
RPCB parms;
enum clnt_stat clnt_st;
char *ua = NULL;
rpcvers_t vers;
struct netbuf *address = NULL;
rpcvers_t start_vers = RPCBVERS4;
struct netbuf servaddr;
/* parameter checking */
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
parms.r_addr = NULL;
/*
* Use default total timeout if no timeout is specified.
*/
if (tp == NULL)
tp = &tottimeout;
#ifdef PORTMAP
/* Try version 2 for TCP or UDP */
if (strcmp(nconf->nc_protofmly, NC_INET) == 0) {
u_short port = 0;
struct netbuf remote;
rpcvers_t pmapvers = 2;
struct pmap pmapparms;
/*
* The comment below is now very old, having
* been committed to FreeBSD during an import
* from NetBSD in 2001. I do not believe there
* will still be any rpcbind servers that do
* UDP only and, since Azure requires use of
* TCP for NFSv3 mounts, comment this out
* so that NFSv3 mounts on Azure can work.
*/
#ifdef notnow
/*
* Try UDP only - there are some portmappers out
* there that use UDP only.
*/
if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
struct netconfig *newnconf;
if ((newnconf = getnetconfigent("udp")) == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
client = getclnthandle(host, newnconf, &parms.r_addr);
freenetconfigent(newnconf);
} else
#endif
client = getclnthandle(host, nconf, &parms.r_addr);
if (client == NULL)
return (NULL);
/*
* Set version and retry timeout.
*/
CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
CLNT_CONTROL(client, CLSET_VERS, (char *)&pmapvers);
pmapparms.pm_prog = program;
pmapparms.pm_vers = version;
pmapparms.pm_prot = strcmp(nconf->nc_proto, NC_TCP) ?
IPPROTO_UDP : IPPROTO_TCP;
pmapparms.pm_port = 0; /* not needed */
clnt_st = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT,
(xdrproc_t) xdr_pmap, (caddr_t)(void *)&pmapparms,
(xdrproc_t) xdr_u_short, (caddr_t)(void *)&port,
*tp);
if (clnt_st != RPC_SUCCESS) {
if ((clnt_st == RPC_PROGVERSMISMATCH) ||
(clnt_st == RPC_PROGUNAVAIL))
goto try_rpcbind; /* Try different versions */
rpc_createerr.cf_stat = RPC_PMAPFAILURE;
clnt_geterr(client, &rpc_createerr.cf_error);
goto error;
} else if (port == 0) {
address = NULL;
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
goto error;
}
port = htons(port);
CLNT_CONTROL(client, CLGET_SVC_ADDR, (char *)&remote);
if (((address = (struct netbuf *)
malloc(sizeof (struct netbuf))) == NULL) ||
((address->buf = (char *)
malloc(remote.len)) == NULL)) {
rpc_createerr.cf_stat = RPC_SYSTEMERROR;
clnt_geterr(client, &rpc_createerr.cf_error);
free(address);
address = NULL;
goto error;
}
memcpy(address->buf, remote.buf, remote.len);
memcpy(&((char *)address->buf)[sizeof (short)],
(char *)(void *)&port, sizeof (short));
address->len = address->maxlen = remote.len;
goto done;
}
#endif /* PORTMAP */
try_rpcbind:
/*
* Check if rpcbind is up. This prevents needless delays when
* accessing applications such as the keyserver while booting
* disklessly.
*/
if (check_rpcbind && strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
if (!__rpcbind_is_up()) {
rpc_createerr.cf_stat = RPC_PMAPFAILURE;
rpc_createerr.cf_error.re_errno = 0;
goto error;
}
check_rpcbind = FALSE;
}
/*
* Now we try version 4 and then 3.
* We also send the remote system the address we used to
* contact it in case it can help to connect back with us
*/
parms.r_prog = program;
parms.r_vers = version;
/*LINTED const castaway*/
parms.r_owner = (char *) &nullstring[0]; /* not needed; */
/* just for xdring */
parms.r_netid = nconf->nc_netid; /* not really needed */
/*
* If a COTS transport is being used, try getting address via CLTS
* transport. This works only with version 4.
*/
if (nconf->nc_semantics == NC_TPI_COTS_ORD ||
nconf->nc_semantics == NC_TPI_COTS) {
void *handle;
struct netconfig *nconf_clts;
rpcb_entry_list_ptr relp = NULL;
if (client == NULL) {
/* This did not go through the above PORTMAP/TCP code */
if ((handle = __rpc_setconf("datagram_v")) != NULL) {
while ((nconf_clts = __rpc_getconf(handle))
!= NULL) {
if (strcmp(nconf_clts->nc_protofmly,
nconf->nc_protofmly) != 0) {
continue;
}
client = getclnthandle(host, nconf_clts,
&parms.r_addr);
break;
}
__rpc_endconf(handle);
}
if (client == NULL)
goto regular_rpcbind; /* Go the regular way */
} else {
/* This is a UDP PORTMAP handle. Change to version 4 */
vers = RPCBVERS4;
CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
}
/*
* We also send the remote system the address we used to
* contact it in case it can help it connect back with us
*/
if (parms.r_addr == NULL) {
/*LINTED const castaway*/
parms.r_addr = (char *) &nullstring[0]; /* for XDRing */
}
CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)&rpcbrmttime);
clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDRLIST,
(xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
(xdrproc_t) xdr_rpcb_entry_list_ptr,
(char *)(void *)&relp, *tp);
if (clnt_st == RPC_SUCCESS) {
if ((address = got_entry(relp, nconf)) != NULL) {
xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
(char *)(void *)&relp);
CLNT_CONTROL(client, CLGET_SVC_ADDR,
(char *)(void *)&servaddr);
__rpc_fixup_addr(address, &servaddr);
goto done;
}
/* Entry not found for this transport */
xdr_free((xdrproc_t) xdr_rpcb_entry_list_ptr,
(char *)(void *)&relp);
/*
* XXX: should have perhaps returned with error but
* since the remote machine might not always be able
* to send the address on all transports, we try the
* regular way with regular_rpcbind
*/
goto regular_rpcbind;
} else if ((clnt_st == RPC_PROGVERSMISMATCH) ||
(clnt_st == RPC_PROGUNAVAIL)) {
start_vers = RPCBVERS; /* Try version 3 now */
goto regular_rpcbind; /* Try different versions */
} else {
rpc_createerr.cf_stat = RPC_PMAPFAILURE;
clnt_geterr(client, &rpc_createerr.cf_error);
goto error;
}
}
regular_rpcbind:
/* Now the same transport is to be used to get the address */
if (client && ((nconf->nc_semantics == NC_TPI_COTS_ORD) ||
(nconf->nc_semantics == NC_TPI_COTS))) {
/* A CLTS type of client - destroy it */
CLNT_DESTROY(client);
client = NULL;
}
if (client == NULL) {
client = getclnthandle(host, nconf, &parms.r_addr);
if (client == NULL) {
goto error;
}
}
if (parms.r_addr == NULL) {
/*LINTED const castaway*/
parms.r_addr = (char *) &nullstring[0];
}
/* First try from start_vers and then version 3 (RPCBVERS) */
CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *) &rpcbrmttime);
for (vers = start_vers; vers >= RPCBVERS; vers--) {
/* Set the version */
CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR,
(xdrproc_t) xdr_rpcb, (char *)(void *)&parms,
(xdrproc_t) xdr_wrapstring, (char *)(void *) &ua, *tp);
if (clnt_st == RPC_SUCCESS) {
if ((ua == NULL) || (ua[0] == 0)) {
/* address unknown */
rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED;
goto error;
}
address = uaddr2taddr(nconf, ua);
#ifdef ND_DEBUG
fprintf(stderr, "\tRemote address is [%s]\n", ua);
if (!address)
fprintf(stderr,
"\tCouldn't resolve remote address!\n");
#endif
xdr_free((xdrproc_t)xdr_wrapstring,
(char *)(void *)&ua);
if (! address) {
/* We don't know about your universal address */
rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE;
goto error;
}
CLNT_CONTROL(client, CLGET_SVC_ADDR,
(char *)(void *)&servaddr);
__rpc_fixup_addr(address, &servaddr);
goto done;
} else if (clnt_st == RPC_PROGVERSMISMATCH) {
struct rpc_err rpcerr;
clnt_geterr(client, &rpcerr);
if (rpcerr.re_vers.low > RPCBVERS4)
goto error; /* a new version, can't handle */
} else if (clnt_st != RPC_PROGUNAVAIL) {
/* Cant handle this error */
rpc_createerr.cf_stat = clnt_st;
clnt_geterr(client, &rpc_createerr.cf_error);
goto error;
}
}
error:
if (client) {
CLNT_DESTROY(client);
client = NULL;
}
done:
if (nconf->nc_semantics != NC_TPI_CLTS) {
/* This client is the connectionless one */
if (client) {
CLNT_DESTROY(client);
client = NULL;
}
}
if (clpp) {
*clpp = client;
} else if (client) {
CLNT_DESTROY(client);
}
if (parms.r_addr != NULL && parms.r_addr != nullstring)
free(parms.r_addr);
return (address);
}
/*
* Find the mapped address for program, version.
* Calls the rpcbind service remotely to do the lookup.
* Uses the transport specified in nconf.
* Returns FALSE (0) if no map exists, else returns 1.
*
* Assuming that the address is all properly allocated
*/
bool_t
rpcb_getaddr(rpcprog_t program, rpcvers_t version, const struct netconfig *nconf,
struct netbuf *address, const char *host)
{
struct netbuf *na;
if ((na = __rpcb_findaddr_timed(program, version,
(struct netconfig *) nconf, (char *) host,
(CLIENT **) NULL, (struct timeval *) NULL)) == NULL)
return (FALSE);
if (na->len > address->maxlen) {
/* Too long address */
free(na->buf);
free(na);
rpc_createerr.cf_stat = RPC_FAILED;
return (FALSE);
}
memcpy(address->buf, na->buf, (size_t)na->len);
address->len = na->len;
free(na->buf);
free(na);
return (TRUE);
}
/*
* Get a copy of the current maps.
* Calls the rpcbind service remotely to get the maps.
*
* It returns only a list of the services
* It returns NULL on failure.
*/
rpcblist *
rpcb_getmaps(const struct netconfig *nconf, const char *host)
{
rpcblist_ptr head = NULL;
CLIENT *client;
enum clnt_stat clnt_st;
rpcvers_t vers = 0;
client = getclnthandle(host, nconf, NULL);
if (client == NULL) {
return (head);
}
clnt_st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
(xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
(char *)(void *)&head, tottimeout);
if (clnt_st == RPC_SUCCESS)
goto done;
if ((clnt_st != RPC_PROGVERSMISMATCH) &&
(clnt_st != RPC_PROGUNAVAIL)) {
rpc_createerr.cf_stat = RPC_RPCBFAILURE;
clnt_geterr(client, &rpc_createerr.cf_error);
goto done;
}
/* fall back to earlier version */
CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
if (vers == RPCBVERS4) {
vers = RPCBVERS;
CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_DUMP,
(xdrproc_t) xdr_void, NULL, (xdrproc_t) xdr_rpcblist_ptr,
(char *)(void *)&head, tottimeout) == RPC_SUCCESS)
goto done;
}
rpc_createerr.cf_stat = RPC_RPCBFAILURE;
clnt_geterr(client, &rpc_createerr.cf_error);
done:
CLNT_DESTROY(client);
return (head);
}
/*
* rpcbinder remote-call-service interface.
* This routine is used to call the rpcbind remote call service
* which will look up a service program in the address maps, and then
* remotely call that routine with the given parameters. This allows
* programs to do a lookup and call in one step.
*
* nconf -Netconfig structure
* host - Remote host name
* proc - Remote proc identifiers
* xdrargs, xdrres; XDR routines
* argsp, resp - Argument and Result
* tout - Timeout value for this call
* addr_ptr - Preallocated netbuf address
*/
enum clnt_stat
rpcb_rmtcall(const struct netconfig *nconf, const char *host, rpcprog_t prog,
rpcvers_t vers, rpcproc_t proc, xdrproc_t xdrargs, caddr_t argsp,
xdrproc_t xdrres, caddr_t resp, struct timeval tout,
const struct netbuf *addr_ptr)
{
CLIENT *client;
enum clnt_stat stat;
struct r_rpcb_rmtcallargs a;
struct r_rpcb_rmtcallres r;
rpcvers_t rpcb_vers;
stat = 0;
client = getclnthandle(host, nconf, NULL);
if (client == NULL) {
return (RPC_FAILED);
}
/*LINTED const castaway*/
CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, (char *)(void *)&rmttimeout);
a.prog = prog;
a.vers = vers;
a.proc = proc;
a.args.args_val = argsp;
a.xdr_args = xdrargs;
r.addr = NULL;
r.results.results_val = resp;
r.xdr_res = xdrres;
for (rpcb_vers = RPCBVERS4; rpcb_vers >= RPCBVERS; rpcb_vers--) {
CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&rpcb_vers);
stat = CLNT_CALL(client, (rpcproc_t)RPCBPROC_CALLIT,
(xdrproc_t) xdr_rpcb_rmtcallargs, (char *)(void *)&a,
(xdrproc_t) xdr_rpcb_rmtcallres, (char *)(void *)&r, tout);
if ((stat == RPC_SUCCESS) && (addr_ptr != NULL)) {
struct netbuf *na;
/*LINTED const castaway*/
na = uaddr2taddr((struct netconfig *) nconf, r.addr);
if (!na) {
stat = RPC_N2AXLATEFAILURE;
/*LINTED const castaway*/
((struct netbuf *) addr_ptr)->len = 0;
goto error;
}
if (na->len > addr_ptr->maxlen) {
/* Too long address */
stat = RPC_FAILED; /* XXX A better error no */
free(na->buf);
free(na);
/*LINTED const castaway*/
((struct netbuf *) addr_ptr)->len = 0;
goto error;
}
memcpy(addr_ptr->buf, na->buf, (size_t)na->len);
/*LINTED const castaway*/
((struct netbuf *)addr_ptr)->len = na->len;
free(na->buf);
free(na);
break;
} else if ((stat != RPC_PROGVERSMISMATCH) &&
(stat != RPC_PROGUNAVAIL)) {
goto error;
}
}
error:
CLNT_DESTROY(client);
if (r.addr)
xdr_free((xdrproc_t) xdr_wrapstring, (char *)(void *)&r.addr);
return (stat);
}
/*
* Gets the time on the remote host.
* Returns 1 if succeeds else 0.
*/
bool_t
rpcb_gettime(const char *host, time_t *timep)
{
CLIENT *client = NULL;
void *handle;
struct netconfig *nconf;
rpcvers_t vers;
enum clnt_stat st;
if ((host == NULL) || (host[0] == 0)) {
time(timep);
return (TRUE);
}
if ((handle = __rpc_setconf("netpath")) == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (FALSE);
}
rpc_createerr.cf_stat = RPC_SUCCESS;
while (client == NULL) {
if ((nconf = __rpc_getconf(handle)) == NULL) {
if (rpc_createerr.cf_stat == RPC_SUCCESS)
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
break;
}
client = getclnthandle(host, nconf, NULL);
if (client)
break;
}
__rpc_endconf(handle);
if (client == (CLIENT *) NULL) {
return (FALSE);
}
st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
(xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_int, (char *)(void *)timep, tottimeout);
if ((st == RPC_PROGVERSMISMATCH) || (st == RPC_PROGUNAVAIL)) {
CLNT_CONTROL(client, CLGET_VERS, (char *)(void *)&vers);
if (vers == RPCBVERS4) {
/* fall back to earlier version */
vers = RPCBVERS;
CLNT_CONTROL(client, CLSET_VERS, (char *)(void *)&vers);
st = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETTIME,
(xdrproc_t) xdr_void, NULL,
(xdrproc_t) xdr_int, (char *)(void *)timep,
tottimeout);
}
}
CLNT_DESTROY(client);
return (st == RPC_SUCCESS? TRUE: FALSE);
}
/*
* Converts taddr to universal address. This routine should never
* really be called because local n2a libraries are always provided.
*/
char *
rpcb_taddr2uaddr(struct netconfig *nconf, struct netbuf *taddr)
{
CLIENT *client;
char *uaddr = NULL;
/* parameter checking */
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
if (taddr == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
return (NULL);
}
client = local_rpcb();
if (! client) {
return (NULL);
}
CLNT_CALL(client, (rpcproc_t)RPCBPROC_TADDR2UADDR,
(xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
(xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr, tottimeout);
CLNT_DESTROY(client);
return (uaddr);
}
/*
* Converts universal address to netbuf. This routine should never
* really be called because local n2a libraries are always provided.
*/
struct netbuf *
rpcb_uaddr2taddr(struct netconfig *nconf, char *uaddr)
{
CLIENT *client;
struct netbuf *taddr;
/* parameter checking */
if (nconf == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNPROTO;
return (NULL);
}
if (uaddr == NULL) {
rpc_createerr.cf_stat = RPC_UNKNOWNADDR;
return (NULL);
}
client = local_rpcb();
if (! client) {
return (NULL);
}
taddr = (struct netbuf *)calloc(1, sizeof (struct netbuf));
if (taddr == NULL) {
CLNT_DESTROY(client);
return (NULL);
}
if (CLNT_CALL(client, (rpcproc_t)RPCBPROC_UADDR2TADDR,
(xdrproc_t) xdr_wrapstring, (char *)(void *)&uaddr,
(xdrproc_t) xdr_netbuf, (char *)(void *)taddr,
tottimeout) != RPC_SUCCESS) {
free(taddr);
taddr = NULL;
}
CLNT_DESTROY(client);
return (taddr);
}
diff --git a/lib/libc/rpc/rpcb_prot.c b/lib/libc/rpc/rpcb_prot.c
index 088d2493bd80..5c550e46b254 100644
--- a/lib/libc/rpc/rpcb_prot.c
+++ b/lib/libc/rpc/rpcb_prot.c
@@ -1,316 +1,315 @@
/* $NetBSD: rpcb_prot.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
/* #ident "@(#)rpcb_prot.c 1.13 94/04/24 SMI" */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rpcb_prot.c 1.9 89/04/21 Copyr 1984 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* rpcb_prot.c
* XDR routines for the rpcbinder version 3.
*
* Copyright (C) 1984, 1988, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <rpc/rpc.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/rpcb_prot.h>
#include <rpc/rpc_com.h>
#include "un-namespace.h"
bool_t
xdr_rpcb(XDR *xdrs, RPCB *objp)
{
if (!xdr_rpcprog(xdrs, &objp->r_prog)) {
return (FALSE);
}
if (!xdr_rpcvers(xdrs, &objp->r_vers)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_addr, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_owner, RPC_MAXDATASIZE)) {
return (FALSE);
}
return (TRUE);
}
/*
* rpcblist_ptr implements a linked list. The RPCL definition from
* rpcb_prot.x is:
*
* struct rpcblist {
* rpcb rpcb_map;
* struct rpcblist *rpcb_next;
* };
* typedef rpcblist *rpcblist_ptr;
*
* Recall that "pointers" in XDR are encoded as a boolean, indicating whether
* there's any data behind the pointer, followed by the data (if any exists).
* The boolean can be interpreted as ``more data follows me''; if FALSE then
* nothing follows the boolean; if TRUE then the boolean is followed by an
* actual struct rpcb, and another rpcblist_ptr (declared in RPCL as "struct
* rpcblist *").
*
* This could be implemented via the xdr_pointer type, though this would
* result in one recursive call per element in the list. Rather than do that
* we can ``unwind'' the recursion into a while loop and use xdr_reference to
* serialize the rpcb elements.
*/
bool_t
xdr_rpcblist_ptr(XDR *xdrs, rpcblist_ptr *rp)
{
/*
* more_elements is pre-computed in case the direction is
* XDR_ENCODE or XDR_FREE. more_elements is overwritten by
* xdr_bool when the direction is XDR_DECODE.
*/
bool_t more_elements;
int freeing = (xdrs->x_op == XDR_FREE);
rpcblist_ptr next;
rpcblist_ptr next_copy;
next = NULL;
for (;;) {
more_elements = (bool_t)(*rp != NULL);
if (! xdr_bool(xdrs, &more_elements)) {
return (FALSE);
}
if (! more_elements) {
return (TRUE); /* we are done */
}
/*
* the unfortunate side effect of non-recursion is that in
* the case of freeing we must remember the next object
* before we free the current object ...
*/
if (freeing && *rp)
next = (*rp)->rpcb_next;
if (! xdr_reference(xdrs, (caddr_t *)rp,
(u_int)sizeof (rpcblist), (xdrproc_t)xdr_rpcb)) {
return (FALSE);
}
if (freeing) {
next_copy = next;
rp = &next_copy;
/*
* Note that in the subsequent iteration, next_copy
* gets nulled out by the xdr_reference
* but next itself survives.
*/
} else if (*rp) {
rp = &((*rp)->rpcb_next);
}
}
/*NOTREACHED*/
}
/*
* xdr_rpcblist() is specified to take a RPCBLIST **, but is identical in
* functionality to xdr_rpcblist_ptr().
*/
bool_t
xdr_rpcblist(XDR *xdrs, RPCBLIST **rp)
{
bool_t dummy;
dummy = xdr_rpcblist_ptr(xdrs, (rpcblist_ptr *)rp);
return (dummy);
}
bool_t
xdr_rpcb_entry(XDR *xdrs, rpcb_entry *objp)
{
if (!xdr_string(xdrs, &objp->r_maddr, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_nc_netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_u_int32_t(xdrs, &objp->r_nc_semantics)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_nc_protofmly, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->r_nc_proto, RPC_MAXDATASIZE)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_rpcb_entry_list_ptr(XDR *xdrs, rpcb_entry_list_ptr *rp)
{
/*
* more_elements is pre-computed in case the direction is
* XDR_ENCODE or XDR_FREE. more_elements is overwritten by
* xdr_bool when the direction is XDR_DECODE.
*/
bool_t more_elements;
int freeing = (xdrs->x_op == XDR_FREE);
rpcb_entry_list_ptr next;
rpcb_entry_list_ptr next_copy;
next = NULL;
for (;;) {
more_elements = (bool_t)(*rp != NULL);
if (! xdr_bool(xdrs, &more_elements)) {
return (FALSE);
}
if (! more_elements) {
return (TRUE); /* we are done */
}
/*
* the unfortunate side effect of non-recursion is that in
* the case of freeing we must remember the next object
* before we free the current object ...
*/
if (freeing && *rp)
next = (*rp)->rpcb_entry_next;
if (! xdr_reference(xdrs, (caddr_t *)rp,
(u_int)sizeof (rpcb_entry_list),
(xdrproc_t)xdr_rpcb_entry)) {
return (FALSE);
}
if (freeing) {
next_copy = next;
rp = &next_copy;
/*
* Note that in the subsequent iteration, next_copy
* gets nulled out by the xdr_reference
* but next itself survives.
*/
} else if (*rp) {
rp = &((*rp)->rpcb_entry_next);
}
}
/*NOTREACHED*/
}
/*
* XDR remote call arguments
* written for XDR_ENCODE direction only
*/
bool_t
xdr_rpcb_rmtcallargs(XDR *xdrs, struct rpcb_rmtcallargs *p)
{
struct r_rpcb_rmtcallargs *objp =
(struct r_rpcb_rmtcallargs *)(void *)p;
u_int lenposition, argposition, position;
int32_t *buf;
buf = XDR_INLINE(xdrs, 3 * BYTES_PER_XDR_UNIT);
if (buf == NULL) {
if (!xdr_rpcprog(xdrs, &objp->prog)) {
return (FALSE);
}
if (!xdr_rpcvers(xdrs, &objp->vers)) {
return (FALSE);
}
if (!xdr_rpcproc(xdrs, &objp->proc)) {
return (FALSE);
}
} else {
IXDR_PUT_U_INT32(buf, objp->prog);
IXDR_PUT_U_INT32(buf, objp->vers);
IXDR_PUT_U_INT32(buf, objp->proc);
}
/*
* All the jugglery for just getting the size of the arguments
*/
lenposition = XDR_GETPOS(xdrs);
if (! xdr_u_int(xdrs, &(objp->args.args_len))) {
return (FALSE);
}
argposition = XDR_GETPOS(xdrs);
if (! (*objp->xdr_args)(xdrs, objp->args.args_val)) {
return (FALSE);
}
position = XDR_GETPOS(xdrs);
objp->args.args_len = (u_int)((u_long)position - (u_long)argposition);
XDR_SETPOS(xdrs, lenposition);
if (! xdr_u_int(xdrs, &(objp->args.args_len))) {
return (FALSE);
}
XDR_SETPOS(xdrs, position);
return (TRUE);
}
/*
* XDR remote call results
* written for XDR_DECODE direction only
*/
bool_t
xdr_rpcb_rmtcallres(XDR *xdrs, struct rpcb_rmtcallres *p)
{
bool_t dummy;
struct r_rpcb_rmtcallres *objp = (struct r_rpcb_rmtcallres *)(void *)p;
if (!xdr_string(xdrs, &objp->addr, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_u_int(xdrs, &objp->results.results_len)) {
return (FALSE);
}
dummy = (*(objp->xdr_res))(xdrs, objp->results.results_val);
return (dummy);
}
bool_t
xdr_netbuf(XDR *xdrs, struct netbuf *objp)
{
bool_t dummy;
void **pp;
if (!xdr_u_int32_t(xdrs, (u_int32_t *) &objp->maxlen)) {
return (FALSE);
}
pp = &objp->buf;
dummy = xdr_bytes(xdrs, (char **) pp,
(u_int *)&(objp->len), objp->maxlen);
return (dummy);
}
diff --git a/lib/libc/rpc/rpcb_st_xdr.c b/lib/libc/rpc/rpcb_st_xdr.c
index 5791681b812c..ece2f284a980 100644
--- a/lib/libc/rpc/rpcb_st_xdr.c
+++ b/lib/libc/rpc/rpcb_st_xdr.c
@@ -1,260 +1,259 @@
/* $NetBSD: rpcb_st_xdr.c,v 1.3 2000/07/14 08:40:42 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright 1991 Sun Microsystems, Inc.
* rpcb_stat_xdr.c
*/
/*
* This file was generated from rpcb_prot.x, but includes only those
* routines used with the rpcbind stats facility.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include "un-namespace.h"
/* Link list of all the stats about getport and getaddr */
bool_t
xdr_rpcbs_addrlist(XDR *xdrs, rpcbs_addrlist *objp)
{
struct rpcbs_addrlist **pnext;
if (!xdr_rpcprog(xdrs, &objp->prog)) {
return (FALSE);
}
if (!xdr_rpcvers(xdrs, &objp->vers)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->success)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->failure)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
pnext = &objp->next;
if (!xdr_pointer(xdrs, (char **) pnext,
sizeof (rpcbs_addrlist),
(xdrproc_t)xdr_rpcbs_addrlist)) {
return (FALSE);
}
return (TRUE);
}
/* Link list of all the stats about rmtcall */
bool_t
xdr_rpcbs_rmtcalllist(XDR *xdrs, rpcbs_rmtcalllist *objp)
{
struct rpcbs_rmtcalllist **pnext;
int32_t *buf;
pnext = &objp->next;
if (xdrs->x_op == XDR_ENCODE) {
buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
if (buf == NULL) {
if (!xdr_rpcprog(xdrs, &objp->prog)) {
return (FALSE);
}
if (!xdr_rpcvers(xdrs, &objp->vers)) {
return (FALSE);
}
if (!xdr_rpcproc(xdrs, &objp->proc)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->success)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->failure)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->indirect)) {
return (FALSE);
}
} else {
IXDR_PUT_U_INT32(buf, objp->prog);
IXDR_PUT_U_INT32(buf, objp->vers);
IXDR_PUT_U_INT32(buf, objp->proc);
IXDR_PUT_INT32(buf, objp->success);
IXDR_PUT_INT32(buf, objp->failure);
IXDR_PUT_INT32(buf, objp->indirect);
}
if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_pointer(xdrs, (char **) pnext,
sizeof (rpcbs_rmtcalllist),
(xdrproc_t)xdr_rpcbs_rmtcalllist)) {
return (FALSE);
}
return (TRUE);
} else if (xdrs->x_op == XDR_DECODE) {
buf = XDR_INLINE(xdrs, 6 * BYTES_PER_XDR_UNIT);
if (buf == NULL) {
if (!xdr_rpcprog(xdrs, &objp->prog)) {
return (FALSE);
}
if (!xdr_rpcvers(xdrs, &objp->vers)) {
return (FALSE);
}
if (!xdr_rpcproc(xdrs, &objp->proc)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->success)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->failure)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->indirect)) {
return (FALSE);
}
} else {
objp->prog = (rpcprog_t)IXDR_GET_U_INT32(buf);
objp->vers = (rpcvers_t)IXDR_GET_U_INT32(buf);
objp->proc = (rpcproc_t)IXDR_GET_U_INT32(buf);
objp->success = (int)IXDR_GET_INT32(buf);
objp->failure = (int)IXDR_GET_INT32(buf);
objp->indirect = (int)IXDR_GET_INT32(buf);
}
if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_pointer(xdrs, (char **) pnext,
sizeof (rpcbs_rmtcalllist),
(xdrproc_t)xdr_rpcbs_rmtcalllist)) {
return (FALSE);
}
return (TRUE);
}
if (!xdr_rpcprog(xdrs, &objp->prog)) {
return (FALSE);
}
if (!xdr_rpcvers(xdrs, &objp->vers)) {
return (FALSE);
}
if (!xdr_rpcproc(xdrs, &objp->proc)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->success)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->failure)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->indirect)) {
return (FALSE);
}
if (!xdr_string(xdrs, &objp->netid, RPC_MAXDATASIZE)) {
return (FALSE);
}
if (!xdr_pointer(xdrs, (char **) pnext,
sizeof (rpcbs_rmtcalllist),
(xdrproc_t)xdr_rpcbs_rmtcalllist)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_rpcbs_proc(XDR *xdrs, rpcbs_proc objp)
{
if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBSTAT_HIGHPROC,
sizeof (int), (xdrproc_t)xdr_int)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_rpcbs_addrlist_ptr(XDR *xdrs, rpcbs_addrlist_ptr *objp)
{
if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_addrlist),
(xdrproc_t)xdr_rpcbs_addrlist)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_rpcbs_rmtcalllist_ptr(XDR *xdrs, rpcbs_rmtcalllist_ptr *objp)
{
if (!xdr_pointer(xdrs, (char **)objp, sizeof (rpcbs_rmtcalllist),
(xdrproc_t)xdr_rpcbs_rmtcalllist)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_rpcb_stat(XDR *xdrs, rpcb_stat *objp)
{
if (!xdr_rpcbs_proc(xdrs, objp->info)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->setinfo)) {
return (FALSE);
}
if (!xdr_int(xdrs, &objp->unsetinfo)) {
return (FALSE);
}
if (!xdr_rpcbs_addrlist_ptr(xdrs, &objp->addrinfo)) {
return (FALSE);
}
if (!xdr_rpcbs_rmtcalllist_ptr(xdrs, &objp->rmtinfo)) {
return (FALSE);
}
return (TRUE);
}
/*
* One rpcb_stat structure is returned for each version of rpcbind
* being monitored.
*/
bool_t
xdr_rpcb_stat_byvers(XDR *xdrs, rpcb_stat_byvers objp)
{
if (!xdr_vector(xdrs, (char *)(void *)objp, RPCBVERS_STAT,
sizeof (rpcb_stat), (xdrproc_t)xdr_rpcb_stat)) {
return (FALSE);
}
return (TRUE);
}
diff --git a/lib/libc/rpc/rpcdname.c b/lib/libc/rpc/rpcdname.c
index 970588d01430..fa9335b5d252 100644
--- a/lib/libc/rpc/rpcdname.c
+++ b/lib/libc/rpc/rpcdname.c
@@ -1,79 +1,78 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rpcdname.c 1.7 91/03/11 Copyr 1989 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* rpcdname.c
* Gets the default domain name
*/
#include "namespace.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "un-namespace.h"
static char *default_domain;
static char *
get_default_domain(void)
{
char temp[256];
if (default_domain != NULL)
return (default_domain);
if (getdomainname(temp, sizeof(temp)) < 0)
return (0);
if ((int) strlen(temp) > 0) {
default_domain = malloc((strlen(temp) + (unsigned)1));
if (default_domain == NULL)
return (0);
(void) strcpy(default_domain, temp);
return (default_domain);
}
return (0);
}
/*
* This is a wrapper for the system call getdomainname which returns a
* ypclnt.h error code in the failure case. It also checks to see that
* the domain name is non-null, knowing that the null string is going to
* get rejected elsewhere in the NIS client package.
*/
int
__rpc_get_default_domain(char **domain)
{
if ((*domain = get_default_domain()) != NULL)
return (0);
return (-1);
}
diff --git a/lib/libc/rpc/rtime.c b/lib/libc/rpc/rtime.c
index 673751c8a03b..81e19a45fb23 100644
--- a/lib/libc/rpc/rtime.c
+++ b/lib/libc/rpc/rtime.c
@@ -1,156 +1,155 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*
* rtime - get time from remote machine
*
* gets time, obtaining value from host
* on the udp/time socket. Since timeserver returns
* with time of day in seconds since Jan 1, 1900, must
* subtract seconds before Jan 1, 1970 to get
* what unix uses.
*/
#include "namespace.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <stdio.h>
#include <netdb.h>
#include "un-namespace.h"
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rtime.c 2.2 88/08/10 4.0 RPCSRC; from 1.8 88/02/08 SMI";
#endif
-#include <sys/cdefs.h>
extern int _rpc_dtablesize( void );
#define NYEARS (unsigned long)(1970 - 1900)
#define TOFFSET (unsigned long)(60*60*24*(365*NYEARS + (NYEARS/4)))
static void do_close( int );
int
rtime(struct sockaddr_in *addrp, struct timeval *timep,
struct timeval *timeout)
{
int s;
fd_set readfds;
int res;
unsigned long thetime;
struct sockaddr_in from;
socklen_t fromlen;
int type;
struct servent *serv;
if (timeout == NULL) {
type = SOCK_STREAM;
} else {
type = SOCK_DGRAM;
}
s = _socket(AF_INET, type, 0);
if (s < 0) {
return(-1);
}
addrp->sin_family = AF_INET;
/* TCP and UDP port are the same in this case */
if ((serv = getservbyname("time", "tcp")) == NULL) {
return(-1);
}
addrp->sin_port = serv->s_port;
if (type == SOCK_DGRAM) {
res = _sendto(s, (char *)&thetime, sizeof(thetime), 0,
(struct sockaddr *)addrp, sizeof(*addrp));
if (res < 0) {
do_close(s);
return(-1);
}
do {
FD_ZERO(&readfds);
FD_SET(s, &readfds);
res = _select(_rpc_dtablesize(), &readfds,
(fd_set *)NULL, (fd_set *)NULL, timeout);
} while (res < 0 && errno == EINTR);
if (res <= 0) {
if (res == 0) {
errno = ETIMEDOUT;
}
do_close(s);
return(-1);
}
fromlen = sizeof(from);
res = _recvfrom(s, (char *)&thetime, sizeof(thetime), 0,
(struct sockaddr *)&from, &fromlen);
do_close(s);
if (res < 0) {
return(-1);
}
} else {
if (_connect(s, (struct sockaddr *)addrp, sizeof(*addrp)) < 0) {
do_close(s);
return(-1);
}
res = _read(s, (char *)&thetime, sizeof(thetime));
do_close(s);
if (res < 0) {
return(-1);
}
}
if (res != sizeof(thetime)) {
errno = EIO;
return(-1);
}
thetime = ntohl(thetime);
timep->tv_sec = thetime - TOFFSET;
timep->tv_usec = 0;
return(0);
}
static void
do_close(int s)
{
int save;
save = errno;
(void)_close(s);
errno = save;
}
diff --git a/lib/libc/rpc/svc.c b/lib/libc/rpc/svc.c
index 4fb69dda9c7a..9ad697b8ada2 100644
--- a/lib/libc/rpc/svc.c
+++ b/lib/libc/rpc/svc.c
@@ -1,761 +1,760 @@
/* $NetBSD: svc.c,v 1.21 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)svc.c 1.44 88/02/08 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)svc.c 2.4 88/08/11 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* svc.c, Server-side remote procedure call interface.
*
* There are two sets of procedures here. The xprt routines are
* for handling transport handles. The svc routines handle the
* list of service routines.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/poll.h>
#include <assert.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/rpc.h>
#ifdef PORTMAP
#include <rpc/pmap_clnt.h>
#endif /* PORTMAP */
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
#define RQCRED_SIZE 400 /* this size is excessive */
#define SVC_VERSQUIET 0x0001 /* keep quiet about vers mismatch */
#define version_keepquiet(xp) (SVC_EXT(xp)->xp_flags & SVC_VERSQUIET)
#define max(a, b) (a > b ? a : b)
/*
* The services list
* Each entry represents a set of procedures (an rpc program).
* The dispatch routine takes request structs and runs the
* appropriate procedure.
*/
static struct svc_callout {
struct svc_callout *sc_next;
rpcprog_t sc_prog;
rpcvers_t sc_vers;
char *sc_netid;
void (*sc_dispatch)(struct svc_req *, SVCXPRT *);
} *svc_head;
SVCXPRT **__svc_xports;
int __svc_maxrec;
static struct svc_callout *svc_find(rpcprog_t, rpcvers_t,
struct svc_callout **, char *);
static void __xprt_do_unregister (SVCXPRT *xprt, bool_t dolock);
/* *************** SVCXPRT related stuff **************** */
/*
* Activate a transport handle.
*/
void
xprt_register(SVCXPRT *xprt)
{
int sock;
assert(xprt != NULL);
sock = xprt->xp_fd;
rwlock_wrlock(&svc_fd_lock);
if (__svc_xports == NULL) {
__svc_xports = (SVCXPRT **)
mem_alloc((FD_SETSIZE + 1) * sizeof(SVCXPRT *));
if (__svc_xports == NULL) {
rwlock_unlock(&svc_fd_lock);
return;
}
memset(__svc_xports, '\0', (FD_SETSIZE + 1) * sizeof(SVCXPRT *));
}
if (sock < FD_SETSIZE) {
__svc_xports[sock] = xprt;
FD_SET(sock, &svc_fdset);
svc_maxfd = max(svc_maxfd, sock);
} else if (sock == FD_SETSIZE)
__svc_xports[sock] = xprt;
rwlock_unlock(&svc_fd_lock);
}
void
xprt_unregister(SVCXPRT *xprt)
{
__xprt_do_unregister(xprt, TRUE);
}
void
__xprt_unregister_unlocked(SVCXPRT *xprt)
{
__xprt_do_unregister(xprt, FALSE);
}
/*
* De-activate a transport handle.
*/
static void
__xprt_do_unregister(SVCXPRT *xprt, bool_t dolock)
{
int sock;
assert(xprt != NULL);
sock = xprt->xp_fd;
if (dolock)
rwlock_wrlock(&svc_fd_lock);
if ((sock < FD_SETSIZE) && (__svc_xports[sock] == xprt)) {
__svc_xports[sock] = NULL;
FD_CLR(sock, &svc_fdset);
if (sock >= svc_maxfd) {
for (svc_maxfd--; svc_maxfd>=0; svc_maxfd--)
if (__svc_xports[svc_maxfd])
break;
}
} else if ((sock == FD_SETSIZE) && (__svc_xports[sock] == xprt))
__svc_xports[sock] = NULL;
if (dolock)
rwlock_unlock(&svc_fd_lock);
}
/*
* Add a service program to the callout list.
* The dispatch routine will be called when a rpc request for this
* program number comes in.
*/
bool_t
svc_reg(SVCXPRT *xprt, const rpcprog_t prog, const rpcvers_t vers,
void (*dispatch)(struct svc_req *, SVCXPRT *),
const struct netconfig *nconf)
{
bool_t dummy;
struct svc_callout *prev;
struct svc_callout *s;
struct netconfig *tnconf;
char *netid = NULL;
int flag = 0;
/* VARIABLES PROTECTED BY svc_lock: s, prev, svc_head */
if (xprt->xp_netid) {
netid = strdup(xprt->xp_netid);
flag = 1;
} else if (nconf && nconf->nc_netid) {
netid = strdup(nconf->nc_netid);
flag = 1;
} else if ((tnconf = __rpcgettp(xprt->xp_fd)) != NULL) {
netid = strdup(tnconf->nc_netid);
flag = 1;
freenetconfigent(tnconf);
} /* must have been created with svc_raw_create */
if ((netid == NULL) && (flag == 1)) {
return (FALSE);
}
rwlock_wrlock(&svc_lock);
if ((s = svc_find(prog, vers, &prev, netid)) != NULL) {
free(netid);
if (s->sc_dispatch == dispatch)
goto rpcb_it; /* he is registering another xptr */
rwlock_unlock(&svc_lock);
return (FALSE);
}
s = mem_alloc(sizeof (struct svc_callout));
if (s == NULL) {
free(netid);
rwlock_unlock(&svc_lock);
return (FALSE);
}
s->sc_prog = prog;
s->sc_vers = vers;
s->sc_dispatch = dispatch;
s->sc_netid = netid;
s->sc_next = svc_head;
svc_head = s;
if ((xprt->xp_netid == NULL) && (flag == 1) && netid)
((SVCXPRT *) xprt)->xp_netid = strdup(netid);
rpcb_it:
rwlock_unlock(&svc_lock);
/* now register the information with the local binder service */
if (nconf) {
/*LINTED const castaway*/
dummy = rpcb_set(prog, vers, (struct netconfig *) nconf,
&((SVCXPRT *) xprt)->xp_ltaddr);
return (dummy);
}
return (TRUE);
}
/*
* Remove a service program from the callout list.
*/
void
svc_unreg(const rpcprog_t prog, const rpcvers_t vers)
{
struct svc_callout *prev;
struct svc_callout *s;
/* unregister the information anyway */
(void) rpcb_unset(prog, vers, NULL);
rwlock_wrlock(&svc_lock);
while ((s = svc_find(prog, vers, &prev, NULL)) != NULL) {
if (prev == NULL) {
svc_head = s->sc_next;
} else {
prev->sc_next = s->sc_next;
}
s->sc_next = NULL;
if (s->sc_netid)
mem_free(s->sc_netid, sizeof (s->sc_netid) + 1);
mem_free(s, sizeof (struct svc_callout));
}
rwlock_unlock(&svc_lock);
}
/* ********************** CALLOUT list related stuff ************* */
#ifdef PORTMAP
/*
* Add a service program to the callout list.
* The dispatch routine will be called when a rpc request for this
* program number comes in.
*/
bool_t
svc_register(SVCXPRT *xprt, u_long prog, u_long vers,
void (*dispatch)(struct svc_req *, SVCXPRT *),
int protocol)
{
struct svc_callout *prev;
struct svc_callout *s;
assert(xprt != NULL);
assert(dispatch != NULL);
if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) !=
NULL) {
if (s->sc_dispatch == dispatch)
goto pmap_it; /* he is registering another xptr */
return (FALSE);
}
s = mem_alloc(sizeof(struct svc_callout));
if (s == NULL) {
return (FALSE);
}
s->sc_prog = (rpcprog_t)prog;
s->sc_vers = (rpcvers_t)vers;
s->sc_dispatch = dispatch;
s->sc_next = svc_head;
svc_head = s;
pmap_it:
/* now register the information with the local binder service */
if (protocol) {
return (pmap_set(prog, vers, protocol, xprt->xp_port));
}
return (TRUE);
}
/*
* Remove a service program from the callout list.
*/
void
svc_unregister(u_long prog, u_long vers)
{
struct svc_callout *prev;
struct svc_callout *s;
if ((s = svc_find((rpcprog_t)prog, (rpcvers_t)vers, &prev, NULL)) ==
NULL)
return;
if (prev == NULL) {
svc_head = s->sc_next;
} else {
prev->sc_next = s->sc_next;
}
s->sc_next = NULL;
mem_free(s, sizeof(struct svc_callout));
/* now unregister the information with the local binder service */
(void)pmap_unset(prog, vers);
}
#endif /* PORTMAP */
/*
* Search the callout list for a program number, return the callout
* struct.
*/
static struct svc_callout *
svc_find(rpcprog_t prog, rpcvers_t vers, struct svc_callout **prev,
char *netid)
{
struct svc_callout *s, *p;
assert(prev != NULL);
p = NULL;
for (s = svc_head; s != NULL; s = s->sc_next) {
if (((s->sc_prog == prog) && (s->sc_vers == vers)) &&
((netid == NULL) || (s->sc_netid == NULL) ||
(strcmp(netid, s->sc_netid) == 0)))
break;
p = s;
}
*prev = p;
return (s);
}
/* ******************* REPLY GENERATION ROUTINES ************ */
/*
* Send a reply to an rpc request
*/
bool_t
svc_sendreply(SVCXPRT *xprt, xdrproc_t xdr_results,
void * xdr_location)
{
struct rpc_msg rply;
assert(xprt != NULL);
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = SUCCESS;
rply.acpted_rply.ar_results.where = xdr_location;
rply.acpted_rply.ar_results.proc = xdr_results;
return (SVC_REPLY(xprt, &rply));
}
/*
* No procedure error reply
*/
void
svcerr_noproc(SVCXPRT *xprt)
{
struct rpc_msg rply;
assert(xprt != NULL);
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = PROC_UNAVAIL;
SVC_REPLY(xprt, &rply);
}
/*
* Can't decode args error reply
*/
void
svcerr_decode(SVCXPRT *xprt)
{
struct rpc_msg rply;
assert(xprt != NULL);
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = GARBAGE_ARGS;
SVC_REPLY(xprt, &rply);
}
/*
* Some system error
*/
void
svcerr_systemerr(SVCXPRT *xprt)
{
struct rpc_msg rply;
assert(xprt != NULL);
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = SYSTEM_ERR;
SVC_REPLY(xprt, &rply);
}
#if 0
/*
* Tell RPC package to not complain about version errors to the client. This
* is useful when revving broadcast protocols that sit on a fixed address.
* There is really one (or should be only one) example of this kind of
* protocol: the portmapper (or rpc binder).
*/
void
__svc_versquiet_on(SVCXPRT *xprt)
{
SVC_EXT(xprt)->xp_flags |= SVC_VERSQUIET;
}
void
__svc_versquiet_off(SVCXPRT *xprt)
{
SVC_EXT(xprt)->xp_flags &= ~SVC_VERSQUIET;
}
void
svc_versquiet(SVCXPRT *xprt)
{
__svc_versquiet_on(xprt);
}
int
__svc_versquiet_get(SVCXPRT *xprt)
{
return (SVC_EXT(xprt)->xp_flags & SVC_VERSQUIET);
}
#endif
/*
* Authentication error reply
*/
void
svcerr_auth(SVCXPRT *xprt, enum auth_stat why)
{
struct rpc_msg rply;
assert(xprt != NULL);
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_DENIED;
rply.rjcted_rply.rj_stat = AUTH_ERROR;
rply.rjcted_rply.rj_why = why;
SVC_REPLY(xprt, &rply);
}
/*
* Auth too weak error reply
*/
void
svcerr_weakauth(SVCXPRT *xprt)
{
assert(xprt != NULL);
svcerr_auth(xprt, AUTH_TOOWEAK);
}
/*
* Program unavailable error reply
*/
void
svcerr_noprog(SVCXPRT *xprt)
{
struct rpc_msg rply;
assert(xprt != NULL);
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = PROG_UNAVAIL;
SVC_REPLY(xprt, &rply);
}
/*
* Program version mismatch error reply
*/
void
svcerr_progvers(SVCXPRT *xprt, rpcvers_t low_vers, rpcvers_t high_vers)
{
struct rpc_msg rply;
assert(xprt != NULL);
rply.rm_direction = REPLY;
rply.rm_reply.rp_stat = MSG_ACCEPTED;
rply.acpted_rply.ar_verf = xprt->xp_verf;
rply.acpted_rply.ar_stat = PROG_MISMATCH;
rply.acpted_rply.ar_vers.low = (u_int32_t)low_vers;
rply.acpted_rply.ar_vers.high = (u_int32_t)high_vers;
SVC_REPLY(xprt, &rply);
}
/*
* Allocate a new server transport structure. All fields are
* initialized to zero and xp_p3 is initialized to point at an
* extension structure to hold various flags and authentication
* parameters.
*/
SVCXPRT *
svc_xprt_alloc(void)
{
SVCXPRT *xprt;
SVCXPRT_EXT *ext;
xprt = mem_alloc(sizeof(SVCXPRT));
if (xprt == NULL)
return (NULL);
memset(xprt, 0, sizeof(SVCXPRT));
ext = mem_alloc(sizeof(SVCXPRT_EXT));
if (ext == NULL) {
mem_free(xprt, sizeof(SVCXPRT));
return (NULL);
}
memset(ext, 0, sizeof(SVCXPRT_EXT));
xprt->xp_p3 = ext;
ext->xp_auth.svc_ah_ops = &svc_auth_null_ops;
return (xprt);
}
/*
* Free a server transport structure.
*/
void
svc_xprt_free(SVCXPRT *xprt)
{
mem_free(xprt->xp_p3, sizeof(SVCXPRT_EXT));
mem_free(xprt, sizeof(SVCXPRT));
}
/* ******************* SERVER INPUT STUFF ******************* */
/*
* Get server side input from some transport.
*
* Statement of authentication parameters management:
* This function owns and manages all authentication parameters, specifically
* the "raw" parameters (msg.rm_call.cb_cred and msg.rm_call.cb_verf) and
* the "cooked" credentials (rqst->rq_clntcred).
* However, this function does not know the structure of the cooked
* credentials, so it make the following assumptions:
* a) the structure is contiguous (no pointers), and
* b) the cred structure size does not exceed RQCRED_SIZE bytes.
* In all events, all three parameters are freed upon exit from this routine.
* The storage is trivially management on the call stack in user land, but
* is mallocated in kernel land.
*/
void
svc_getreq(int rdfds)
{
fd_set readfds;
FD_ZERO(&readfds);
readfds.fds_bits[0] = rdfds;
svc_getreqset(&readfds);
}
void
svc_getreqset(fd_set *readfds)
{
int bit, fd;
fd_mask mask, *maskp;
int sock;
assert(readfds != NULL);
maskp = readfds->fds_bits;
for (sock = 0; sock < FD_SETSIZE; sock += NFDBITS) {
for (mask = *maskp++; (bit = ffsl(mask)) != 0;
mask ^= (1ul << (bit - 1))) {
/* sock has input waiting */
fd = sock + bit - 1;
svc_getreq_common(fd);
}
}
}
void
svc_getreq_common(int fd)
{
SVCXPRT *xprt;
struct svc_req r;
struct rpc_msg msg;
int prog_found;
rpcvers_t low_vers;
rpcvers_t high_vers;
enum xprt_stat stat;
char cred_area[2*MAX_AUTH_BYTES + RQCRED_SIZE];
msg.rm_call.cb_cred.oa_base = cred_area;
msg.rm_call.cb_verf.oa_base = &(cred_area[MAX_AUTH_BYTES]);
r.rq_clntcred = &(cred_area[2*MAX_AUTH_BYTES]);
rwlock_rdlock(&svc_fd_lock);
xprt = __svc_xports[fd];
rwlock_unlock(&svc_fd_lock);
if (xprt == NULL)
/* But do we control sock? */
return;
/* now receive msgs from xprtprt (support batch calls) */
do {
if (SVC_RECV(xprt, &msg)) {
/* now find the exported program and call it */
struct svc_callout *s;
enum auth_stat why;
r.rq_xprt = xprt;
r.rq_prog = msg.rm_call.cb_prog;
r.rq_vers = msg.rm_call.cb_vers;
r.rq_proc = msg.rm_call.cb_proc;
r.rq_cred = msg.rm_call.cb_cred;
/* first authenticate the message */
if ((why = _authenticate(&r, &msg)) != AUTH_OK) {
/*
* RPCSEC_GSS uses this return code
* for requests that form part of its
* context establishment protocol and
* should not be dispatched to the
* application.
*/
if (why != RPCSEC_GSS_NODISPATCH)
svcerr_auth(xprt, why);
goto call_done;
}
/* now match message with a registered service*/
prog_found = FALSE;
low_vers = (rpcvers_t) -1L;
high_vers = (rpcvers_t) 0L;
for (s = svc_head; s != NULL; s = s->sc_next) {
if (s->sc_prog == r.rq_prog) {
if (s->sc_vers == r.rq_vers) {
(*s->sc_dispatch)(&r, xprt);
goto call_done;
} /* found correct version */
prog_found = TRUE;
if (s->sc_vers < low_vers)
low_vers = s->sc_vers;
if (s->sc_vers > high_vers)
high_vers = s->sc_vers;
} /* found correct program */
}
/*
* if we got here, the program or version
* is not served ...
*/
if (prog_found)
svcerr_progvers(xprt, low_vers, high_vers);
else
svcerr_noprog(xprt);
/* Fall through to ... */
}
/*
* Check if the xprt has been disconnected in a
* recursive call in the service dispatch routine.
* If so, then break.
*/
rwlock_rdlock(&svc_fd_lock);
if (xprt != __svc_xports[fd]) {
rwlock_unlock(&svc_fd_lock);
break;
}
rwlock_unlock(&svc_fd_lock);
call_done:
if ((stat = SVC_STAT(xprt)) == XPRT_DIED){
SVC_DESTROY(xprt);
break;
}
} while (stat == XPRT_MOREREQS);
}
void
svc_getreq_poll(struct pollfd *pfdp, int pollretval)
{
int i;
int fds_found;
for (i = fds_found = 0; fds_found < pollretval; i++) {
struct pollfd *p = &pfdp[i];
if (p->revents) {
/* fd has input waiting */
fds_found++;
/*
* We assume that this function is only called
* via someone _select()ing from svc_fdset or
* _poll()ing from svc_pollset[]. Thus it's safe
* to handle the POLLNVAL event by simply turning
* the corresponding bit off in svc_fdset. The
* svc_pollset[] array is derived from svc_fdset
* and so will also be updated eventually.
*
* XXX Should we do an xprt_unregister() instead?
*/
if (p->revents & POLLNVAL) {
rwlock_wrlock(&svc_fd_lock);
FD_CLR(p->fd, &svc_fdset);
rwlock_unlock(&svc_fd_lock);
} else
svc_getreq_common(p->fd);
}
}
}
bool_t
rpc_control(int what, void *arg)
{
int val;
switch (what) {
case RPC_SVC_CONNMAXREC_SET:
val = *(int *)arg;
if (val <= 0)
return FALSE;
__svc_maxrec = val;
return TRUE;
case RPC_SVC_CONNMAXREC_GET:
*(int *)arg = __svc_maxrec;
return TRUE;
default:
break;
}
return FALSE;
}
diff --git a/lib/libc/rpc/svc_auth.c b/lib/libc/rpc/svc_auth.c
index 1bfffcc4786f..adcca4cf3d25 100644
--- a/lib/libc/rpc/svc_auth.c
+++ b/lib/libc/rpc/svc_auth.c
@@ -1,224 +1,223 @@
/* $NetBSD: svc_auth.c,v 1.12 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)svc_auth.c 1.16 94/04/24 SMI"
static char sccsid[] = "@(#)svc_auth.c 1.26 89/02/07 Copyr 1984 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* svc_auth.c, Server-side rpc authenticator interface.
*
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <rpc/rpc.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "mt_misc.h"
/*
* svcauthsw is the bdevsw of server side authentication.
*
* Server side authenticators are called from authenticate by
* using the client auth struct flavor field to index into svcauthsw.
* The server auth flavors must implement a routine that looks
* like:
*
* enum auth_stat
* flavorx_auth(rqst, msg)
* struct svc_req *rqst;
* struct rpc_msg *msg;
*
*/
/* declarations to allow servers to specify new authentication flavors */
struct authsvc {
int flavor;
enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *);
struct authsvc *next;
};
static struct authsvc *Auths = NULL;
struct svc_auth_ops svc_auth_null_ops;
/*
* The call rpc message, msg has been obtained from the wire. The msg contains
* the raw form of credentials and verifiers. authenticate returns AUTH_OK
* if the msg is successfully authenticated. If AUTH_OK then the routine also
* does the following things:
* set rqst->rq_xprt->verf to the appropriate response verifier;
* sets rqst->rq_client_cred to the "cooked" form of the credentials.
*
* NB: rqst->rq_cxprt->verf must be pre-allocated;
* its length is set appropriately.
*
* The caller still owns and is responsible for msg->u.cmb.cred and
* msg->u.cmb.verf. The authentication system retains ownership of
* rqst->rq_client_cred, the cooked credentials.
*
* There is an assumption that any flavour less than AUTH_NULL is
* invalid.
*/
enum auth_stat
_authenticate(struct svc_req *rqst, struct rpc_msg *msg)
{
int cred_flavor;
struct authsvc *asp;
enum auth_stat dummy;
/* VARIABLES PROTECTED BY authsvc_lock: asp, Auths */
rqst->rq_cred = msg->rm_call.cb_cred;
SVC_AUTH(rqst->rq_xprt).svc_ah_ops = &svc_auth_null_ops;
SVC_AUTH(rqst->rq_xprt).svc_ah_private = NULL;
rqst->rq_xprt->xp_verf.oa_flavor = _null_auth.oa_flavor;
rqst->rq_xprt->xp_verf.oa_length = 0;
cred_flavor = rqst->rq_cred.oa_flavor;
switch (cred_flavor) {
case AUTH_NULL:
dummy = _svcauth_null(rqst, msg);
return (dummy);
case AUTH_SYS:
dummy = _svcauth_unix(rqst, msg);
return (dummy);
case AUTH_SHORT:
dummy = _svcauth_short(rqst, msg);
return (dummy);
#ifdef DES_BUILTIN
case AUTH_DES:
dummy = _svcauth_des(rqst, msg);
return (dummy);
#endif
default:
break;
}
/* flavor doesn't match any of the builtin types, so try new ones */
mutex_lock(&authsvc_lock);
for (asp = Auths; asp; asp = asp->next) {
if (asp->flavor == cred_flavor) {
enum auth_stat as;
as = (*asp->handler)(rqst, msg);
mutex_unlock(&authsvc_lock);
return (as);
}
}
mutex_unlock(&authsvc_lock);
return (AUTH_REJECTEDCRED);
}
/*
* A set of null auth methods used by any authentication protocols
* that don't need to inspect or modify the message body.
*/
static bool_t
svcauth_null_wrap(SVCAUTH *auth, XDR *xdrs, xdrproc_t xdr_func, caddr_t xdr_ptr)
{
return (xdr_func(xdrs, xdr_ptr));
}
struct svc_auth_ops svc_auth_null_ops = {
svcauth_null_wrap,
svcauth_null_wrap,
};
/*ARGSUSED*/
enum auth_stat
_svcauth_null(struct svc_req *rqst, struct rpc_msg *msg)
{
return (AUTH_OK);
}
/*
* Allow the rpc service to register new authentication types that it is
* prepared to handle. When an authentication flavor is registered,
* the flavor is checked against already registered values. If not
* registered, then a new Auths entry is added on the list.
*
* There is no provision to delete a registration once registered.
*
* This routine returns:
* 0 if registration successful
* 1 if flavor already registered
* -1 if can't register (errno set)
*/
int
svc_auth_reg(int cred_flavor,
enum auth_stat (*handler)(struct svc_req *, struct rpc_msg *))
{
struct authsvc *asp;
switch (cred_flavor) {
case AUTH_NULL:
case AUTH_SYS:
case AUTH_SHORT:
#ifdef DES_BUILTIN
case AUTH_DES:
#endif
/* already registered */
return (1);
default:
mutex_lock(&authsvc_lock);
for (asp = Auths; asp; asp = asp->next) {
if (asp->flavor == cred_flavor) {
/* already registered */
mutex_unlock(&authsvc_lock);
return (1);
}
}
/* this is a new one, so go ahead and register it */
asp = mem_alloc(sizeof (*asp));
if (asp == NULL) {
mutex_unlock(&authsvc_lock);
return (-1);
}
asp->flavor = cred_flavor;
asp->handler = handler;
asp->next = Auths;
Auths = asp;
mutex_unlock(&authsvc_lock);
break;
}
return (0);
}
diff --git a/lib/libc/rpc/svc_auth_des.c b/lib/libc/rpc/svc_auth_des.c
index a2dd0c92e541..14e4baf4a0a2 100644
--- a/lib/libc/rpc/svc_auth_des.c
+++ b/lib/libc/rpc/svc_auth_des.c
@@ -1,526 +1,525 @@
/*
* Copyright (c) 1988 by Sun Microsystems, Inc.
*/
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* svcauth_des.c, server-side des authentication
*
* We insure for the service the following:
* (1) The timestamp microseconds do not exceed 1 million.
* (2) The timestamp plus the window is less than the current time.
* (3) The timestamp is not less than the one previously
* seen in the current session.
*
* It is up to the server to determine if the window size is
* too small .
*
*/
#include "namespace.h"
#include "reentrant.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <rpc/des_crypt.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/auth_des.h>
#include <rpc/svc.h>
#include <rpc/rpc_msg.h>
#include <rpc/svc_auth.h>
#include "libc_private.h"
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)svcauth_des.c 2.3 89/07/11 4.0 RPCSRC; from 1.15 88/02/08 SMI";
#endif
-#include <sys/cdefs.h>
extern int key_decryptsession_pk(const char *, netobj *, des_block *);
#define debug(msg) printf("svcauth_des: %s\n", msg)
#define USEC_PER_SEC ((u_long) 1000000L)
#define BEFORE(t1, t2) timercmp(t1, t2, <)
/*
* LRU cache of conversation keys and some other useful items.
*/
#define AUTHDES_CACHESZ 64
struct cache_entry {
des_block key; /* conversation key */
char *rname; /* client's name */
u_int window; /* credential lifetime window */
struct timeval laststamp; /* detect replays of creds */
char *localcred; /* generic local credential */
};
static struct cache_entry *authdes_cache/* [AUTHDES_CACHESZ] */;
static short *authdes_lru/* [AUTHDES_CACHESZ] */;
static void cache_init(void); /* initialize the cache */
static short cache_spot(des_block *, char *, struct timeval *); /* find an entry in the cache */
static void cache_ref(short sid); /* note that sid was ref'd */
static void invalidate(char *); /* invalidate entry in cache */
/*
* cache statistics
*/
static struct {
u_long ncachehits; /* times cache hit, and is not replay */
u_long ncachereplays; /* times cache hit, and is replay */
u_long ncachemisses; /* times cache missed */
} svcauthdes_stats;
/*
* Service side authenticator for AUTH_DES
*/
enum auth_stat
_svcauth_des(struct svc_req *rqst, struct rpc_msg *msg)
{
long *ixdr;
des_block cryptbuf[2];
struct authdes_cred *cred;
struct authdes_verf verf;
int status;
struct cache_entry *entry;
short sid = 0;
des_block *sessionkey;
des_block ivec;
u_int window;
struct timeval timestamp;
u_long namelen;
struct area {
struct authdes_cred area_cred;
char area_netname[MAXNETNAMELEN+1];
} *area;
if (authdes_cache == NULL) {
cache_init();
}
area = (struct area *)rqst->rq_clntcred;
cred = (struct authdes_cred *)&area->area_cred;
/*
* Get the credential
*/
ixdr = (long *)msg->rm_call.cb_cred.oa_base;
cred->adc_namekind = IXDR_GET_ENUM(ixdr, enum authdes_namekind);
switch (cred->adc_namekind) {
case ADN_FULLNAME:
namelen = IXDR_GET_U_LONG(ixdr);
if (namelen > MAXNETNAMELEN) {
return (AUTH_BADCRED);
}
cred->adc_fullname.name = area->area_netname;
bcopy((char *)ixdr, cred->adc_fullname.name,
(u_int)namelen);
cred->adc_fullname.name[namelen] = 0;
ixdr += (RNDUP(namelen) / BYTES_PER_XDR_UNIT);
cred->adc_fullname.key.key.high = (u_long)*ixdr++;
cred->adc_fullname.key.key.low = (u_long)*ixdr++;
cred->adc_fullname.window = (u_long)*ixdr++;
break;
case ADN_NICKNAME:
cred->adc_nickname = (u_long)*ixdr++;
break;
default:
return (AUTH_BADCRED);
}
/*
* Get the verifier
*/
ixdr = (long *)msg->rm_call.cb_verf.oa_base;
verf.adv_xtimestamp.key.high = (u_long)*ixdr++;
verf.adv_xtimestamp.key.low = (u_long)*ixdr++;
verf.adv_int_u = (u_long)*ixdr++;
/*
* Get the conversation key
*/
if (cred->adc_namekind == ADN_FULLNAME) {
netobj pkey;
char pkey_data[1024];
sessionkey = &cred->adc_fullname.key;
if (! getpublickey(cred->adc_fullname.name, pkey_data)) {
debug("getpublickey");
return(AUTH_BADCRED);
}
pkey.n_bytes = pkey_data;
pkey.n_len = strlen(pkey_data) + 1;
if (key_decryptsession_pk(cred->adc_fullname.name, &pkey,
sessionkey) < 0) {
debug("decryptsessionkey");
return (AUTH_BADCRED); /* key not found */
}
} else { /* ADN_NICKNAME */
sid = (short)cred->adc_nickname;
if (sid < 0 || sid >= AUTHDES_CACHESZ) {
debug("bad nickname");
return (AUTH_BADCRED); /* garbled credential */
}
sessionkey = &authdes_cache[sid].key;
}
/*
* Decrypt the timestamp
*/
cryptbuf[0] = verf.adv_xtimestamp;
if (cred->adc_namekind == ADN_FULLNAME) {
cryptbuf[1].key.high = cred->adc_fullname.window;
cryptbuf[1].key.low = verf.adv_winverf;
ivec.key.high = ivec.key.low = 0;
status = cbc_crypt((char *)sessionkey, (char *)cryptbuf,
2*sizeof(des_block), DES_DECRYPT | DES_HW,
(char *)&ivec);
} else {
status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
sizeof(des_block), DES_DECRYPT | DES_HW);
}
if (DES_FAILED(status)) {
debug("decryption failure");
return (AUTH_FAILED); /* system error */
}
/*
* XDR the decrypted timestamp
*/
ixdr = (long *)cryptbuf;
timestamp.tv_sec = IXDR_GET_LONG(ixdr);
timestamp.tv_usec = IXDR_GET_LONG(ixdr);
/*
* Check for valid credentials and verifiers.
* They could be invalid because the key was flushed
* out of the cache, and so a new session should begin.
* Be sure and send AUTH_REJECTED{CRED, VERF} if this is the case.
*/
{
struct timeval current;
int nick;
int winverf;
if (cred->adc_namekind == ADN_FULLNAME) {
window = IXDR_GET_U_LONG(ixdr);
winverf = IXDR_GET_U_LONG(ixdr);
if (winverf != window - 1) {
debug("window verifier mismatch");
return (AUTH_BADCRED); /* garbled credential */
}
sid = cache_spot(sessionkey, cred->adc_fullname.name,
&timestamp);
if (sid < 0) {
debug("replayed credential");
return (AUTH_REJECTEDCRED); /* replay */
}
nick = 0;
} else { /* ADN_NICKNAME */
window = authdes_cache[sid].window;
nick = 1;
}
if ((u_long)timestamp.tv_usec >= USEC_PER_SEC) {
debug("invalid usecs");
/* cached out (bad key), or garbled verifier */
return (nick ? AUTH_REJECTEDVERF : AUTH_BADVERF);
}
if (nick && BEFORE(&timestamp,
&authdes_cache[sid].laststamp)) {
debug("timestamp before last seen");
return (AUTH_REJECTEDVERF); /* replay */
}
(void)gettimeofday(&current, NULL);
current.tv_sec -= window; /* allow for expiration */
if (!BEFORE(&current, &timestamp)) {
debug("timestamp expired");
/* replay, or garbled credential */
return (nick ? AUTH_REJECTEDVERF : AUTH_BADCRED);
}
}
/*
* Set up the reply verifier
*/
verf.adv_nickname = (u_long)sid;
/*
* xdr the timestamp before encrypting
*/
ixdr = (long *)cryptbuf;
IXDR_PUT_LONG(ixdr, timestamp.tv_sec - 1);
IXDR_PUT_LONG(ixdr, timestamp.tv_usec);
/*
* encrypt the timestamp
*/
status = ecb_crypt((char *)sessionkey, (char *)cryptbuf,
sizeof(des_block), DES_ENCRYPT | DES_HW);
if (DES_FAILED(status)) {
debug("encryption failure");
return (AUTH_FAILED); /* system error */
}
verf.adv_xtimestamp = cryptbuf[0];
/*
* Serialize the reply verifier, and update rqst
*/
ixdr = (long *)msg->rm_call.cb_verf.oa_base;
*ixdr++ = (long)verf.adv_xtimestamp.key.high;
*ixdr++ = (long)verf.adv_xtimestamp.key.low;
*ixdr++ = (long)verf.adv_int_u;
rqst->rq_xprt->xp_verf.oa_flavor = AUTH_DES;
rqst->rq_xprt->xp_verf.oa_base = msg->rm_call.cb_verf.oa_base;
rqst->rq_xprt->xp_verf.oa_length =
(char *)ixdr - msg->rm_call.cb_verf.oa_base;
/*
* We succeeded, commit the data to the cache now and
* finish cooking the credential.
*/
entry = &authdes_cache[sid];
entry->laststamp = timestamp;
cache_ref(sid);
if (cred->adc_namekind == ADN_FULLNAME) {
cred->adc_fullname.window = window;
cred->adc_nickname = (u_long)sid; /* save nickname */
if (entry->rname != NULL) {
mem_free(entry->rname, strlen(entry->rname) + 1);
}
entry->rname = (char *)mem_alloc((u_int)strlen(cred->adc_fullname.name)
+ 1);
if (entry->rname != NULL) {
(void) strcpy(entry->rname, cred->adc_fullname.name);
} else {
debug("out of memory");
}
entry->key = *sessionkey;
entry->window = window;
invalidate(entry->localcred); /* mark any cached cred invalid */
} else { /* ADN_NICKNAME */
/*
* nicknames are cooked into fullnames
*/
cred->adc_namekind = ADN_FULLNAME;
cred->adc_fullname.name = entry->rname;
cred->adc_fullname.key = entry->key;
cred->adc_fullname.window = entry->window;
}
return (AUTH_OK); /* we made it!*/
}
/*
* Initialize the cache
*/
static void
cache_init(void)
{
int i;
authdes_cache = (struct cache_entry *)
mem_alloc(sizeof(struct cache_entry) * AUTHDES_CACHESZ);
bzero((char *)authdes_cache,
sizeof(struct cache_entry) * AUTHDES_CACHESZ);
authdes_lru = (short *)mem_alloc(sizeof(short) * AUTHDES_CACHESZ);
/*
* Initialize the lru list
*/
for (i = 0; i < AUTHDES_CACHESZ; i++) {
authdes_lru[i] = i;
}
}
/*
* Find the lru victim
*/
static short
cache_victim(void)
{
return (authdes_lru[AUTHDES_CACHESZ-1]);
}
/*
* Note that sid was referenced
*/
static void
cache_ref(short sid)
{
int i;
short curr;
short prev;
prev = authdes_lru[0];
authdes_lru[0] = sid;
for (i = 1; prev != sid; i++) {
curr = authdes_lru[i];
authdes_lru[i] = prev;
prev = curr;
}
}
/*
* Find a spot in the cache for a credential containing
* the items given. Return -1 if a replay is detected, otherwise
* return the spot in the cache.
*/
static short
cache_spot(des_block *key, char *name, struct timeval *timestamp)
{
struct cache_entry *cp;
int i;
u_long hi;
hi = key->key.high;
for (cp = authdes_cache, i = 0; i < AUTHDES_CACHESZ; i++, cp++) {
if (cp->key.key.high == hi &&
cp->key.key.low == key->key.low &&
cp->rname != NULL &&
bcmp(cp->rname, name, strlen(name) + 1) == 0) {
if (BEFORE(timestamp, &cp->laststamp)) {
svcauthdes_stats.ncachereplays++;
return (-1); /* replay */
}
svcauthdes_stats.ncachehits++;
return (i); /* refresh */
}
}
svcauthdes_stats.ncachemisses++;
return (cache_victim()); /* new credential */
}
#if (defined(sun) || defined(vax) || defined(__FreeBSD__))
/*
* Local credential handling stuff.
* NOTE: bsd unix dependent.
* Other operating systems should put something else here.
*/
#define UNKNOWN -2 /* grouplen, if cached cred is unknown user */
#define INVALID -1 /* grouplen, if cache entry is invalid */
struct bsdcred {
uid_t uid; /* cached uid */
gid_t gid; /* cached gid */
int grouplen; /* length of cached groups */
gid_t groups[NGRPS]; /* cached groups */
};
/*
* Map a des credential into a unix cred.
* We cache the credential here so the application does
* not have to make an rpc call every time to interpret
* the credential.
*/
int
authdes_getucred(struct authdes_cred *adc, uid_t *uid, gid_t *gid,
int *grouplen, gid_t *groups)
{
unsigned sid;
int i;
uid_t i_uid;
gid_t i_gid;
int i_grouplen;
struct bsdcred *cred;
sid = adc->adc_nickname;
if (sid >= AUTHDES_CACHESZ) {
debug("invalid nickname");
return (0);
}
cred = (struct bsdcred *)authdes_cache[sid].localcred;
if (cred == NULL) {
cred = (struct bsdcred *)mem_alloc(sizeof(struct bsdcred));
authdes_cache[sid].localcred = (char *)cred;
cred->grouplen = INVALID;
}
if (cred->grouplen == INVALID) {
/*
* not in cache: lookup
*/
if (!netname2user(adc->adc_fullname.name, &i_uid, &i_gid,
&i_grouplen, groups))
{
debug("unknown netname");
cred->grouplen = UNKNOWN; /* mark as lookup up, but not found */
return (0);
}
debug("missed ucred cache");
*uid = cred->uid = i_uid;
*gid = cred->gid = i_gid;
*grouplen = cred->grouplen = i_grouplen;
for (i = i_grouplen - 1; i >= 0; i--) {
cred->groups[i] = groups[i]; /* int to short */
}
return (1);
} else if (cred->grouplen == UNKNOWN) {
/*
* Already lookup up, but no match found
*/
return (0);
}
/*
* cached credentials
*/
*uid = cred->uid;
*gid = cred->gid;
*grouplen = cred->grouplen;
for (i = cred->grouplen - 1; i >= 0; i--) {
groups[i] = cred->groups[i]; /* short to int */
}
return (1);
}
static void
invalidate(char *cred)
{
if (cred == NULL) {
return;
}
((struct bsdcred *)cred)->grouplen = INVALID;
}
#endif
diff --git a/lib/libc/rpc/svc_auth_unix.c b/lib/libc/rpc/svc_auth_unix.c
index b5f783240ad4..5cce2be11f32 100644
--- a/lib/libc/rpc/svc_auth_unix.c
+++ b/lib/libc/rpc/svc_auth_unix.c
@@ -1,151 +1,150 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)svc_auth_unix.c 1.28 88/02/08 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)svc_auth_unix.c 2.3 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* svc_auth_unix.c
* Handles UNIX flavor authentication parameters on the service side of rpc.
* There are two svc auth implementations here: AUTH_UNIX and AUTH_SHORT.
* _svcauth_unix does full blown unix style uid,gid+gids auth,
* _svcauth_short uses a shorthand auth to index into a cache of longhand auths.
* Note: the shorthand has been gutted for efficiency.
*
* Copyright (C) 1984, Sun Microsystems, Inc.
*/
#include "namespace.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <rpc/rpc.h>
#include "un-namespace.h"
/*
* Unix longhand authenticator
*/
enum auth_stat
_svcauth_unix(struct svc_req *rqst, struct rpc_msg *msg)
{
enum auth_stat stat;
XDR xdrs;
struct authunix_parms *aup;
int32_t *buf;
struct area {
struct authunix_parms area_aup;
char area_machname[MAX_MACHINE_NAME+1];
u_int area_gids[NGRPS];
} *area;
u_int auth_len;
size_t str_len, gid_len;
u_int i;
assert(rqst != NULL);
assert(msg != NULL);
area = (struct area *) rqst->rq_clntcred;
aup = &area->area_aup;
aup->aup_machname = area->area_machname;
aup->aup_gids = area->area_gids;
auth_len = (u_int)msg->rm_call.cb_cred.oa_length;
xdrmem_create(&xdrs, msg->rm_call.cb_cred.oa_base, auth_len,XDR_DECODE);
buf = XDR_INLINE(&xdrs, auth_len);
if (buf != NULL) {
aup->aup_time = IXDR_GET_INT32(buf);
str_len = (size_t)IXDR_GET_U_INT32(buf);
if (str_len > MAX_MACHINE_NAME) {
stat = AUTH_BADCRED;
goto done;
}
memmove(aup->aup_machname, buf, str_len);
aup->aup_machname[str_len] = 0;
str_len = RNDUP(str_len);
buf += str_len / sizeof (int32_t);
aup->aup_uid = (int)IXDR_GET_INT32(buf);
aup->aup_gid = (int)IXDR_GET_INT32(buf);
gid_len = (size_t)IXDR_GET_U_INT32(buf);
if (gid_len > NGRPS) {
stat = AUTH_BADCRED;
goto done;
}
aup->aup_len = gid_len;
for (i = 0; i < gid_len; i++) {
aup->aup_gids[i] = (int)IXDR_GET_INT32(buf);
}
/*
* five is the smallest unix credentials structure -
* timestamp, hostname len (0), uid, gid, and gids len (0).
*/
if ((5 + gid_len) * BYTES_PER_XDR_UNIT + str_len > auth_len) {
(void) printf("bad auth_len gid %ld str %ld auth %u\n",
(long)gid_len, (long)str_len, auth_len);
stat = AUTH_BADCRED;
goto done;
}
} else if (! xdr_authunix_parms(&xdrs, aup)) {
xdrs.x_op = XDR_FREE;
(void)xdr_authunix_parms(&xdrs, aup);
stat = AUTH_BADCRED;
goto done;
}
/* get the verifier */
if ((u_int)msg->rm_call.cb_verf.oa_length) {
rqst->rq_xprt->xp_verf.oa_flavor =
msg->rm_call.cb_verf.oa_flavor;
rqst->rq_xprt->xp_verf.oa_base =
msg->rm_call.cb_verf.oa_base;
rqst->rq_xprt->xp_verf.oa_length =
msg->rm_call.cb_verf.oa_length;
} else {
rqst->rq_xprt->xp_verf.oa_flavor = AUTH_NULL;
rqst->rq_xprt->xp_verf.oa_length = 0;
}
stat = AUTH_OK;
done:
XDR_DESTROY(&xdrs);
return (stat);
}
/*
* Shorthand unix authenticator
* Looks up longhand in a cache.
*/
/*ARGSUSED*/
enum auth_stat
_svcauth_short(struct svc_req *rqst, struct rpc_msg *msg)
{
return (AUTH_REJECTEDCRED);
}
diff --git a/lib/libc/rpc/svc_dg.c b/lib/libc/rpc/svc_dg.c
index 544b80a65d95..c7d3bcbf9184 100644
--- a/lib/libc/rpc/svc_dg.c
+++ b/lib/libc/rpc/svc_dg.c
@@ -1,710 +1,709 @@
/* $NetBSD: svc_dg.c,v 1.4 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)svc_dg.c 1.17 94/04/24 SMI"
#endif
-#include <sys/cdefs.h>
/*
* svc_dg.c, Server side for connectionless RPC.
*
* Does some caching in the hopes of achieving execute-at-most-once semantics.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <rpc/rpc.h>
#include <rpc/svc_dg.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef RPC_CACHE_DEBUG
#include <netconfig.h>
#include <netdir.h>
#endif
#include <err.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
#define su_data(xprt) ((struct svc_dg_data *)((xprt)->xp_p2))
#define rpc_buffer(xprt) ((xprt)->xp_p1)
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
static void svc_dg_ops(SVCXPRT *);
static enum xprt_stat svc_dg_stat(SVCXPRT *);
static bool_t svc_dg_recv(SVCXPRT *, struct rpc_msg *);
static bool_t svc_dg_reply(SVCXPRT *, struct rpc_msg *);
static bool_t svc_dg_getargs(SVCXPRT *, xdrproc_t, void *);
static bool_t svc_dg_freeargs(SVCXPRT *, xdrproc_t, void *);
static void svc_dg_destroy(SVCXPRT *);
static bool_t svc_dg_control(SVCXPRT *, const u_int, void *);
static int cache_get(SVCXPRT *, struct rpc_msg *, char **, size_t *);
static void cache_set(SVCXPRT *, size_t);
int svc_dg_enablecache(SVCXPRT *, u_int);
/*
* Usage:
* xprt = svc_dg_create(sock, sendsize, recvsize);
* Does other connectionless specific initializations.
* Once *xprt is initialized, it is registered.
* see (svc.h, xprt_register). If recvsize or sendsize are 0 suitable
* system defaults are chosen.
* The routines returns NULL if a problem occurred.
*/
static const char svc_dg_str[] = "svc_dg_create: %s";
static const char svc_dg_err1[] = "could not get transport information";
static const char svc_dg_err2[] = "transport does not support data transfer";
static const char svc_dg_err3[] = "getsockname failed";
static const char svc_dg_err4[] = "cannot set IP_RECVDSTADDR";
static const char __no_mem_str[] = "out of memory";
SVCXPRT *
svc_dg_create(int fd, u_int sendsize, u_int recvsize)
{
SVCXPRT *xprt;
struct svc_dg_data *su = NULL;
struct __rpc_sockinfo si;
struct sockaddr_storage ss;
socklen_t slen;
if (!__rpc_fd2sockinfo(fd, &si)) {
warnx(svc_dg_str, svc_dg_err1);
return (NULL);
}
/*
* Find the receive and the send size
*/
sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
if ((sendsize == 0) || (recvsize == 0)) {
warnx(svc_dg_str, svc_dg_err2);
return (NULL);
}
xprt = svc_xprt_alloc();
if (xprt == NULL)
goto freedata;
su = mem_alloc(sizeof (*su));
if (su == NULL)
goto freedata;
su->su_iosz = ((MAX(sendsize, recvsize) + 3) / 4) * 4;
if ((rpc_buffer(xprt) = mem_alloc(su->su_iosz)) == NULL)
goto freedata;
xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt), su->su_iosz,
XDR_DECODE);
su->su_cache = NULL;
xprt->xp_fd = fd;
xprt->xp_p2 = su;
xprt->xp_verf.oa_base = su->su_verfbody;
svc_dg_ops(xprt);
xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
slen = sizeof ss;
if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
warnx(svc_dg_str, svc_dg_err3);
goto freedata_nowarn;
}
xprt->xp_ltaddr.buf = mem_alloc(sizeof (struct sockaddr_storage));
xprt->xp_ltaddr.maxlen = sizeof (struct sockaddr_storage);
xprt->xp_ltaddr.len = slen;
memcpy(xprt->xp_ltaddr.buf, &ss, slen);
if (ss.ss_family == AF_INET) {
struct sockaddr_in *sin;
static const int true_value = 1;
sin = (struct sockaddr_in *)(void *)&ss;
if (sin->sin_addr.s_addr == INADDR_ANY) {
su->su_srcaddr.buf = mem_alloc(sizeof (ss));
su->su_srcaddr.maxlen = sizeof (ss);
if (_setsockopt(fd, IPPROTO_IP, IP_RECVDSTADDR,
&true_value, sizeof(true_value))) {
warnx(svc_dg_str, svc_dg_err4);
goto freedata_nowarn;
}
}
}
xprt_register(xprt);
return (xprt);
freedata:
(void) warnx(svc_dg_str, __no_mem_str);
freedata_nowarn:
if (xprt) {
if (su)
(void) mem_free(su, sizeof (*su));
svc_xprt_free(xprt);
}
return (NULL);
}
/*ARGSUSED*/
static enum xprt_stat
svc_dg_stat(SVCXPRT *xprt)
{
return (XPRT_IDLE);
}
static int
svc_dg_recvfrom(int fd, char *buf, int buflen,
struct sockaddr *raddr, socklen_t *raddrlen,
struct sockaddr *laddr, socklen_t *laddrlen)
{
struct msghdr msg;
struct iovec msg_iov[1];
struct sockaddr_in *lin = (struct sockaddr_in *)laddr;
int rlen;
bool_t have_lin = FALSE;
char tmp[CMSG_LEN(sizeof(*lin))];
struct cmsghdr *cmsg;
memset((char *)&msg, 0, sizeof(msg));
msg_iov[0].iov_base = buf;
msg_iov[0].iov_len = buflen;
msg.msg_iov = msg_iov;
msg.msg_iovlen = 1;
msg.msg_namelen = *raddrlen;
msg.msg_name = (char *)raddr;
if (laddr != NULL) {
msg.msg_control = (caddr_t)tmp;
msg.msg_controllen = CMSG_LEN(sizeof(*lin));
}
rlen = _recvmsg(fd, &msg, 0);
if (rlen >= 0)
*raddrlen = msg.msg_namelen;
if (rlen == -1 || laddr == NULL ||
msg.msg_controllen < sizeof(struct cmsghdr) ||
msg.msg_flags & MSG_CTRUNC)
return rlen;
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
cmsg = CMSG_NXTHDR(&msg, cmsg)) {
if (cmsg->cmsg_level == IPPROTO_IP &&
cmsg->cmsg_type == IP_RECVDSTADDR) {
have_lin = TRUE;
memcpy(&lin->sin_addr,
(struct in_addr *)CMSG_DATA(cmsg),
sizeof(struct in_addr));
break;
}
}
lin->sin_family = AF_INET;
lin->sin_port = 0;
*laddrlen = sizeof(struct sockaddr_in);
if (!have_lin)
lin->sin_addr.s_addr = INADDR_ANY;
return rlen;
}
static bool_t
svc_dg_recv(SVCXPRT *xprt, struct rpc_msg *msg)
{
struct svc_dg_data *su = su_data(xprt);
XDR *xdrs = &(su->su_xdrs);
char *reply;
struct sockaddr_storage ss;
socklen_t alen;
size_t replylen;
ssize_t rlen;
again:
alen = sizeof (struct sockaddr_storage);
rlen = svc_dg_recvfrom(xprt->xp_fd, rpc_buffer(xprt), su->su_iosz,
(struct sockaddr *)(void *)&ss, &alen,
(struct sockaddr *)su->su_srcaddr.buf, &su->su_srcaddr.len);
if (rlen == -1 && errno == EINTR)
goto again;
if (rlen == -1 || (rlen < (ssize_t)(4 * sizeof (u_int32_t))))
return (FALSE);
if (xprt->xp_rtaddr.len < alen) {
if (xprt->xp_rtaddr.len != 0)
mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.len);
xprt->xp_rtaddr.buf = mem_alloc(alen);
xprt->xp_rtaddr.len = alen;
}
memcpy(xprt->xp_rtaddr.buf, &ss, alen);
#ifdef PORTMAP
if (ss.ss_family == AF_INET) {
xprt->xp_raddr = *(struct sockaddr_in *)xprt->xp_rtaddr.buf;
xprt->xp_addrlen = sizeof (struct sockaddr_in);
}
#endif /* PORTMAP */
xdrs->x_op = XDR_DECODE;
XDR_SETPOS(xdrs, 0);
if (! xdr_callmsg(xdrs, msg)) {
return (FALSE);
}
su->su_xid = msg->rm_xid;
if (su->su_cache != NULL) {
if (cache_get(xprt, msg, &reply, &replylen)) {
(void)_sendto(xprt->xp_fd, reply, replylen, 0,
(struct sockaddr *)(void *)&ss, alen);
return (FALSE);
}
}
return (TRUE);
}
static int
svc_dg_sendto(int fd, char *buf, int buflen,
const struct sockaddr *raddr, socklen_t raddrlen,
const struct sockaddr *laddr, socklen_t laddrlen)
{
struct msghdr msg;
struct iovec msg_iov[1];
struct sockaddr_in *laddr_in = (struct sockaddr_in *)laddr;
struct in_addr *lin = &laddr_in->sin_addr;
char tmp[CMSG_SPACE(sizeof(*lin))];
struct cmsghdr *cmsg;
memset((char *)&msg, 0, sizeof(msg));
msg_iov[0].iov_base = buf;
msg_iov[0].iov_len = buflen;
msg.msg_iov = msg_iov;
msg.msg_iovlen = 1;
msg.msg_namelen = raddrlen;
msg.msg_name = (char *)raddr;
if (laddr != NULL && laddr->sa_family == AF_INET &&
lin->s_addr != INADDR_ANY) {
msg.msg_control = (caddr_t)tmp;
msg.msg_controllen = CMSG_LEN(sizeof(*lin));
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_len = CMSG_LEN(sizeof(*lin));
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_SENDSRCADDR;
memcpy(CMSG_DATA(cmsg), lin, sizeof(*lin));
}
return _sendmsg(fd, &msg, 0);
}
static bool_t
svc_dg_reply(SVCXPRT *xprt, struct rpc_msg *msg)
{
struct svc_dg_data *su = su_data(xprt);
XDR *xdrs = &(su->su_xdrs);
bool_t stat = TRUE;
size_t slen;
xdrproc_t xdr_proc;
caddr_t xdr_where;
xdrs->x_op = XDR_ENCODE;
XDR_SETPOS(xdrs, 0);
msg->rm_xid = su->su_xid;
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
xdr_proc = msg->acpted_rply.ar_results.proc;
xdr_where = msg->acpted_rply.ar_results.where;
msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
msg->acpted_rply.ar_results.where = NULL;
if (!xdr_replymsg(xdrs, msg) ||
!SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where))
stat = FALSE;
} else {
stat = xdr_replymsg(xdrs, msg);
}
if (stat) {
slen = XDR_GETPOS(xdrs);
if (svc_dg_sendto(xprt->xp_fd, rpc_buffer(xprt), slen,
(struct sockaddr *)xprt->xp_rtaddr.buf,
(socklen_t)xprt->xp_rtaddr.len,
(struct sockaddr *)su->su_srcaddr.buf,
(socklen_t)su->su_srcaddr.len) == (ssize_t) slen) {
stat = TRUE;
if (su->su_cache)
cache_set(xprt, slen);
}
}
return (stat);
}
static bool_t
svc_dg_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
{
struct svc_dg_data *su;
assert(xprt != NULL);
su = su_data(xprt);
return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
&su->su_xdrs, xdr_args, args_ptr));
}
static bool_t
svc_dg_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
{
XDR *xdrs = &(su_data(xprt)->su_xdrs);
xdrs->x_op = XDR_FREE;
return (*xdr_args)(xdrs, args_ptr);
}
static void
svc_dg_destroy(SVCXPRT *xprt)
{
struct svc_dg_data *su = su_data(xprt);
xprt_unregister(xprt);
if (xprt->xp_fd != -1)
(void)_close(xprt->xp_fd);
XDR_DESTROY(&(su->su_xdrs));
(void) mem_free(rpc_buffer(xprt), su->su_iosz);
if (su->su_srcaddr.buf)
(void) mem_free(su->su_srcaddr.buf, su->su_srcaddr.maxlen);
(void) mem_free(su, sizeof (*su));
if (xprt->xp_rtaddr.buf)
(void) mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
if (xprt->xp_ltaddr.buf)
(void) mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
free(xprt->xp_tp);
svc_xprt_free(xprt);
}
static bool_t
/*ARGSUSED*/
svc_dg_control(SVCXPRT *xprt, const u_int rq, void *in)
{
return (FALSE);
}
static void
svc_dg_ops(SVCXPRT *xprt)
{
static struct xp_ops ops;
static struct xp_ops2 ops2;
/* VARIABLES PROTECTED BY ops_lock: ops */
mutex_lock(&ops_lock);
if (ops.xp_recv == NULL) {
ops.xp_recv = svc_dg_recv;
ops.xp_stat = svc_dg_stat;
ops.xp_getargs = svc_dg_getargs;
ops.xp_reply = svc_dg_reply;
ops.xp_freeargs = svc_dg_freeargs;
ops.xp_destroy = svc_dg_destroy;
ops2.xp_control = svc_dg_control;
}
xprt->xp_ops = &ops;
xprt->xp_ops2 = &ops2;
mutex_unlock(&ops_lock);
}
/* The CACHING COMPONENT */
/*
* Could have been a separate file, but some part of it depends upon the
* private structure of the client handle.
*
* Fifo cache for cl server
* Copies pointers to reply buffers into fifo cache
* Buffers are sent again if retransmissions are detected.
*/
#define SPARSENESS 4 /* 75% sparse */
#define ALLOC(type, size) \
(type *) mem_alloc((sizeof (type) * (size)))
#define MEMZERO(addr, type, size) \
(void) memset((void *) (addr), 0, sizeof (type) * (int) (size))
#define FREE(addr, type, size) \
mem_free((addr), (sizeof (type) * (size)))
/*
* An entry in the cache
*/
typedef struct cache_node *cache_ptr;
struct cache_node {
/*
* Index into cache is xid, proc, vers, prog and address
*/
u_int32_t cache_xid;
rpcproc_t cache_proc;
rpcvers_t cache_vers;
rpcprog_t cache_prog;
struct netbuf cache_addr;
/*
* The cached reply and length
*/
char *cache_reply;
size_t cache_replylen;
/*
* Next node on the list, if there is a collision
*/
cache_ptr cache_next;
};
/*
* The entire cache
*/
struct cl_cache {
u_int uc_size; /* size of cache */
cache_ptr *uc_entries; /* hash table of entries in cache */
cache_ptr *uc_fifo; /* fifo list of entries in cache */
u_int uc_nextvictim; /* points to next victim in fifo list */
rpcprog_t uc_prog; /* saved program number */
rpcvers_t uc_vers; /* saved version number */
rpcproc_t uc_proc; /* saved procedure number */
};
/*
* the hashing function
*/
#define CACHE_LOC(transp, xid) \
(xid % (SPARSENESS * ((struct cl_cache *) \
su_data(transp)->su_cache)->uc_size))
/*
* Enable use of the cache. Returns 1 on success, 0 on failure.
* Note: there is no disable.
*/
static const char cache_enable_str[] = "svc_enablecache: %s %s";
static const char alloc_err[] = "could not allocate cache ";
static const char enable_err[] = "cache already enabled";
int
svc_dg_enablecache(SVCXPRT *transp, u_int size)
{
struct svc_dg_data *su = su_data(transp);
struct cl_cache *uc;
mutex_lock(&dupreq_lock);
if (su->su_cache != NULL) {
(void) warnx(cache_enable_str, enable_err, " ");
mutex_unlock(&dupreq_lock);
return (0);
}
uc = ALLOC(struct cl_cache, 1);
if (uc == NULL) {
warnx(cache_enable_str, alloc_err, " ");
mutex_unlock(&dupreq_lock);
return (0);
}
uc->uc_size = size;
uc->uc_nextvictim = 0;
uc->uc_entries = ALLOC(cache_ptr, size * SPARSENESS);
if (uc->uc_entries == NULL) {
warnx(cache_enable_str, alloc_err, "data");
FREE(uc, struct cl_cache, 1);
mutex_unlock(&dupreq_lock);
return (0);
}
MEMZERO(uc->uc_entries, cache_ptr, size * SPARSENESS);
uc->uc_fifo = ALLOC(cache_ptr, size);
if (uc->uc_fifo == NULL) {
warnx(cache_enable_str, alloc_err, "fifo");
FREE(uc->uc_entries, cache_ptr, size * SPARSENESS);
FREE(uc, struct cl_cache, 1);
mutex_unlock(&dupreq_lock);
return (0);
}
MEMZERO(uc->uc_fifo, cache_ptr, size);
su->su_cache = (char *)(void *)uc;
mutex_unlock(&dupreq_lock);
return (1);
}
/*
* Set an entry in the cache. It assumes that the uc entry is set from
* the earlier call to cache_get() for the same procedure. This will always
* happen because cache_get() is calle by svc_dg_recv and cache_set() is called
* by svc_dg_reply(). All this hoopla because the right RPC parameters are
* not available at svc_dg_reply time.
*/
static const char cache_set_str[] = "cache_set: %s";
static const char cache_set_err1[] = "victim not found";
static const char cache_set_err2[] = "victim alloc failed";
static const char cache_set_err3[] = "could not allocate new rpc buffer";
static void
cache_set(SVCXPRT *xprt, size_t replylen)
{
cache_ptr victim;
cache_ptr *vicp;
struct svc_dg_data *su = su_data(xprt);
struct cl_cache *uc = (struct cl_cache *) su->su_cache;
u_int loc;
char *newbuf;
#ifdef RPC_CACHE_DEBUG
struct netconfig *nconf;
char *uaddr;
#endif
mutex_lock(&dupreq_lock);
/*
* Find space for the new entry, either by
* reusing an old entry, or by mallocing a new one
*/
victim = uc->uc_fifo[uc->uc_nextvictim];
if (victim != NULL) {
loc = CACHE_LOC(xprt, victim->cache_xid);
for (vicp = &uc->uc_entries[loc];
*vicp != NULL && *vicp != victim;
vicp = &(*vicp)->cache_next)
;
if (*vicp == NULL) {
warnx(cache_set_str, cache_set_err1);
mutex_unlock(&dupreq_lock);
return;
}
*vicp = victim->cache_next; /* remove from cache */
newbuf = victim->cache_reply;
} else {
victim = ALLOC(struct cache_node, 1);
if (victim == NULL) {
warnx(cache_set_str, cache_set_err2);
mutex_unlock(&dupreq_lock);
return;
}
newbuf = mem_alloc(su->su_iosz);
if (newbuf == NULL) {
warnx(cache_set_str, cache_set_err3);
FREE(victim, struct cache_node, 1);
mutex_unlock(&dupreq_lock);
return;
}
}
/*
* Store it away
*/
#ifdef RPC_CACHE_DEBUG
if (nconf = getnetconfigent(xprt->xp_netid)) {
uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
freenetconfigent(nconf);
printf(
"cache set for xid= %x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
su->su_xid, uc->uc_prog, uc->uc_vers,
uc->uc_proc, uaddr);
free(uaddr);
}
#endif
victim->cache_replylen = replylen;
victim->cache_reply = rpc_buffer(xprt);
rpc_buffer(xprt) = newbuf;
xdrmem_create(&(su->su_xdrs), rpc_buffer(xprt),
su->su_iosz, XDR_ENCODE);
victim->cache_xid = su->su_xid;
victim->cache_proc = uc->uc_proc;
victim->cache_vers = uc->uc_vers;
victim->cache_prog = uc->uc_prog;
victim->cache_addr = xprt->xp_rtaddr;
victim->cache_addr.buf = ALLOC(char, xprt->xp_rtaddr.len);
(void) memcpy(victim->cache_addr.buf, xprt->xp_rtaddr.buf,
(size_t)xprt->xp_rtaddr.len);
loc = CACHE_LOC(xprt, victim->cache_xid);
victim->cache_next = uc->uc_entries[loc];
uc->uc_entries[loc] = victim;
uc->uc_fifo[uc->uc_nextvictim++] = victim;
uc->uc_nextvictim %= uc->uc_size;
mutex_unlock(&dupreq_lock);
}
/*
* Try to get an entry from the cache
* return 1 if found, 0 if not found and set the stage for cache_set()
*/
static int
cache_get(SVCXPRT *xprt, struct rpc_msg *msg, char **replyp, size_t *replylenp)
{
u_int loc;
cache_ptr ent;
struct svc_dg_data *su = su_data(xprt);
struct cl_cache *uc = (struct cl_cache *) su->su_cache;
#ifdef RPC_CACHE_DEBUG
struct netconfig *nconf;
char *uaddr;
#endif
mutex_lock(&dupreq_lock);
loc = CACHE_LOC(xprt, su->su_xid);
for (ent = uc->uc_entries[loc]; ent != NULL; ent = ent->cache_next) {
if (ent->cache_xid == su->su_xid &&
ent->cache_proc == msg->rm_call.cb_proc &&
ent->cache_vers == msg->rm_call.cb_vers &&
ent->cache_prog == msg->rm_call.cb_prog &&
ent->cache_addr.len == xprt->xp_rtaddr.len &&
(memcmp(ent->cache_addr.buf, xprt->xp_rtaddr.buf,
xprt->xp_rtaddr.len) == 0)) {
#ifdef RPC_CACHE_DEBUG
if (nconf = getnetconfigent(xprt->xp_netid)) {
uaddr = taddr2uaddr(nconf, &xprt->xp_rtaddr);
freenetconfigent(nconf);
printf(
"cache entry found for xid=%x prog=%d vers=%d proc=%d for rmtaddr=%s\n",
su->su_xid, msg->rm_call.cb_prog,
msg->rm_call.cb_vers,
msg->rm_call.cb_proc, uaddr);
free(uaddr);
}
#endif
*replyp = ent->cache_reply;
*replylenp = ent->cache_replylen;
mutex_unlock(&dupreq_lock);
return (1);
}
}
/*
* Failed to find entry
* Remember a few things so we can do a set later
*/
uc->uc_proc = msg->rm_call.cb_proc;
uc->uc_vers = msg->rm_call.cb_vers;
uc->uc_prog = msg->rm_call.cb_prog;
mutex_unlock(&dupreq_lock);
return (0);
}
diff --git a/lib/libc/rpc/svc_generic.c b/lib/libc/rpc/svc_generic.c
index b0913b42d045..ade7ea1bcd8a 100644
--- a/lib/libc/rpc/svc_generic.c
+++ b/lib/libc/rpc/svc_generic.c
@@ -1,316 +1,315 @@
/* $NetBSD: svc_generic.c,v 1.3 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
#if defined(LIBC_SCCS) && !defined(lint)
#ident "@(#)svc_generic.c 1.19 94/04/24 SMI"
static char sccsid[] = "@(#)svc_generic.c 1.21 89/02/28 Copyr 1988 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* svc_generic.c, Server side for RPC.
*
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <rpc/rpc.h>
#include <rpc/nettype.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
extern int __svc_vc_setflag(SVCXPRT *, int);
/*
* The highest level interface for server creation.
* It tries for all the nettokens in that particular class of token
* and returns the number of handles it can create and/or find.
*
* It creates a link list of all the handles it could create.
* If svc_create() is called multiple times, it uses the handle
* created earlier instead of creating a new handle every time.
*
* prognum - Program number
* versnum - Version number
* nettype - Networktype token
*/
int
svc_create(void (*dispatch)(struct svc_req *, SVCXPRT *),
rpcprog_t prognum, rpcvers_t versnum, const char *nettype)
{
struct xlist {
SVCXPRT *xprt; /* Server handle */
struct xlist *next; /* Next item */
} *l;
static struct xlist *xprtlist; /* A link list of all the handles */
int num = 0;
SVCXPRT *xprt;
struct netconfig *nconf;
void *handle;
/* VARIABLES PROTECTED BY xprtlist_lock: xprtlist */
if ((handle = __rpc_setconf(nettype)) == NULL) {
warnx("svc_create: unknown protocol");
return (0);
}
while ((nconf = __rpc_getconf(handle)) != NULL) {
mutex_lock(&xprtlist_lock);
for (l = xprtlist; l; l = l->next) {
if (strcmp(l->xprt->xp_netid, nconf->nc_netid) == 0) {
/* Found an old one, use it */
(void) rpcb_unset(prognum, versnum, nconf);
if (svc_reg(l->xprt, prognum, versnum,
dispatch, nconf) == FALSE)
warnx(
"svc_create: could not register prog %u vers %u on %s",
(unsigned)prognum, (unsigned)versnum,
nconf->nc_netid);
else
num++;
break;
}
}
if (l == NULL) {
/* It was not found. Now create a new one */
xprt = svc_tp_create(dispatch, prognum, versnum, nconf);
if (xprt) {
l = (struct xlist *)malloc(sizeof (*l));
if (l == NULL) {
warnx("svc_create: no memory");
mutex_unlock(&xprtlist_lock);
num = 0;
goto done;
}
l->xprt = xprt;
l->next = xprtlist;
xprtlist = l;
num++;
}
}
mutex_unlock(&xprtlist_lock);
}
done:
__rpc_endconf(handle);
/*
* In case of num == 0; the error messages are generated by the
* underlying layers; and hence not needed here.
*/
return (num);
}
/*
* The high level interface to svc_tli_create().
* It tries to create a server for "nconf" and registers the service
* with the rpcbind. It calls svc_tli_create();
*
* prognum - Program number
* versnum - Version number
* ncofn - Netconfig structure for the network
*/
SVCXPRT *
svc_tp_create(void (*dispatch)(struct svc_req *, SVCXPRT *),
rpcprog_t prognum, rpcvers_t versnum, const struct netconfig *nconf)
{
SVCXPRT *xprt;
if (nconf == NULL) {
warnx(
"svc_tp_create: invalid netconfig structure for prog %u vers %u",
(unsigned)prognum, (unsigned)versnum);
return (NULL);
}
xprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
if (xprt == NULL) {
return (NULL);
}
/*LINTED const castaway*/
(void) rpcb_unset(prognum, versnum, (struct netconfig *) nconf);
if (svc_reg(xprt, prognum, versnum, dispatch, nconf) == FALSE) {
warnx(
"svc_tp_create: Could not register prog %u vers %u on %s",
(unsigned)prognum, (unsigned)versnum,
nconf->nc_netid);
SVC_DESTROY(xprt);
return (NULL);
}
return (xprt);
}
/*
* If fd is RPC_ANYFD, then it opens a fd for the given transport
* provider (nconf cannot be NULL then). If the t_state is T_UNBND and
* bindaddr is NON-NULL, it performs a t_bind using the bindaddr. For
* NULL bindadr and Connection oriented transports, the value of qlen
* is set to 8.
*
* If sendsz or recvsz are zero, their default values are chosen.
*
* fd - Connection end point
* nconf - Netconfig struct for nettoken
* bindaddr - Local bind address
* sendsz - Max sendsize
* recvxz - Max recvsize
*/
SVCXPRT *
svc_tli_create(int fd, const struct netconfig *nconf,
const struct t_bind *bindaddr, u_int sendsz, u_int recvsz)
{
SVCXPRT *xprt = NULL; /* service handle */
bool_t madefd = FALSE; /* whether fd opened here */
struct __rpc_sockinfo si;
struct sockaddr_storage ss;
socklen_t slen;
if (fd == RPC_ANYFD) {
if (nconf == NULL) {
warnx("svc_tli_create: invalid netconfig");
return (NULL);
}
fd = __rpc_nconf2fd(nconf);
if (fd == -1) {
warnx(
"svc_tli_create: could not open connection for %s",
nconf->nc_netid);
return (NULL);
}
__rpc_nconf2sockinfo(nconf, &si);
madefd = TRUE;
} else {
/*
* It is an open descriptor. Get the transport info.
*/
if (!__rpc_fd2sockinfo(fd, &si)) {
warnx(
"svc_tli_create: could not get transport information");
return (NULL);
}
}
/*
* If the fd is unbound, try to bind it.
*/
if (madefd || !__rpc_sockisbound(fd)) {
if (bindaddr == NULL) {
if (bindresvport(fd, NULL) < 0) {
memset(&ss, 0, sizeof ss);
ss.ss_family = si.si_af;
ss.ss_len = si.si_alen;
if (_bind(fd, (struct sockaddr *)(void *)&ss,
(socklen_t)si.si_alen) < 0) {
warnx(
"svc_tli_create: could not bind to anonymous port");
goto freedata;
}
}
_listen(fd, SOMAXCONN);
} else {
if (_bind(fd,
(struct sockaddr *)bindaddr->addr.buf,
(socklen_t)si.si_alen) < 0) {
warnx(
"svc_tli_create: could not bind to requested address");
goto freedata;
}
_listen(fd, (int)bindaddr->qlen);
}
}
/*
* call transport specific function.
*/
switch (si.si_socktype) {
case SOCK_STREAM:
slen = sizeof ss;
if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen)
== 0) {
/* accepted socket */
xprt = svc_fd_create(fd, sendsz, recvsz);
} else
xprt = svc_vc_create(fd, sendsz, recvsz);
if (!nconf || !xprt)
break;
#if 0
/* XXX fvdl */
if (strcmp(nconf->nc_protofmly, "inet") == 0 ||
strcmp(nconf->nc_protofmly, "inet6") == 0)
(void) __svc_vc_setflag(xprt, TRUE);
#endif
break;
case SOCK_DGRAM:
xprt = svc_dg_create(fd, sendsz, recvsz);
break;
default:
warnx("svc_tli_create: bad service type");
goto freedata;
}
if (xprt == NULL)
/*
* The error messages here are spitted out by the lower layers:
* svc_vc_create(), svc_fd_create() and svc_dg_create().
*/
goto freedata;
/* Fill in type of service */
xprt->xp_type = __rpc_socktype2seman(si.si_socktype);
if (nconf) {
xprt->xp_netid = strdup(nconf->nc_netid);
xprt->xp_tp = strdup(nconf->nc_device);
}
return (xprt);
freedata:
if (madefd)
(void)_close(fd);
if (xprt) {
if (!madefd) /* so that svc_destroy doesnt close fd */
xprt->xp_fd = RPC_ANYFD;
SVC_DESTROY(xprt);
}
return (NULL);
}
diff --git a/lib/libc/rpc/svc_raw.c b/lib/libc/rpc/svc_raw.c
index d734e2c45894..c7de392c6924 100644
--- a/lib/libc/rpc/svc_raw.c
+++ b/lib/libc/rpc/svc_raw.c
@@ -1,269 +1,268 @@
/* $NetBSD: svc_raw.c,v 1.14 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
/* #ident "@(#)svc_raw.c 1.16 94/04/24 SMI" */
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)svc_raw.c 1.25 89/01/31 Copyr 1984 Sun Micro";
#endif
-#include <sys/cdefs.h>
/*
* svc_raw.c, This a toy for simple testing and timing.
* Interface to create an rpc client and server in the same UNIX process.
* This lets us similate rpc and get rpc (round trip) overhead, without
* any interference from the kernel.
*
*/
#include "namespace.h"
#include "reentrant.h"
#include <rpc/rpc.h>
#include <sys/types.h>
#include <rpc/raw.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "mt_misc.h"
#ifndef UDPMSGSIZE
#define UDPMSGSIZE 8800
#endif
/*
* This is the "network" that we will be moving data over
*/
static struct svc_raw_private {
char *raw_buf; /* should be shared with the cl handle */
SVCXPRT *server;
XDR xdr_stream;
char verf_body[MAX_AUTH_BYTES];
} *svc_raw_private;
static enum xprt_stat svc_raw_stat(SVCXPRT *);
static bool_t svc_raw_recv(SVCXPRT *, struct rpc_msg *);
static bool_t svc_raw_reply(SVCXPRT *, struct rpc_msg *);
static bool_t svc_raw_getargs(SVCXPRT *, xdrproc_t, void *);
static bool_t svc_raw_freeargs(SVCXPRT *, xdrproc_t, void *);
static void svc_raw_destroy(SVCXPRT *);
static void svc_raw_ops(SVCXPRT *);
static bool_t svc_raw_control(SVCXPRT *, const u_int, void *);
char *__rpc_rawcombuf = NULL;
SVCXPRT *
svc_raw_create(void)
{
struct svc_raw_private *srp;
/* VARIABLES PROTECTED BY svcraw_lock: svc_raw_private, srp */
mutex_lock(&svcraw_lock);
srp = svc_raw_private;
if (srp == NULL) {
srp = (struct svc_raw_private *)calloc(1, sizeof (*srp));
if (srp == NULL) {
mutex_unlock(&svcraw_lock);
return (NULL);
}
if (__rpc_rawcombuf == NULL) {
__rpc_rawcombuf = calloc(UDPMSGSIZE, sizeof (char));
if (__rpc_rawcombuf == NULL) {
free(srp);
mutex_unlock(&svcraw_lock);
return (NULL);
}
}
srp->raw_buf = __rpc_rawcombuf; /* Share it with the client */
srp->server = svc_xprt_alloc();
if (srp->server == NULL) {
free(__rpc_rawcombuf);
free(srp);
mutex_unlock(&svcraw_lock);
return (NULL);
}
svc_raw_private = srp;
}
srp->server->xp_fd = FD_SETSIZE;
srp->server->xp_port = 0;
svc_raw_ops(srp->server);
srp->server->xp_verf.oa_base = srp->verf_body;
xdrmem_create(&srp->xdr_stream, srp->raw_buf, UDPMSGSIZE, XDR_DECODE);
xprt_register(srp->server);
mutex_unlock(&svcraw_lock);
return (srp->server);
}
/*ARGSUSED*/
static enum xprt_stat
svc_raw_stat(SVCXPRT *xprt)
{
return (XPRT_IDLE);
}
/*ARGSUSED*/
static bool_t
svc_raw_recv(SVCXPRT *xprt, struct rpc_msg *msg)
{
struct svc_raw_private *srp;
XDR *xdrs;
mutex_lock(&svcraw_lock);
srp = svc_raw_private;
if (srp == NULL) {
mutex_unlock(&svcraw_lock);
return (FALSE);
}
mutex_unlock(&svcraw_lock);
xdrs = &srp->xdr_stream;
xdrs->x_op = XDR_DECODE;
(void) XDR_SETPOS(xdrs, 0);
if (! xdr_callmsg(xdrs, msg)) {
return (FALSE);
}
return (TRUE);
}
/*ARGSUSED*/
static bool_t
svc_raw_reply(SVCXPRT *xprt, struct rpc_msg *msg)
{
struct svc_raw_private *srp;
XDR *xdrs;
bool_t stat;
xdrproc_t xdr_proc;
caddr_t xdr_where;
mutex_lock(&svcraw_lock);
srp = svc_raw_private;
if (srp == NULL) {
mutex_unlock(&svcraw_lock);
return (FALSE);
}
mutex_unlock(&svcraw_lock);
xdrs = &srp->xdr_stream;
xdrs->x_op = XDR_ENCODE;
(void) XDR_SETPOS(xdrs, 0);
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
xdr_proc = msg->acpted_rply.ar_results.proc;
xdr_where = msg->acpted_rply.ar_results.where;
msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
msg->acpted_rply.ar_results.where = NULL;
stat = xdr_replymsg(xdrs, msg) &&
SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where);
} else {
stat = xdr_replymsg(xdrs, msg);
}
if (!stat) {
return (FALSE);
}
(void) XDR_GETPOS(xdrs); /* called just for overhead */
return (TRUE);
}
/*ARGSUSED*/
static bool_t
svc_raw_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
{
struct svc_raw_private *srp;
mutex_lock(&svcraw_lock);
srp = svc_raw_private;
if (srp == NULL) {
mutex_unlock(&svcraw_lock);
return (FALSE);
}
mutex_unlock(&svcraw_lock);
return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt), &srp->xdr_stream,
xdr_args, args_ptr));
}
/*ARGSUSED*/
static bool_t
svc_raw_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
{
struct svc_raw_private *srp;
XDR *xdrs;
mutex_lock(&svcraw_lock);
srp = svc_raw_private;
if (srp == NULL) {
mutex_unlock(&svcraw_lock);
return (FALSE);
}
mutex_unlock(&svcraw_lock);
xdrs = &srp->xdr_stream;
xdrs->x_op = XDR_FREE;
return (*xdr_args)(xdrs, args_ptr);
}
/*ARGSUSED*/
static void
svc_raw_destroy(SVCXPRT *xprt)
{
}
/*ARGSUSED*/
static bool_t
svc_raw_control(SVCXPRT *xprt, const u_int rq, void *in)
{
return (FALSE);
}
static void
svc_raw_ops(SVCXPRT *xprt)
{
static struct xp_ops ops;
static struct xp_ops2 ops2;
/* VARIABLES PROTECTED BY ops_lock: ops */
mutex_lock(&ops_lock);
if (ops.xp_recv == NULL) {
ops.xp_recv = svc_raw_recv;
ops.xp_stat = svc_raw_stat;
ops.xp_getargs = svc_raw_getargs;
ops.xp_reply = svc_raw_reply;
ops.xp_freeargs = svc_raw_freeargs;
ops.xp_destroy = svc_raw_destroy;
ops2.xp_control = svc_raw_control;
}
xprt->xp_ops = &ops;
xprt->xp_ops2 = &ops2;
mutex_unlock(&ops_lock);
}
diff --git a/lib/libc/rpc/svc_run.c b/lib/libc/rpc/svc_run.c
index 104be0b5078d..9d7098f53514 100644
--- a/lib/libc/rpc/svc_run.c
+++ b/lib/libc/rpc/svc_run.c
@@ -1,97 +1,96 @@
/* $NetBSD: svc_run.c,v 1.17 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "from: @(#)svc_run.c 1.1 87/10/13 Copyr 1984 Sun Micro";
static char *sccsid = "from: @(#)svc_run.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* This is the rpc server side idle loop
* Wait for input, call server program.
*/
#include "namespace.h"
#include "reentrant.h"
#include <err.h>
#include <errno.h>
#include <rpc/rpc.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include <rpc/rpc.h>
#include "rpc_com.h"
#include "mt_misc.h"
void
svc_run(void)
{
fd_set readfds, cleanfds;
struct timeval timeout;
timeout.tv_sec = 30;
timeout.tv_usec = 0;
for (;;) {
rwlock_rdlock(&svc_fd_lock);
readfds = svc_fdset;
cleanfds = svc_fdset;
rwlock_unlock(&svc_fd_lock);
switch (_select(svc_maxfd+1, &readfds, NULL, NULL, &timeout)) {
case -1:
FD_ZERO(&readfds);
if (errno == EINTR) {
continue;
}
_warn("svc_run: - select failed");
return;
case 0:
__svc_clean_idle(&cleanfds, 30, FALSE);
continue;
default:
svc_getreqset(&readfds);
}
}
}
/*
* This function causes svc_run() to exit by telling it that it has no
* more work to do.
*/
void
svc_exit(void)
{
rwlock_wrlock(&svc_fd_lock);
FD_ZERO(&svc_fdset);
rwlock_unlock(&svc_fd_lock);
}
diff --git a/lib/libc/rpc/svc_simple.c b/lib/libc/rpc/svc_simple.c
index 8a99fce0d7d5..df62e7018001 100644
--- a/lib/libc/rpc/svc_simple.c
+++ b/lib/libc/rpc/svc_simple.c
@@ -1,310 +1,309 @@
/* $NetBSD: svc_simple.c,v 1.20 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* Copyright (c) 1986-1991 by Sun Microsystems Inc.
*/
/* #pragma ident "@(#)svc_simple.c 1.18 94/04/24 SMI" */
-#include <sys/cdefs.h>
/*
* svc_simple.c
* Simplified front end to rpc.
*/
/*
* This interface creates a virtual listener for all the services
* started through rpc_reg(). It listens on the same endpoint for
* all the services and then executes the corresponding service
* for the given prognum and procnum.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/types.h>
#include <rpc/rpc.h>
#include <rpc/nettype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <err.h>
#include "un-namespace.h"
#include "rpc_com.h"
#include "mt_misc.h"
static void universal(struct svc_req *, SVCXPRT *);
static struct proglst {
char *(*p_progname)(char *);
rpcprog_t p_prognum;
rpcvers_t p_versnum;
rpcproc_t p_procnum;
SVCXPRT *p_transp;
char *p_netid;
char *p_xdrbuf;
int p_recvsz;
xdrproc_t p_inproc, p_outproc;
struct proglst *p_nxt;
} *proglst;
static const char rpc_reg_err[] = "%s: %s";
static const char rpc_reg_msg[] = "rpc_reg: ";
static const char __reg_err1[] = "can't find appropriate transport";
static const char __reg_err2[] = "can't get protocol info";
static const char __reg_err3[] = "unsupported transport size";
static const char __no_mem_str[] = "out of memory";
/*
* For simplified, easy to use kind of rpc interfaces.
* nettype indicates the type of transport on which the service will be
* listening. Used for conservation of the system resource. Only one
* handle is created for all the services (actually one of each netid)
* and same xdrbuf is used for same netid. The size of the arguments
* is also limited by the recvsize for that transport, even if it is
* a COTS transport. This may be wrong, but for cases like these, they
* should not use the simplified interfaces like this.
*
* prognum - program number
* versnum - version number
* procnum - procedure number
* progname - Server routine
* inproc, outproc - in/out XDR procedures
* nettype - nettype
*/
int
rpc_reg(rpcprog_t prognum, rpcvers_t versnum, rpcproc_t procnum,
char *(*progname)(char *), xdrproc_t inproc, xdrproc_t outproc,
char *nettype)
{
struct netconfig *nconf;
int done = FALSE;
void *handle;
if (procnum == NULLPROC) {
warnx("%s can't reassign procedure number %u", rpc_reg_msg,
NULLPROC);
return (-1);
}
if (nettype == NULL)
nettype = "netpath"; /* The default behavior */
if ((handle = __rpc_setconf(nettype)) == NULL) {
warnx(rpc_reg_err, rpc_reg_msg, __reg_err1);
return (-1);
}
/* VARIABLES PROTECTED BY proglst_lock: proglst */
mutex_lock(&proglst_lock);
while ((nconf = __rpc_getconf(handle)) != NULL) {
struct proglst *pl;
SVCXPRT *svcxprt;
int madenow;
u_int recvsz;
char *xdrbuf;
char *netid;
madenow = FALSE;
svcxprt = NULL;
recvsz = 0;
xdrbuf = netid = NULL;
for (pl = proglst; pl; pl = pl->p_nxt) {
if (strcmp(pl->p_netid, nconf->nc_netid) == 0) {
svcxprt = pl->p_transp;
xdrbuf = pl->p_xdrbuf;
recvsz = pl->p_recvsz;
netid = pl->p_netid;
break;
}
}
if (svcxprt == NULL) {
struct __rpc_sockinfo si;
svcxprt = svc_tli_create(RPC_ANYFD, nconf, NULL, 0, 0);
if (svcxprt == NULL)
continue;
if (!__rpc_fd2sockinfo(svcxprt->xp_fd, &si)) {
warnx(rpc_reg_err, rpc_reg_msg, __reg_err2);
SVC_DESTROY(svcxprt);
continue;
}
recvsz = __rpc_get_t_size(si.si_af, si.si_proto, 0);
if (recvsz == 0) {
warnx(rpc_reg_err, rpc_reg_msg, __reg_err3);
SVC_DESTROY(svcxprt);
continue;
}
if (((xdrbuf = malloc((unsigned)recvsz)) == NULL) ||
((netid = strdup(nconf->nc_netid)) == NULL)) {
warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
free(xdrbuf);
free(netid);
SVC_DESTROY(svcxprt);
break;
}
madenow = TRUE;
}
/*
* Check if this (program, version, netid) had already been
* registered. The check may save a few RPC calls to rpcbind
*/
for (pl = proglst; pl; pl = pl->p_nxt)
if ((pl->p_prognum == prognum) &&
(pl->p_versnum == versnum) &&
(strcmp(pl->p_netid, netid) == 0))
break;
if (pl == NULL) { /* Not yet */
(void) rpcb_unset(prognum, versnum, nconf);
} else {
/* so that svc_reg does not call rpcb_set() */
nconf = NULL;
}
if (!svc_reg(svcxprt, prognum, versnum, universal, nconf)) {
warnx("%s couldn't register prog %u vers %u for %s",
rpc_reg_msg, (unsigned)prognum,
(unsigned)versnum, netid);
if (madenow) {
SVC_DESTROY(svcxprt);
free(xdrbuf);
free(netid);
}
continue;
}
pl = malloc(sizeof (struct proglst));
if (pl == NULL) {
warnx(rpc_reg_err, rpc_reg_msg, __no_mem_str);
if (madenow) {
SVC_DESTROY(svcxprt);
free(xdrbuf);
free(netid);
}
break;
}
pl->p_progname = progname;
pl->p_prognum = prognum;
pl->p_versnum = versnum;
pl->p_procnum = procnum;
pl->p_inproc = inproc;
pl->p_outproc = outproc;
pl->p_transp = svcxprt;
pl->p_xdrbuf = xdrbuf;
pl->p_recvsz = recvsz;
pl->p_netid = netid;
pl->p_nxt = proglst;
proglst = pl;
done = TRUE;
}
__rpc_endconf(handle);
mutex_unlock(&proglst_lock);
if (done == FALSE) {
warnx("%s can't find suitable transport for %s",
rpc_reg_msg, nettype);
return (-1);
}
return (0);
}
/*
* The universal handler for the services registered using registerrpc.
* It handles both the connectionless and the connection oriented cases.
*/
static void
universal(struct svc_req *rqstp, SVCXPRT *transp)
{
rpcprog_t prog;
rpcvers_t vers;
rpcproc_t proc;
char *outdata;
char *xdrbuf;
struct proglst *pl;
/*
* enforce "procnum 0 is echo" convention
*/
if (rqstp->rq_proc == NULLPROC) {
if (svc_sendreply(transp, (xdrproc_t) xdr_void, NULL) ==
FALSE) {
warnx("svc_sendreply failed");
}
return;
}
prog = rqstp->rq_prog;
vers = rqstp->rq_vers;
proc = rqstp->rq_proc;
mutex_lock(&proglst_lock);
for (pl = proglst; pl; pl = pl->p_nxt)
if (pl->p_prognum == prog && pl->p_procnum == proc &&
pl->p_versnum == vers &&
(strcmp(pl->p_netid, transp->xp_netid) == 0)) {
/* decode arguments into a CLEAN buffer */
xdrbuf = pl->p_xdrbuf;
/* Zero the arguments: reqd ! */
(void) memset(xdrbuf, 0, (size_t)pl->p_recvsz);
/*
* Assuming that sizeof (xdrbuf) would be enough
* for the arguments; if not then the program
* may bomb. BEWARE!
*/
if (!svc_getargs(transp, pl->p_inproc, xdrbuf)) {
svcerr_decode(transp);
mutex_unlock(&proglst_lock);
return;
}
outdata = (*(pl->p_progname))(xdrbuf);
if (outdata == NULL &&
pl->p_outproc != (xdrproc_t) xdr_void){
/* there was an error */
mutex_unlock(&proglst_lock);
return;
}
if (!svc_sendreply(transp, pl->p_outproc, outdata)) {
warnx(
"rpc: rpc_reg trouble replying to prog %u vers %u",
(unsigned)prog, (unsigned)vers);
mutex_unlock(&proglst_lock);
return;
}
/* free the decoded arguments */
(void)svc_freeargs(transp, pl->p_inproc, xdrbuf);
mutex_unlock(&proglst_lock);
return;
}
mutex_unlock(&proglst_lock);
/* This should never happen */
warnx("rpc: rpc_reg: never registered prog %u vers %u",
(unsigned)prog, (unsigned)vers);
return;
}
diff --git a/lib/libc/rpc/svc_vc.c b/lib/libc/rpc/svc_vc.c
index 1f377b41e41b..6e141317be84 100644
--- a/lib/libc/rpc/svc_vc.c
+++ b/lib/libc/rpc/svc_vc.c
@@ -1,782 +1,781 @@
/* $NetBSD: svc_vc.c,v 1.7 2000/08/03 00:01:53 fvdl Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2009, Sun Microsystems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of Sun Microsystems, Inc. nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)svc_tcp.c 1.21 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)svc_tcp.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* svc_vc.c, Server side for Connection Oriented based RPC.
*
* Actually implements two flavors of transporter -
* a tcp rendezvouser (a listner and connection establisher)
* and a record/tcp stream.
*/
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <sys/poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/time.h>
#include <sys/uio.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include "rpc_com.h"
#include "mt_misc.h"
#include "un-namespace.h"
static SVCXPRT *makefd_xprt(int, u_int, u_int);
static bool_t rendezvous_request(SVCXPRT *, struct rpc_msg *);
static enum xprt_stat rendezvous_stat(SVCXPRT *);
static void svc_vc_destroy(SVCXPRT *);
static void __svc_vc_dodestroy (SVCXPRT *);
static int read_vc(void *, void *, int);
static int write_vc(void *, void *, int);
static enum xprt_stat svc_vc_stat(SVCXPRT *);
static bool_t svc_vc_recv(SVCXPRT *, struct rpc_msg *);
static bool_t svc_vc_getargs(SVCXPRT *, xdrproc_t, void *);
static bool_t svc_vc_freeargs(SVCXPRT *, xdrproc_t, void *);
static bool_t svc_vc_reply(SVCXPRT *, struct rpc_msg *);
static void svc_vc_rendezvous_ops(SVCXPRT *);
static void svc_vc_ops(SVCXPRT *);
static bool_t svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in);
static bool_t svc_vc_rendezvous_control (SVCXPRT *xprt, const u_int rq,
void *in);
struct cf_rendezvous { /* kept in xprt->xp_p1 for rendezvouser */
u_int sendsize;
u_int recvsize;
int maxrec;
};
struct cf_conn { /* kept in xprt->xp_p1 for actual connection */
enum xprt_stat strm_stat;
u_int32_t x_id;
XDR xdrs;
char verf_body[MAX_AUTH_BYTES];
u_int sendsize;
u_int recvsize;
int maxrec;
bool_t nonblock;
struct timeval last_recv_time;
};
/*
* Usage:
* xprt = svc_vc_create(sock, send_buf_size, recv_buf_size);
*
* Creates, registers, and returns a (rpc) tcp based transporter.
* Once *xprt is initialized, it is registered as a transporter
* see (svc.h, xprt_register). This routine returns
* a NULL if a problem occurred.
*
* The filedescriptor passed in is expected to refer to a bound, but
* not yet connected socket.
*
* Since streams do buffered io similar to stdio, the caller can specify
* how big the send and receive buffers are via the second and third parms;
* 0 => use the system default.
*/
SVCXPRT *
svc_vc_create(int fd, u_int sendsize, u_int recvsize)
{
SVCXPRT *xprt = NULL;
struct cf_rendezvous *r = NULL;
struct __rpc_sockinfo si;
struct sockaddr_storage sslocal;
socklen_t slen;
if (!__rpc_fd2sockinfo(fd, &si))
return NULL;
r = mem_alloc(sizeof(*r));
if (r == NULL) {
warnx("svc_vc_create: out of memory");
goto cleanup_svc_vc_create;
}
r->sendsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)sendsize);
r->recvsize = __rpc_get_t_size(si.si_af, si.si_proto, (int)recvsize);
r->maxrec = __svc_maxrec;
xprt = svc_xprt_alloc();
if (xprt == NULL) {
warnx("svc_vc_create: out of memory");
goto cleanup_svc_vc_create;
}
xprt->xp_p1 = r;
xprt->xp_verf = _null_auth;
svc_vc_rendezvous_ops(xprt);
xprt->xp_port = (u_short)-1; /* It is the rendezvouser */
xprt->xp_fd = fd;
slen = sizeof (struct sockaddr_storage);
if (_getsockname(fd, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
warnx("svc_vc_create: could not retrieve local addr");
goto cleanup_svc_vc_create;
}
xprt->xp_ltaddr.maxlen = xprt->xp_ltaddr.len = sslocal.ss_len;
xprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
if (xprt->xp_ltaddr.buf == NULL) {
warnx("svc_vc_create: no mem for local addr");
goto cleanup_svc_vc_create;
}
memcpy(xprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
xprt->xp_rtaddr.maxlen = sizeof (struct sockaddr_storage);
xprt_register(xprt);
return (xprt);
cleanup_svc_vc_create:
if (xprt)
mem_free(xprt, sizeof(*xprt));
if (r != NULL)
mem_free(r, sizeof(*r));
return (NULL);
}
/*
* Like svtcp_create(), except the routine takes any *open* UNIX file
* descriptor as its first input.
*/
SVCXPRT *
svc_fd_create(int fd, u_int sendsize, u_int recvsize)
{
struct sockaddr_storage ss;
socklen_t slen;
SVCXPRT *ret;
assert(fd != -1);
ret = makefd_xprt(fd, sendsize, recvsize);
if (ret == NULL)
return NULL;
slen = sizeof (struct sockaddr_storage);
if (_getsockname(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
warnx("svc_fd_create: could not retrieve local addr");
goto freedata;
}
ret->xp_ltaddr.maxlen = ret->xp_ltaddr.len = ss.ss_len;
ret->xp_ltaddr.buf = mem_alloc((size_t)ss.ss_len);
if (ret->xp_ltaddr.buf == NULL) {
warnx("svc_fd_create: no mem for local addr");
goto freedata;
}
memcpy(ret->xp_ltaddr.buf, &ss, (size_t)ss.ss_len);
slen = sizeof (struct sockaddr_storage);
if (_getpeername(fd, (struct sockaddr *)(void *)&ss, &slen) < 0) {
warnx("svc_fd_create: could not retrieve remote addr");
goto freedata;
}
ret->xp_rtaddr.maxlen = ret->xp_rtaddr.len = ss.ss_len;
ret->xp_rtaddr.buf = mem_alloc((size_t)ss.ss_len);
if (ret->xp_rtaddr.buf == NULL) {
warnx("svc_fd_create: no mem for local addr");
goto freedata;
}
memcpy(ret->xp_rtaddr.buf, &ss, (size_t)ss.ss_len);
#ifdef PORTMAP
if (ss.ss_family == AF_INET || ss.ss_family == AF_LOCAL) {
ret->xp_raddr = *(struct sockaddr_in *)ret->xp_rtaddr.buf;
ret->xp_addrlen = sizeof (struct sockaddr_in);
}
#endif /* PORTMAP */
return ret;
freedata:
if (ret->xp_ltaddr.buf != NULL)
mem_free(ret->xp_ltaddr.buf, rep->xp_ltaddr.maxlen);
return NULL;
}
static SVCXPRT *
makefd_xprt(int fd, u_int sendsize, u_int recvsize)
{
SVCXPRT *xprt;
struct cf_conn *cd;
const char *netid;
struct __rpc_sockinfo si;
assert(fd != -1);
xprt = svc_xprt_alloc();
if (xprt == NULL) {
warnx("svc_vc: makefd_xprt: out of memory");
goto done;
}
cd = mem_alloc(sizeof(struct cf_conn));
if (cd == NULL) {
warnx("svc_tcp: makefd_xprt: out of memory");
svc_xprt_free(xprt);
xprt = NULL;
goto done;
}
cd->strm_stat = XPRT_IDLE;
xdrrec_create(&(cd->xdrs), sendsize, recvsize,
xprt, read_vc, write_vc);
xprt->xp_p1 = cd;
xprt->xp_verf.oa_base = cd->verf_body;
svc_vc_ops(xprt); /* truly deals with calls */
xprt->xp_port = 0; /* this is a connection, not a rendezvouser */
xprt->xp_fd = fd;
if (__rpc_fd2sockinfo(fd, &si) && __rpc_sockinfo2netid(&si, &netid))
xprt->xp_netid = strdup(netid);
xprt_register(xprt);
done:
return (xprt);
}
/*ARGSUSED*/
static bool_t
rendezvous_request(SVCXPRT *xprt, struct rpc_msg *msg)
{
int sock, flags;
struct cf_rendezvous *r;
struct cf_conn *cd;
struct sockaddr_storage addr, sslocal;
socklen_t len, slen;
struct __rpc_sockinfo si;
SVCXPRT *newxprt;
fd_set cleanfds;
assert(xprt != NULL);
assert(msg != NULL);
r = (struct cf_rendezvous *)xprt->xp_p1;
again:
len = sizeof addr;
if ((sock = _accept(xprt->xp_fd, (struct sockaddr *)(void *)&addr,
&len)) < 0) {
if (errno == EINTR)
goto again;
/*
* Clean out the most idle file descriptor when we're
* running out.
*/
if (errno == EMFILE || errno == ENFILE) {
cleanfds = svc_fdset;
__svc_clean_idle(&cleanfds, 0, FALSE);
goto again;
}
return (FALSE);
}
/*
* make a new transporter (re-uses xprt)
*/
newxprt = makefd_xprt(sock, r->sendsize, r->recvsize);
newxprt->xp_rtaddr.buf = mem_alloc(len);
if (newxprt->xp_rtaddr.buf == NULL)
return (FALSE);
memcpy(newxprt->xp_rtaddr.buf, &addr, len);
newxprt->xp_rtaddr.len = len;
#ifdef PORTMAP
if (addr.ss_family == AF_INET || addr.ss_family == AF_LOCAL) {
newxprt->xp_raddr = *(struct sockaddr_in *)newxprt->xp_rtaddr.buf;
newxprt->xp_addrlen = sizeof (struct sockaddr_in);
}
#endif /* PORTMAP */
if (__rpc_fd2sockinfo(sock, &si) && si.si_proto == IPPROTO_TCP) {
len = 1;
/* XXX fvdl - is this useful? */
_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &len, sizeof (len));
}
cd = (struct cf_conn *)newxprt->xp_p1;
cd->recvsize = r->recvsize;
cd->sendsize = r->sendsize;
cd->maxrec = r->maxrec;
if (cd->maxrec != 0) {
flags = _fcntl(sock, F_GETFL, 0);
if (flags == -1)
return (FALSE);
if (_fcntl(sock, F_SETFL, flags | O_NONBLOCK) == -1)
return (FALSE);
if (cd->recvsize > cd->maxrec)
cd->recvsize = cd->maxrec;
cd->nonblock = TRUE;
__xdrrec_setnonblock(&cd->xdrs, cd->maxrec);
} else
cd->nonblock = FALSE;
slen = sizeof(struct sockaddr_storage);
if(_getsockname(sock, (struct sockaddr *)(void *)&sslocal, &slen) < 0) {
warnx("svc_vc_create: could not retrieve local addr");
newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
} else {
newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = sslocal.ss_len;
newxprt->xp_ltaddr.buf = mem_alloc((size_t)sslocal.ss_len);
if (newxprt->xp_ltaddr.buf == NULL) {
warnx("svc_vc_create: no mem for local addr");
newxprt->xp_ltaddr.maxlen = newxprt->xp_ltaddr.len = 0;
} else {
memcpy(newxprt->xp_ltaddr.buf, &sslocal, (size_t)sslocal.ss_len);
}
}
gettimeofday(&cd->last_recv_time, NULL);
return (FALSE); /* there is never an rpc msg to be processed */
}
/*ARGSUSED*/
static enum xprt_stat
rendezvous_stat(SVCXPRT *xprt)
{
return (XPRT_IDLE);
}
static void
svc_vc_destroy(SVCXPRT *xprt)
{
assert(xprt != NULL);
xprt_unregister(xprt);
__svc_vc_dodestroy(xprt);
}
static void
__svc_vc_dodestroy(SVCXPRT *xprt)
{
struct cf_conn *cd;
struct cf_rendezvous *r;
cd = (struct cf_conn *)xprt->xp_p1;
if (xprt->xp_fd != RPC_ANYFD)
(void)_close(xprt->xp_fd);
if (xprt->xp_port != 0) {
/* a rendezvouser socket */
r = (struct cf_rendezvous *)xprt->xp_p1;
mem_free(r, sizeof (struct cf_rendezvous));
xprt->xp_port = 0;
} else {
/* an actual connection socket */
XDR_DESTROY(&(cd->xdrs));
mem_free(cd, sizeof(struct cf_conn));
}
if (xprt->xp_rtaddr.buf)
mem_free(xprt->xp_rtaddr.buf, xprt->xp_rtaddr.maxlen);
if (xprt->xp_ltaddr.buf)
mem_free(xprt->xp_ltaddr.buf, xprt->xp_ltaddr.maxlen);
free(xprt->xp_tp);
free(xprt->xp_netid);
svc_xprt_free(xprt);
}
/*ARGSUSED*/
static bool_t
svc_vc_control(SVCXPRT *xprt, const u_int rq, void *in)
{
return (FALSE);
}
static bool_t
svc_vc_rendezvous_control(SVCXPRT *xprt, const u_int rq, void *in)
{
struct cf_rendezvous *cfp;
cfp = (struct cf_rendezvous *)xprt->xp_p1;
if (cfp == NULL)
return (FALSE);
switch (rq) {
case SVCGET_CONNMAXREC:
*(int *)in = cfp->maxrec;
break;
case SVCSET_CONNMAXREC:
cfp->maxrec = *(int *)in;
break;
default:
return (FALSE);
}
return (TRUE);
}
/*
* reads data from the tcp or uip connection.
* any error is fatal and the connection is closed.
* (And a read of zero bytes is a half closed stream => error.)
* All read operations timeout after 35 seconds. A timeout is
* fatal for the connection.
*/
static int
read_vc(void *xprtp, void *buf, int len)
{
SVCXPRT *xprt;
int sock;
int milliseconds = 35 * 1000;
struct pollfd pollfd;
struct cf_conn *cfp;
xprt = (SVCXPRT *)xprtp;
assert(xprt != NULL);
sock = xprt->xp_fd;
cfp = (struct cf_conn *)xprt->xp_p1;
if (cfp->nonblock) {
len = _read(sock, buf, (size_t)len);
if (len < 0) {
if (errno == EAGAIN)
len = 0;
else
goto fatal_err;
}
if (len != 0)
gettimeofday(&cfp->last_recv_time, NULL);
return len;
}
do {
pollfd.fd = sock;
pollfd.events = POLLIN;
pollfd.revents = 0;
switch (_poll(&pollfd, 1, milliseconds)) {
case -1:
if (errno == EINTR)
continue;
/*FALLTHROUGH*/
case 0:
goto fatal_err;
default:
break;
}
} while ((pollfd.revents & POLLIN) == 0);
if ((len = _read(sock, buf, (size_t)len)) > 0) {
gettimeofday(&cfp->last_recv_time, NULL);
return (len);
}
fatal_err:
((struct cf_conn *)(xprt->xp_p1))->strm_stat = XPRT_DIED;
return (-1);
}
/*
* writes data to the tcp connection.
* Any error is fatal and the connection is closed.
*/
static int
write_vc(void *xprtp, void *buf, int len)
{
SVCXPRT *xprt;
int i, cnt;
struct cf_conn *cd;
struct timeval tv0, tv1;
xprt = (SVCXPRT *)xprtp;
assert(xprt != NULL);
cd = (struct cf_conn *)xprt->xp_p1;
if (cd->nonblock)
gettimeofday(&tv0, NULL);
for (cnt = len; cnt > 0; cnt -= i, buf = (char *)buf + i) {
i = _write(xprt->xp_fd, buf, (size_t)cnt);
if (i < 0) {
if (errno != EAGAIN || !cd->nonblock) {
cd->strm_stat = XPRT_DIED;
return (-1);
}
if (cd->nonblock) {
/*
* For non-blocking connections, do not
* take more than 2 seconds writing the
* data out.
*
* XXX 2 is an arbitrary amount.
*/
gettimeofday(&tv1, NULL);
if (tv1.tv_sec - tv0.tv_sec >= 2) {
cd->strm_stat = XPRT_DIED;
return (-1);
}
}
i = 0;
}
}
return (len);
}
static enum xprt_stat
svc_vc_stat(SVCXPRT *xprt)
{
struct cf_conn *cd;
assert(xprt != NULL);
cd = (struct cf_conn *)(xprt->xp_p1);
if (cd->strm_stat == XPRT_DIED)
return (XPRT_DIED);
if (! xdrrec_eof(&(cd->xdrs)))
return (XPRT_MOREREQS);
return (XPRT_IDLE);
}
static bool_t
svc_vc_recv(SVCXPRT *xprt, struct rpc_msg *msg)
{
struct cf_conn *cd;
XDR *xdrs;
assert(xprt != NULL);
assert(msg != NULL);
cd = (struct cf_conn *)(xprt->xp_p1);
xdrs = &(cd->xdrs);
if (cd->nonblock) {
if (!__xdrrec_getrec(xdrs, &cd->strm_stat, TRUE))
return FALSE;
} else {
(void)xdrrec_skiprecord(xdrs);
}
xdrs->x_op = XDR_DECODE;
if (xdr_callmsg(xdrs, msg)) {
cd->x_id = msg->rm_xid;
return (TRUE);
}
cd->strm_stat = XPRT_DIED;
return (FALSE);
}
static bool_t
svc_vc_getargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
{
struct cf_conn *cd;
assert(xprt != NULL);
cd = (struct cf_conn *)(xprt->xp_p1);
return (SVCAUTH_UNWRAP(&SVC_AUTH(xprt),
&cd->xdrs, xdr_args, args_ptr));
}
static bool_t
svc_vc_freeargs(SVCXPRT *xprt, xdrproc_t xdr_args, void *args_ptr)
{
XDR *xdrs;
assert(xprt != NULL);
/* args_ptr may be NULL */
xdrs = &(((struct cf_conn *)(xprt->xp_p1))->xdrs);
xdrs->x_op = XDR_FREE;
return ((*xdr_args)(xdrs, args_ptr));
}
static bool_t
svc_vc_reply(SVCXPRT *xprt, struct rpc_msg *msg)
{
struct cf_conn *cd;
XDR *xdrs;
bool_t rstat;
xdrproc_t xdr_proc;
caddr_t xdr_where;
u_int pos;
assert(xprt != NULL);
assert(msg != NULL);
cd = (struct cf_conn *)(xprt->xp_p1);
xdrs = &(cd->xdrs);
xdrs->x_op = XDR_ENCODE;
msg->rm_xid = cd->x_id;
rstat = TRUE;
if (msg->rm_reply.rp_stat == MSG_ACCEPTED &&
msg->rm_reply.rp_acpt.ar_stat == SUCCESS) {
xdr_proc = msg->acpted_rply.ar_results.proc;
xdr_where = msg->acpted_rply.ar_results.where;
msg->acpted_rply.ar_results.proc = (xdrproc_t) xdr_void;
msg->acpted_rply.ar_results.where = NULL;
pos = XDR_GETPOS(xdrs);
if (!xdr_replymsg(xdrs, msg) ||
!SVCAUTH_WRAP(&SVC_AUTH(xprt), xdrs, xdr_proc, xdr_where)) {
XDR_SETPOS(xdrs, pos);
rstat = FALSE;
}
} else {
rstat = xdr_replymsg(xdrs, msg);
}
if (rstat)
(void)xdrrec_endofrecord(xdrs, TRUE);
return (rstat);
}
static void
svc_vc_ops(SVCXPRT *xprt)
{
static struct xp_ops ops;
static struct xp_ops2 ops2;
/* VARIABLES PROTECTED BY ops_lock: ops, ops2 */
mutex_lock(&ops_lock);
if (ops.xp_recv == NULL) {
ops.xp_recv = svc_vc_recv;
ops.xp_stat = svc_vc_stat;
ops.xp_getargs = svc_vc_getargs;
ops.xp_reply = svc_vc_reply;
ops.xp_freeargs = svc_vc_freeargs;
ops.xp_destroy = svc_vc_destroy;
ops2.xp_control = svc_vc_control;
}
xprt->xp_ops = &ops;
xprt->xp_ops2 = &ops2;
mutex_unlock(&ops_lock);
}
static void
svc_vc_rendezvous_ops(SVCXPRT *xprt)
{
static struct xp_ops ops;
static struct xp_ops2 ops2;
mutex_lock(&ops_lock);
if (ops.xp_recv == NULL) {
ops.xp_recv = rendezvous_request;
ops.xp_stat = rendezvous_stat;
ops.xp_getargs =
(bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
ops.xp_reply =
(bool_t (*)(SVCXPRT *, struct rpc_msg *))abort;
ops.xp_freeargs =
(bool_t (*)(SVCXPRT *, xdrproc_t, void *))abort;
ops.xp_destroy = svc_vc_destroy;
ops2.xp_control = svc_vc_rendezvous_control;
}
xprt->xp_ops = &ops;
xprt->xp_ops2 = &ops2;
mutex_unlock(&ops_lock);
}
/*
* Get the effective UID of the sending process. Used by rpcbind, keyserv
* and rpc.yppasswdd on AF_LOCAL.
*/
int
__rpc_get_local_uid(SVCXPRT *transp, uid_t *uid) {
int sock, ret;
gid_t egid;
uid_t euid;
struct sockaddr *sa;
sock = transp->xp_fd;
sa = (struct sockaddr *)transp->xp_rtaddr.buf;
if (sa->sa_family == AF_LOCAL) {
ret = getpeereid(sock, &euid, &egid);
if (ret == 0)
*uid = euid;
return (ret);
} else
return (-1);
}
/*
* Destroy xprts that have not have had any activity in 'timeout' seconds.
* If 'cleanblock' is true, blocking connections (the default) are also
* cleaned. If timeout is 0, the least active connection is picked.
*/
bool_t
__svc_clean_idle(fd_set *fds, int timeout, bool_t cleanblock)
{
int i, ncleaned;
SVCXPRT *xprt, *least_active;
struct timeval tv, tdiff, tmax;
struct cf_conn *cd;
gettimeofday(&tv, NULL);
tmax.tv_sec = tmax.tv_usec = 0;
least_active = NULL;
rwlock_wrlock(&svc_fd_lock);
for (i = ncleaned = 0; i <= svc_maxfd; i++) {
if (FD_ISSET(i, fds)) {
xprt = __svc_xports[i];
if (xprt == NULL || xprt->xp_ops == NULL ||
xprt->xp_ops->xp_recv != svc_vc_recv)
continue;
cd = (struct cf_conn *)xprt->xp_p1;
if (!cleanblock && !cd->nonblock)
continue;
if (timeout == 0) {
timersub(&tv, &cd->last_recv_time, &tdiff);
if (timercmp(&tdiff, &tmax, >)) {
tmax = tdiff;
least_active = xprt;
}
continue;
}
if (tv.tv_sec - cd->last_recv_time.tv_sec > timeout) {
__xprt_unregister_unlocked(xprt);
__svc_vc_dodestroy(xprt);
ncleaned++;
}
}
}
if (timeout == 0 && least_active != NULL) {
__xprt_unregister_unlocked(least_active);
__svc_vc_dodestroy(least_active);
ncleaned++;
}
rwlock_unlock(&svc_fd_lock);
return ncleaned > 0 ? TRUE : FALSE;
}
diff --git a/lib/libc/secure/stack_protector.c b/lib/libc/secure/stack_protector.c
index 15c9e7fcc029..28673caa3866 100644
--- a/lib/libc/secure/stack_protector.c
+++ b/lib/libc/secure/stack_protector.c
@@ -1,138 +1,137 @@
/* $NetBSD: stack_protector.c,v 1.4 2006/11/22 17:23:25 christos Exp $ */
/* $OpenBSD: stack_protector.c,v 1.10 2006/03/31 05:34:44 deraadt Exp $ */
/*
* Copyright (c) 2002 Hiroaki Etoh, Federico G. Schwindt, and Miodrag Vallat.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <link.h>
#include <signal.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include "libc_private.h"
/*
* We give __guard_setup a defined priority early on so that statically linked
* applications have a defined priority at which __stack_chk_guard will be
* getting initialized. This will not matter to most applications, because
* they're either not usually statically linked or they simply don't do things
* in constructors that would be adversely affected by their positioning with
* respect to this initialization.
*/
static void __guard_setup(void)
__attribute__((__constructor__ (200), __used__));
extern long __stack_chk_guard[8];
extern int __sysctl(const int *name, u_int namelen, void *oldp,
size_t *oldlenp, void *newp, size_t newlen);
long __stack_chk_guard[8] = {0, 0, 0, 0, 0, 0, 0, 0};
static void __fail(const char *) __dead2;
void __stack_chk_fail(void) __dead2;
void __chk_fail(void) __dead2;
/*LINTED used*/
static void
__guard_setup(void)
{
static const int mib[2] = { CTL_KERN, KERN_ARND };
volatile long tmp_stack_chk_guard[nitems(__stack_chk_guard)];
size_t idx, len;
int error;
if (__stack_chk_guard[0] != 0)
return;
/*
* Avoid using functions which might have stack protection
* enabled, to update the __stack_chk_guard. First fetch the
* data into a temporal array, then do manual volatile copy to
* not allow optimizer to call memcpy() behind us.
*/
error = _elf_aux_info(AT_CANARY,
__DEQUALIFY(void *, tmp_stack_chk_guard),
sizeof(tmp_stack_chk_guard));
if (error == 0 && tmp_stack_chk_guard[0] != 0) {
for (idx = 0; idx < nitems(__stack_chk_guard); idx++) {
__stack_chk_guard[idx] = tmp_stack_chk_guard[idx];
tmp_stack_chk_guard[idx] = 0;
}
return;
}
len = sizeof(__stack_chk_guard);
if (__sysctl(mib, nitems(mib), __stack_chk_guard, &len, NULL, 0) ==
-1 || len != sizeof(__stack_chk_guard)) {
/* If sysctl was unsuccessful, use the "terminator canary". */
((unsigned char *)(void *)__stack_chk_guard)[0] = 0;
((unsigned char *)(void *)__stack_chk_guard)[1] = 0;
((unsigned char *)(void *)__stack_chk_guard)[2] = '\n';
((unsigned char *)(void *)__stack_chk_guard)[3] = 255;
}
}
/*ARGSUSED*/
static void
__fail(const char *msg)
{
struct sigaction sa;
sigset_t mask;
/* Immediately block all signal handlers from running code */
(void)sigfillset(&mask);
(void)sigdelset(&mask, SIGABRT);
(void)sigprocmask(SIG_BLOCK, &mask, NULL);
/* This may fail on a chroot jail... */
syslog(LOG_CRIT, "%s", msg);
(void)memset(&sa, 0, sizeof(sa));
(void)sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = SIG_DFL;
(void)sigaction(SIGABRT, &sa, NULL);
(void)kill(getpid(), SIGABRT);
_exit(127);
}
void
__stack_chk_fail(void)
{
__fail("stack overflow detected; terminated");
}
void
__chk_fail(void)
{
__fail("buffer overflow detected; terminated");
}
#ifndef PIC
__weak_reference(__stack_chk_fail, __stack_chk_fail_local);
#endif
diff --git a/lib/libc/softfloat/bits32/softfloat.c b/lib/libc/softfloat/bits32/softfloat.c
index 2968786133cd..91aa190695af 100644
--- a/lib/libc/softfloat/bits32/softfloat.c
+++ b/lib/libc/softfloat/bits32/softfloat.c
@@ -1,2345 +1,2344 @@
/* $NetBSD: softfloat.c,v 1.1 2002/05/21 23:51:07 bjh21 Exp $ */
/*
* This version hacked for use with gcc -msoft-float by bjh21.
* (Mostly a case of #ifdefing out things GCC doesn't need or provides
* itself).
*/
/*
* Things you may want to define:
*
* SOFTFLOAT_FOR_GCC - build only those functions necessary for GCC (with
* -msoft-float) to work. Include "softfloat-for-gcc.h" to get them
* properly renamed.
*/
/*
* This differs from the standard bits32/softfloat.c in that float64
* is defined to be a 64-bit integer rather than a structure. The
* structure is float64s, with translation between the two going via
* float64u.
*/
/*
===============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-Point
Arithmetic Package, Release 2a.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these four paragraphs for those parts of
this code that are retained.
===============================================================================
*/
-#include <sys/cdefs.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
/*
* Conversions between floats as stored in memory and floats as
* SoftFloat uses them
*/
#ifndef FLOAT64_DEMANGLE
#define FLOAT64_DEMANGLE(a) (a)
#endif
#ifndef FLOAT64_MANGLE
#define FLOAT64_MANGLE(a) (a)
#endif
/*
-------------------------------------------------------------------------------
Floating-point rounding mode and exception flags.
-------------------------------------------------------------------------------
*/
int float_rounding_mode = float_round_nearest_even;
int float_exception_flags = 0;
/*
-------------------------------------------------------------------------------
Primitive arithmetic functions, including multi-word arithmetic, and
division and square root approximations. (Can be specialized to target if
desired.)
-------------------------------------------------------------------------------
*/
#include "softfloat-macros"
/*
-------------------------------------------------------------------------------
Functions and definitions to determine: (1) whether tininess for underflow
is detected before or after rounding by default, (2) what (if anything)
happens when exceptions are raised, (3) how signaling NaNs are distinguished
from quiet NaNs, (4) the default generated quiet NaNs, and (4) how NaNs
are propagated from function inputs to output. These details are target-
specific.
-------------------------------------------------------------------------------
*/
#include "softfloat-specialize"
/*
-------------------------------------------------------------------------------
Returns the fraction bits of the single-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits32 extractFloat32Frac( float32 a )
{
return a & 0x007FFFFF;
}
/*
-------------------------------------------------------------------------------
Returns the exponent bits of the single-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE int16 extractFloat32Exp( float32 a )
{
return ( a>>23 ) & 0xFF;
}
/*
-------------------------------------------------------------------------------
Returns the sign bit of the single-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE flag extractFloat32Sign( float32 a )
{
return a>>31;
}
/*
-------------------------------------------------------------------------------
Normalizes the subnormal single-precision floating-point value represented
by the denormalized significand `aSig'. The normalized exponent and
significand are stored at the locations pointed to by `zExpPtr' and
`zSigPtr', respectively.
-------------------------------------------------------------------------------
*/
static void
normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
{
int8 shiftCount;
shiftCount = countLeadingZeros32( aSig ) - 8;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*
-------------------------------------------------------------------------------
Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
single-precision floating-point value, returning the result. After being
shifted into the proper positions, the three fields are simply added
together to form the result. This means that any integer portion of `zSig'
will be added into the exponent. Since a properly normalized significand
will have an integer portion equal to 1, the `zExp' input should be 1 less
than the desired result exponent whenever `zSig' is a complete, normalized
significand.
-------------------------------------------------------------------------------
*/
INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
{
return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand `zSig', and returns the proper single-precision floating-
point value corresponding to the abstract input. Ordinarily, the abstract
value is simply rounded and packed into the single-precision format, with
the inexact exception raised if the abstract input cannot be represented
exactly. However, if the abstract value is too large, the overflow and
inexact exceptions are raised and an infinity or maximal finite value is
returned. If the abstract value is too small, the input value is rounded to
a subnormal number, and the underflow and inexact exceptions are raised if
the abstract input cannot be represented exactly as a subnormal single-
precision floating-point number.
The input significand `zSig' has its binary point between bits 30
and 29, which is 7 bits to the left of the usual location. This shifted
significand must be normalized or smaller. If `zSig' is not normalized,
`zExp' must be 0; in that case, the result returned is a subnormal number,
and it must not require rounding. In the usual case that `zSig' is
normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
The handling of underflow and overflow follows the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
{
int8 roundingMode;
flag roundNearestEven;
int8 roundIncrement, roundBits;
flag isTiny;
roundingMode = float_rounding_mode;
roundNearestEven = roundingMode == float_round_nearest_even;
roundIncrement = 0x40;
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
else {
roundIncrement = 0x7F;
if ( zSign ) {
if ( roundingMode == float_round_up ) roundIncrement = 0;
}
else {
if ( roundingMode == float_round_down ) roundIncrement = 0;
}
}
}
roundBits = zSig & 0x7F;
if ( 0xFD <= (bits16) zExp ) {
if ( ( 0xFD < zExp )
|| ( ( zExp == 0xFD )
&& ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
) {
float_raise( float_flag_overflow | float_flag_inexact );
return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
}
if ( zExp < 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < -1 )
|| ( zSig + roundIncrement < 0x80000000 );
shift32RightJamming( zSig, - zExp, &zSig );
zExp = 0;
roundBits = zSig & 0x7F;
if ( isTiny && roundBits ) float_raise( float_flag_underflow );
}
}
if ( roundBits ) float_exception_flags |= float_flag_inexact;
zSig = ( zSig + roundIncrement )>>7;
zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
if ( zSig == 0 ) zExp = 0;
return packFloat32( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand `zSig', and returns the proper single-precision floating-
point value corresponding to the abstract input. This routine is just like
`roundAndPackFloat32' except that `zSig' does not have to be normalized.
Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
floating-point exponent.
-------------------------------------------------------------------------------
*/
static float32
normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
{
int8 shiftCount;
shiftCount = countLeadingZeros32( zSig ) - 1;
return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );
}
/*
-------------------------------------------------------------------------------
Returns the least-significant 32 fraction bits of the double-precision
floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits32 extractFloat64Frac1( float64 a )
{
return FLOAT64_DEMANGLE(a) & LIT64( 0x00000000FFFFFFFF );
}
/*
-------------------------------------------------------------------------------
Returns the most-significant 20 fraction bits of the double-precision
floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits32 extractFloat64Frac0( float64 a )
{
return ( FLOAT64_DEMANGLE(a)>>32 ) & 0x000FFFFF;
}
/*
-------------------------------------------------------------------------------
Returns the exponent bits of the double-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE int16 extractFloat64Exp( float64 a )
{
return ( FLOAT64_DEMANGLE(a)>>52 ) & 0x7FF;
}
/*
-------------------------------------------------------------------------------
Returns the sign bit of the double-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE flag extractFloat64Sign( float64 a )
{
return FLOAT64_DEMANGLE(a)>>63;
}
/*
-------------------------------------------------------------------------------
Normalizes the subnormal double-precision floating-point value represented
by the denormalized significand formed by the concatenation of `aSig0' and
`aSig1'. The normalized exponent is stored at the location pointed to by
`zExpPtr'. The most significant 21 bits of the normalized significand are
stored at the location pointed to by `zSig0Ptr', and the least significant
32 bits of the normalized significand are stored at the location pointed to
by `zSig1Ptr'.
-------------------------------------------------------------------------------
*/
static void
normalizeFloat64Subnormal(
bits32 aSig0,
bits32 aSig1,
int16 *zExpPtr,
bits32 *zSig0Ptr,
bits32 *zSig1Ptr
)
{
int8 shiftCount;
if ( aSig0 == 0 ) {
shiftCount = countLeadingZeros32( aSig1 ) - 11;
if ( shiftCount < 0 ) {
*zSig0Ptr = aSig1>>( - shiftCount );
*zSig1Ptr = aSig1<<( shiftCount & 31 );
}
else {
*zSig0Ptr = aSig1<<shiftCount;
*zSig1Ptr = 0;
}
*zExpPtr = - shiftCount - 31;
}
else {
shiftCount = countLeadingZeros32( aSig0 ) - 11;
shortShift64Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
*zExpPtr = 1 - shiftCount;
}
}
/*
-------------------------------------------------------------------------------
Packs the sign `zSign', the exponent `zExp', and the significand formed by
the concatenation of `zSig0' and `zSig1' into a double-precision floating-
point value, returning the result. After being shifted into the proper
positions, the three fields `zSign', `zExp', and `zSig0' are simply added
together to form the most significant 32 bits of the result. This means
that any integer portion of `zSig0' will be added into the exponent. Since
a properly normalized significand will have an integer portion equal to 1,
the `zExp' input should be 1 less than the desired result exponent whenever
`zSig0' and `zSig1' concatenated form a complete, normalized significand.
-------------------------------------------------------------------------------
*/
INLINE float64
packFloat64( flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 )
{
return FLOAT64_MANGLE( ( ( (bits64) zSign )<<63 ) +
( ( (bits64) zExp )<<52 ) +
( ( (bits64) zSig0 )<<32 ) + zSig1 );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and extended significand formed by the concatenation of `zSig0', `zSig1',
and `zSig2', and returns the proper double-precision floating-point value
corresponding to the abstract input. Ordinarily, the abstract value is
simply rounded and packed into the double-precision format, with the inexact
exception raised if the abstract input cannot be represented exactly.
However, if the abstract value is too large, the overflow and inexact
exceptions are raised and an infinity or maximal finite value is returned.
If the abstract value is too small, the input value is rounded to a
subnormal number, and the underflow and inexact exceptions are raised if the
abstract input cannot be represented exactly as a subnormal double-precision
floating-point number.
The input significand must be normalized or smaller. If the input
significand is not normalized, `zExp' must be 0; in that case, the result
returned is a subnormal number, and it must not require rounding. In the
usual case that the input significand is normalized, `zExp' must be 1 less
than the ``true'' floating-point exponent. The handling of underflow and
overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float64
roundAndPackFloat64(
flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1, bits32 zSig2 )
{
int8 roundingMode;
flag roundNearestEven, increment, isTiny;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
increment = ( (sbits32) zSig2 < 0 );
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
increment = 0;
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig2;
}
else {
increment = ( roundingMode == float_round_up ) && zSig2;
}
}
}
if ( 0x7FD <= (bits16) zExp ) {
if ( ( 0x7FD < zExp )
|| ( ( zExp == 0x7FD )
&& eq64( 0x001FFFFF, 0xFFFFFFFF, zSig0, zSig1 )
&& increment
)
) {
float_raise( float_flag_overflow | float_flag_inexact );
if ( ( roundingMode == float_round_to_zero )
|| ( zSign && ( roundingMode == float_round_up ) )
|| ( ! zSign && ( roundingMode == float_round_down ) )
) {
return packFloat64( zSign, 0x7FE, 0x000FFFFF, 0xFFFFFFFF );
}
return packFloat64( zSign, 0x7FF, 0, 0 );
}
if ( zExp < 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < -1 )
|| ! increment
|| lt64( zSig0, zSig1, 0x001FFFFF, 0xFFFFFFFF );
shift64ExtraRightJamming(
zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
zExp = 0;
if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
if ( roundNearestEven ) {
increment = ( (sbits32) zSig2 < 0 );
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig2;
}
else {
increment = ( roundingMode == float_round_up ) && zSig2;
}
}
}
}
if ( zSig2 ) float_exception_flags |= float_flag_inexact;
if ( increment ) {
add64( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
}
else {
if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
}
return packFloat64( zSign, zExp, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand formed by the concatenation of `zSig0' and `zSig1', and
returns the proper double-precision floating-point value corresponding
to the abstract input. This routine is just like `roundAndPackFloat64'
except that the input significand has fewer bits and does not have to be
normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
point exponent.
-------------------------------------------------------------------------------
*/
static float64
normalizeRoundAndPackFloat64(
flag zSign, int16 zExp, bits32 zSig0, bits32 zSig1 )
{
int8 shiftCount;
bits32 zSig2;
if ( zSig0 == 0 ) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 32;
}
shiftCount = countLeadingZeros32( zSig0 ) - 11;
if ( 0 <= shiftCount ) {
zSig2 = 0;
shortShift64Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
}
else {
shift64ExtraRightJamming(
zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
}
zExp -= shiftCount;
return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the 32-bit two's complement integer `a' to
the single-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 int32_to_float32( int32 a )
{
flag zSign;
if ( a == 0 ) return 0;
if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
zSign = ( a < 0 );
return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the 32-bit two's complement integer `a' to
the double-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 int32_to_float64( int32 a )
{
flag zSign;
bits32 absA;
int8 shiftCount;
bits32 zSig0, zSig1;
if ( a == 0 ) return packFloat64( 0, 0, 0, 0 );
zSign = ( a < 0 );
absA = zSign ? - a : a;
shiftCount = countLeadingZeros32( absA ) - 11;
if ( 0 <= shiftCount ) {
zSig0 = absA<<shiftCount;
zSig1 = 0;
}
else {
shift64Right( absA, 0, - shiftCount, &zSig0, &zSig1 );
}
return packFloat64( zSign, 0x412 - shiftCount, zSig0, zSig1 );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int32 float32_to_int32( float32 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig, aSigExtra;
int32 z;
int8 roundingMode;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
shiftCount = aExp - 0x96;
if ( 0 <= shiftCount ) {
if ( 0x9E <= aExp ) {
if ( a != 0xCF000000 ) {
float_raise( float_flag_invalid );
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
return 0x7FFFFFFF;
}
}
return (sbits32) 0x80000000;
}
z = ( aSig | 0x00800000 )<<shiftCount;
if ( aSign ) z = - z;
}
else {
if ( aExp < 0x7E ) {
aSigExtra = aExp | aSig;
z = 0;
}
else {
aSig |= 0x00800000;
aSigExtra = aSig<<( shiftCount & 31 );
z = aSig>>( - shiftCount );
}
if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
if ( (sbits32) aSigExtra < 0 ) {
++z;
if ( (bits32) ( aSigExtra<<1 ) == 0 ) z &= ~1;
}
if ( aSign ) z = - z;
}
else {
aSigExtra = ( aSigExtra != 0 );
if ( aSign ) {
z += ( roundingMode == float_round_down ) & aSigExtra;
z = - z;
}
else {
z += ( roundingMode == float_round_up ) & aSigExtra;
}
}
}
return z;
}
#endif
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero.
If `a' is a NaN, the largest positive integer is returned. Otherwise, if
the conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int32 float32_to_int32_round_to_zero( float32 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig;
int32 z;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
shiftCount = aExp - 0x9E;
if ( 0 <= shiftCount ) {
if ( a != 0xCF000000 ) {
float_raise( float_flag_invalid );
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
}
return (sbits32) 0x80000000;
}
else if ( aExp <= 0x7E ) {
if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
aSig = ( aSig | 0x00800000 )<<8;
z = aSig>>( - shiftCount );
if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
float_exception_flags |= float_flag_inexact;
}
if ( aSign ) z = - z;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the double-precision floating-point format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float32_to_float64( float32 a )
{
flag aSign;
int16 aExp;
bits32 aSig, zSig0, zSig1;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) );
return packFloat64( aSign, 0x7FF, 0, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat64( aSign, 0, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
--aExp;
}
shift64Right( aSig, 0, 3, &zSig0, &zSig1 );
return packFloat64( aSign, aExp + 0x380, zSig0, zSig1 );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Rounds the single-precision floating-point value `a' to an integer,
and returns the result as a single-precision floating-point value. The
operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_round_to_int( float32 a )
{
flag aSign;
int16 aExp;
bits32 lastBitMask, roundBitsMask;
int8 roundingMode;
float32 z;
aExp = extractFloat32Exp( a );
if ( 0x96 <= aExp ) {
if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
return propagateFloat32NaN( a, a );
}
return a;
}
if ( aExp <= 0x7E ) {
if ( (bits32) ( a<<1 ) == 0 ) return a;
float_exception_flags |= float_flag_inexact;
aSign = extractFloat32Sign( a );
switch ( float_rounding_mode ) {
case float_round_nearest_even:
if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
return packFloat32( aSign, 0x7F, 0 );
}
break;
case float_round_to_zero:
break;
case float_round_down:
return aSign ? 0xBF800000 : 0;
case float_round_up:
return aSign ? 0x80000000 : 0x3F800000;
}
return packFloat32( aSign, 0, 0 );
}
lastBitMask = 1;
lastBitMask <<= 0x96 - aExp;
roundBitsMask = lastBitMask - 1;
z = a;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
z += lastBitMask>>1;
if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
z += roundBitsMask;
}
}
z &= ~ roundBitsMask;
if ( z != a ) float_exception_flags |= float_flag_inexact;
return z;
}
#endif
/*
-------------------------------------------------------------------------------
Returns the result of adding the absolute values of the single-precision
floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
before being returned. `zSign' is ignored if the result is a NaN.
The addition is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
expDiff = aExp - bExp;
aSig <<= 6;
bSig <<= 6;
if ( 0 < expDiff ) {
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= 0x20000000;
}
shift32RightJamming( bSig, expDiff, &bSig );
zExp = aExp;
}
else if ( expDiff < 0 ) {
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign, 0xFF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= 0x20000000;
}
shift32RightJamming( aSig, - expDiff, &aSig );
zExp = bExp;
}
else {
if ( aExp == 0xFF ) {
if ( aSig | bSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
zSig = 0x40000000 + aSig + bSig;
zExp = aExp;
goto roundAndPack;
}
aSig |= 0x20000000;
zSig = ( aSig + bSig )<<1;
--zExp;
if ( (sbits32) zSig < 0 ) {
zSig = aSig + bSig;
++zExp;
}
roundAndPack:
return roundAndPackFloat32( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the absolute values of the single-
precision floating-point values `a' and `b'. If `zSign' is 1, the
difference is negated before being returned. `zSign' is ignored if the
result is a NaN. The subtraction is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
expDiff = aExp - bExp;
aSig <<= 7;
bSig <<= 7;
if ( 0 < expDiff ) goto aExpBigger;
if ( expDiff < 0 ) goto bExpBigger;
if ( aExp == 0xFF ) {
if ( aSig | bSig ) return propagateFloat32NaN( a, b );
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( aExp == 0 ) {
aExp = 1;
bExp = 1;
}
if ( bSig < aSig ) goto aBigger;
if ( aSig < bSig ) goto bBigger;
return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
bExpBigger:
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign ^ 1, 0xFF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= 0x40000000;
}
shift32RightJamming( aSig, - expDiff, &aSig );
bSig |= 0x40000000;
bBigger:
zSig = bSig - aSig;
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= 0x40000000;
}
shift32RightJamming( bSig, expDiff, &bSig );
aSig |= 0x40000000;
aBigger:
zSig = aSig - bSig;
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the single-precision floating-point values `a'
and `b'. The operation is performed according to the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_add( float32 a, float32 b )
{
flag aSign, bSign;
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign == bSign ) {
return addFloat32Sigs( a, b, aSign );
}
else {
return subFloat32Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the single-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_sub( float32 a, float32 b )
{
flag aSign, bSign;
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign == bSign ) {
return subFloat32Sigs( a, b, aSign );
}
else {
return addFloat32Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of multiplying the single-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_mul( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig0, zSig1;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0xFF ) {
if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
return propagateFloat32NaN( a, b );
}
if ( ( bExp | bSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
if ( ( aExp | aSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
}
zExp = aExp + bExp - 0x7F;
aSig = ( aSig | 0x00800000 )<<7;
bSig = ( bSig | 0x00800000 )<<8;
mul32To64( aSig, bSig, &zSig0, &zSig1 );
zSig0 |= ( zSig1 != 0 );
if ( 0 <= (sbits32) ( zSig0<<1 ) ) {
zSig0 <<= 1;
--zExp;
}
return roundAndPackFloat32( zSign, zExp, zSig0 );
}
/*
-------------------------------------------------------------------------------
Returns the result of dividing the single-precision floating-point value `a'
by the corresponding value `b'. The operation is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_div( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig, rem0, rem1, term0, term1;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign, 0, 0 );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
if ( ( aExp | aSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
float_raise( float_flag_divbyzero );
return packFloat32( zSign, 0xFF, 0 );
}
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
zExp = aExp - bExp + 0x7D;
aSig = ( aSig | 0x00800000 )<<7;
bSig = ( bSig | 0x00800000 )<<8;
if ( bSig <= ( aSig + aSig ) ) {
aSig >>= 1;
++zExp;
}
zSig = estimateDiv64To32( aSig, 0, bSig );
if ( ( zSig & 0x3F ) <= 2 ) {
mul32To64( bSig, zSig, &term0, &term1 );
sub64( aSig, 0, term0, term1, &rem0, &rem1 );
while ( (sbits32) rem0 < 0 ) {
--zSig;
add64( rem0, rem1, 0, bSig, &rem0, &rem1 );
}
zSig |= ( rem1 != 0 );
}
return roundAndPackFloat32( zSign, zExp, zSig );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns the remainder of the single-precision floating-point value `a'
with respect to the corresponding value `b'. The operation is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_rem( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, expDiff;
bits32 aSig, bSig, q, allZero, alternateASig;
sbits32 sigMean;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
if ( aExp == 0xFF ) {
if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
return propagateFloat32NaN( a, b );
}
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return a;
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
expDiff = aExp - bExp;
aSig = ( aSig | 0x00800000 )<<8;
bSig = ( bSig | 0x00800000 )<<8;
if ( expDiff < 0 ) {
if ( expDiff < -1 ) return a;
aSig >>= 1;
}
q = ( bSig <= aSig );
if ( q ) aSig -= bSig;
expDiff -= 32;
while ( 0 < expDiff ) {
q = estimateDiv64To32( aSig, 0, bSig );
q = ( 2 < q ) ? q - 2 : 0;
aSig = - ( ( bSig>>2 ) * q );
expDiff -= 30;
}
expDiff += 32;
if ( 0 < expDiff ) {
q = estimateDiv64To32( aSig, 0, bSig );
q = ( 2 < q ) ? q - 2 : 0;
q >>= 32 - expDiff;
bSig >>= 2;
aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
}
else {
aSig >>= 2;
bSig >>= 2;
}
do {
alternateASig = aSig;
++q;
aSig -= bSig;
} while ( 0 <= (sbits32) aSig );
sigMean = aSig + alternateASig;
if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
aSig = alternateASig;
}
zSign = ( (sbits32) aSig < 0 );
if ( zSign ) aSig = - aSig;
return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
}
#endif
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns the square root of the single-precision floating-point value `a'.
The operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_sqrt( float32 a )
{
flag aSign;
int16 aExp, zExp;
bits32 aSig, zSig, rem0, rem1, term0, term1;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, 0 );
if ( ! aSign ) return a;
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( aSign ) {
if ( ( aExp | aSig ) == 0 ) return a;
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return 0;
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
aSig = ( aSig | 0x00800000 )<<8;
zSig = estimateSqrt32( aExp, aSig ) + 2;
if ( ( zSig & 0x7F ) <= 5 ) {
if ( zSig < 2 ) {
zSig = 0x7FFFFFFF;
goto roundAndPack;
}
else {
aSig >>= aExp & 1;
mul32To64( zSig, zSig, &term0, &term1 );
sub64( aSig, 0, term0, term1, &rem0, &rem1 );
while ( (sbits32) rem0 < 0 ) {
--zSig;
shortShift64Left( 0, zSig, 1, &term0, &term1 );
term1 |= 1;
add64( rem0, rem1, term0, term1, &rem0, &rem1 );
}
zSig |= ( ( rem0 | rem1 ) != 0 );
}
}
shift32RightJamming( zSig, 1, &zSig );
roundAndPack:
return roundAndPackFloat32( 0, zExp, zSig );
}
#endif
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_eq( float32 a, float32 b )
{
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than
or equal to the corresponding value `b', and 0 otherwise. The comparison
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_le( float32 a, float32 b )
{
flag aSign, bSign;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
return ( a == b ) || ( aSign ^ ( a < b ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_lt( float32 a, float32 b )
{
flag aSign, bSign;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
return ( a != b ) && ( aSign ^ ( a < b ) );
}
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The invalid exception is
raised if either operand is a NaN. Otherwise, the comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_eq_signaling( float32 a, float32 b )
{
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than or
equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
cause an exception. Otherwise, the comparison is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_le_quiet( float32 a, float32 b )
{
flag aSign, bSign;
int16 aExp, bExp;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
return ( a == b ) || ( aSign ^ ( a < b ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
exception. Otherwise, the comparison is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_lt_quiet( float32 a, float32 b )
{
flag aSign, bSign;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
return ( a != b ) && ( aSign ^ ( a < b ) );
}
#endif /* !SOFTFLOAT_FOR_GCC */
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int32 float64_to_int32( float64 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig0, aSig1, absZ, aSigExtra;
int32 z;
int8 roundingMode;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
shiftCount = aExp - 0x413;
if ( 0 <= shiftCount ) {
if ( 0x41E < aExp ) {
if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0;
goto invalid;
}
shortShift64Left(
aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra );
if ( 0x80000000 < absZ ) goto invalid;
}
else {
aSig1 = ( aSig1 != 0 );
if ( aExp < 0x3FE ) {
aSigExtra = aExp | aSig0 | aSig1;
absZ = 0;
}
else {
aSig0 |= 0x00100000;
aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1;
absZ = aSig0>>( - shiftCount );
}
}
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
if ( (sbits32) aSigExtra < 0 ) {
++absZ;
if ( (bits32) ( aSigExtra<<1 ) == 0 ) absZ &= ~1;
}
z = aSign ? - absZ : absZ;
}
else {
aSigExtra = ( aSigExtra != 0 );
if ( aSign ) {
z = - ( absZ
+ ( ( roundingMode == float_round_down ) & aSigExtra ) );
}
else {
z = absZ + ( ( roundingMode == float_round_up ) & aSigExtra );
}
}
if ( ( aSign ^ ( z < 0 ) ) && z ) {
invalid:
float_raise( float_flag_invalid );
return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
}
if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
return z;
}
#endif /* !SOFTFLOAT_FOR_GCC */
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero.
If `a' is a NaN, the largest positive integer is returned. Otherwise, if
the conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int32 float64_to_int32_round_to_zero( float64 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig0, aSig1, absZ, aSigExtra;
int32 z;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
shiftCount = aExp - 0x413;
if ( 0 <= shiftCount ) {
if ( 0x41E < aExp ) {
if ( ( aExp == 0x7FF ) && ( aSig0 | aSig1 ) ) aSign = 0;
goto invalid;
}
shortShift64Left(
aSig0 | 0x00100000, aSig1, shiftCount, &absZ, &aSigExtra );
}
else {
if ( aExp < 0x3FF ) {
if ( aExp | aSig0 | aSig1 ) {
float_exception_flags |= float_flag_inexact;
}
return 0;
}
aSig0 |= 0x00100000;
aSigExtra = ( aSig0<<( shiftCount & 31 ) ) | aSig1;
absZ = aSig0>>( - shiftCount );
}
z = aSign ? - absZ : absZ;
if ( ( aSign ^ ( z < 0 ) ) && z ) {
invalid:
float_raise( float_flag_invalid );
return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
}
if ( aSigExtra ) float_exception_flags |= float_flag_inexact;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the single-precision floating-point format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float64_to_float32( float64 a )
{
flag aSign;
int16 aExp;
bits32 aSig0, aSig1, zSig;
bits32 allZero;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig0 | aSig1 ) {
return commonNaNToFloat32( float64ToCommonNaN( a ) );
}
return packFloat32( aSign, 0xFF, 0 );
}
shift64RightJamming( aSig0, aSig1, 22, &allZero, &zSig );
if ( aExp ) zSig |= 0x40000000;
return roundAndPackFloat32( aSign, aExp - 0x381, zSig );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Rounds the double-precision floating-point value `a' to an integer,
and returns the result as a double-precision floating-point value. The
operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_round_to_int( float64 a )
{
flag aSign;
int16 aExp;
bits32 lastBitMask, roundBitsMask;
int8 roundingMode;
float64 z;
aExp = extractFloat64Exp( a );
if ( 0x413 <= aExp ) {
if ( 0x433 <= aExp ) {
if ( ( aExp == 0x7FF )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) ) {
return propagateFloat64NaN( a, a );
}
return a;
}
lastBitMask = 1;
lastBitMask = ( lastBitMask<<( 0x432 - aExp ) )<<1;
roundBitsMask = lastBitMask - 1;
z = a;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
if ( lastBitMask ) {
add64( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
}
else {
if ( (sbits32) z.low < 0 ) {
++z.high;
if ( (bits32) ( z.low<<1 ) == 0 ) z.high &= ~1;
}
}
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloat64Sign( z )
^ ( roundingMode == float_round_up ) ) {
add64( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
}
}
z.low &= ~ roundBitsMask;
}
else {
if ( aExp <= 0x3FE ) {
if ( ( ( (bits32) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
float_exception_flags |= float_flag_inexact;
aSign = extractFloat64Sign( a );
switch ( float_rounding_mode ) {
case float_round_nearest_even:
if ( ( aExp == 0x3FE )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) )
) {
return packFloat64( aSign, 0x3FF, 0, 0 );
}
break;
case float_round_down:
return
aSign ? packFloat64( 1, 0x3FF, 0, 0 )
: packFloat64( 0, 0, 0, 0 );
case float_round_up:
return
aSign ? packFloat64( 1, 0, 0, 0 )
: packFloat64( 0, 0x3FF, 0, 0 );
}
return packFloat64( aSign, 0, 0, 0 );
}
lastBitMask = 1;
lastBitMask <<= 0x413 - aExp;
roundBitsMask = lastBitMask - 1;
z.low = 0;
z.high = a.high;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
z.high += lastBitMask>>1;
if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
z.high &= ~ lastBitMask;
}
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloat64Sign( z )
^ ( roundingMode == float_round_up ) ) {
z.high |= ( a.low != 0 );
z.high += roundBitsMask;
}
}
z.high &= ~ roundBitsMask;
}
if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
float_exception_flags |= float_flag_inexact;
}
return z;
}
#endif
/*
-------------------------------------------------------------------------------
Returns the result of adding the absolute values of the double-precision
floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
before being returned. `zSign' is ignored if the result is a NaN.
The addition is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float64 addFloat64Sigs( float64 a, float64 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
int16 expDiff;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
bSig1 = extractFloat64Frac1( b );
bSig0 = extractFloat64Frac0( b );
bExp = extractFloat64Exp( b );
expDiff = aExp - bExp;
if ( 0 < expDiff ) {
if ( aExp == 0x7FF ) {
if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig0 |= 0x00100000;
}
shift64ExtraRightJamming(
bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
zExp = aExp;
}
else if ( expDiff < 0 ) {
if ( bExp == 0x7FF ) {
if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
return packFloat64( zSign, 0x7FF, 0, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig0 |= 0x00100000;
}
shift64ExtraRightJamming(
aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
zExp = bExp;
}
else {
if ( aExp == 0x7FF ) {
if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
return propagateFloat64NaN( a, b );
}
return a;
}
add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
if ( aExp == 0 ) return packFloat64( zSign, 0, zSig0, zSig1 );
zSig2 = 0;
zSig0 |= 0x00200000;
zExp = aExp;
goto shiftRight1;
}
aSig0 |= 0x00100000;
add64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
--zExp;
if ( zSig0 < 0x00200000 ) goto roundAndPack;
++zExp;
shiftRight1:
shift64ExtraRightJamming( zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
roundAndPack:
return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the absolute values of the double-
precision floating-point values `a' and `b'. If `zSign' is 1, the
difference is negated before being returned. `zSign' is ignored if the
result is a NaN. The subtraction is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float64 subFloat64Sigs( float64 a, float64 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
int16 expDiff;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
bSig1 = extractFloat64Frac1( b );
bSig0 = extractFloat64Frac0( b );
bExp = extractFloat64Exp( b );
expDiff = aExp - bExp;
shortShift64Left( aSig0, aSig1, 10, &aSig0, &aSig1 );
shortShift64Left( bSig0, bSig1, 10, &bSig0, &bSig1 );
if ( 0 < expDiff ) goto aExpBigger;
if ( expDiff < 0 ) goto bExpBigger;
if ( aExp == 0x7FF ) {
if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
return propagateFloat64NaN( a, b );
}
float_raise( float_flag_invalid );
return float64_default_nan;
}
if ( aExp == 0 ) {
aExp = 1;
bExp = 1;
}
if ( bSig0 < aSig0 ) goto aBigger;
if ( aSig0 < bSig0 ) goto bBigger;
if ( bSig1 < aSig1 ) goto aBigger;
if ( aSig1 < bSig1 ) goto bBigger;
return packFloat64( float_rounding_mode == float_round_down, 0, 0, 0 );
bExpBigger:
if ( bExp == 0x7FF ) {
if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
return packFloat64( zSign ^ 1, 0x7FF, 0, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig0 |= 0x40000000;
}
shift64RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
bSig0 |= 0x40000000;
bBigger:
sub64( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0x7FF ) {
if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig0 |= 0x40000000;
}
shift64RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
aSig0 |= 0x40000000;
aBigger:
sub64( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat64( zSign, zExp - 10, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the double-precision floating-point values `a'
and `b'. The operation is performed according to the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_add( float64 a, float64 b )
{
flag aSign, bSign;
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign == bSign ) {
return addFloat64Sigs( a, b, aSign );
}
else {
return subFloat64Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the double-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_sub( float64 a, float64 b )
{
flag aSign, bSign;
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign == bSign ) {
return subFloat64Sigs( a, b, aSign );
}
else {
return addFloat64Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of multiplying the double-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_mul( float64 a, float64 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
bSig1 = extractFloat64Frac1( b );
bSig0 = extractFloat64Frac0( b );
bExp = extractFloat64Exp( b );
bSign = extractFloat64Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FF ) {
if ( ( aSig0 | aSig1 )
|| ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) {
return propagateFloat64NaN( a, b );
}
if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
return packFloat64( zSign, 0x7FF, 0, 0 );
}
if ( bExp == 0x7FF ) {
if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
return float64_default_nan;
}
return packFloat64( zSign, 0x7FF, 0, 0 );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
if ( bExp == 0 ) {
if ( ( bSig0 | bSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
}
zExp = aExp + bExp - 0x400;
aSig0 |= 0x00100000;
shortShift64Left( bSig0, bSig1, 12, &bSig0, &bSig1 );
mul64To128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
add64( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
zSig2 |= ( zSig3 != 0 );
if ( 0x00200000 <= zSig0 ) {
shift64ExtraRightJamming(
zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
++zExp;
}
return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
}
/*
-------------------------------------------------------------------------------
Returns the result of dividing the double-precision floating-point value `a'
by the corresponding value `b'. The operation is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_div( float64 a, float64 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
bSig1 = extractFloat64Frac1( b );
bSig0 = extractFloat64Frac0( b );
bExp = extractFloat64Exp( b );
bSign = extractFloat64Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FF ) {
if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, b );
if ( bExp == 0x7FF ) {
if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
goto invalid;
}
return packFloat64( zSign, 0x7FF, 0, 0 );
}
if ( bExp == 0x7FF ) {
if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
return packFloat64( zSign, 0, 0, 0 );
}
if ( bExp == 0 ) {
if ( ( bSig0 | bSig1 ) == 0 ) {
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
return float64_default_nan;
}
float_raise( float_flag_divbyzero );
return packFloat64( zSign, 0x7FF, 0, 0 );
}
normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( zSign, 0, 0, 0 );
normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
zExp = aExp - bExp + 0x3FD;
shortShift64Left( aSig0 | 0x00100000, aSig1, 11, &aSig0, &aSig1 );
shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 );
if ( le64( bSig0, bSig1, aSig0, aSig1 ) ) {
shift64Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
++zExp;
}
zSig0 = estimateDiv64To32( aSig0, aSig1, bSig0 );
mul64By32To96( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
sub96( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
while ( (sbits32) rem0 < 0 ) {
--zSig0;
add96( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
}
zSig1 = estimateDiv64To32( rem1, rem2, bSig0 );
if ( ( zSig1 & 0x3FF ) <= 4 ) {
mul64By32To96( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
sub96( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
while ( (sbits32) rem1 < 0 ) {
--zSig1;
add96( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
}
zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
}
shift64ExtraRightJamming( zSig0, zSig1, 0, 11, &zSig0, &zSig1, &zSig2 );
return roundAndPackFloat64( zSign, zExp, zSig0, zSig1, zSig2 );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns the remainder of the double-precision floating-point value `a'
with respect to the corresponding value `b'. The operation is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_rem( float64 a, float64 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, expDiff;
bits32 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
bits32 allZero, alternateASig0, alternateASig1, sigMean1;
sbits32 sigMean0;
float64 z;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
bSig1 = extractFloat64Frac1( b );
bSig0 = extractFloat64Frac0( b );
bExp = extractFloat64Exp( b );
bSign = extractFloat64Sign( b );
if ( aExp == 0x7FF ) {
if ( ( aSig0 | aSig1 )
|| ( ( bExp == 0x7FF ) && ( bSig0 | bSig1 ) ) ) {
return propagateFloat64NaN( a, b );
}
goto invalid;
}
if ( bExp == 0x7FF ) {
if ( bSig0 | bSig1 ) return propagateFloat64NaN( a, b );
return a;
}
if ( bExp == 0 ) {
if ( ( bSig0 | bSig1 ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
return float64_default_nan;
}
normalizeFloat64Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return a;
normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
expDiff = aExp - bExp;
if ( expDiff < -1 ) return a;
shortShift64Left(
aSig0 | 0x00100000, aSig1, 11 - ( expDiff < 0 ), &aSig0, &aSig1 );
shortShift64Left( bSig0 | 0x00100000, bSig1, 11, &bSig0, &bSig1 );
q = le64( bSig0, bSig1, aSig0, aSig1 );
if ( q ) sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
expDiff -= 32;
while ( 0 < expDiff ) {
q = estimateDiv64To32( aSig0, aSig1, bSig0 );
q = ( 4 < q ) ? q - 4 : 0;
mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 );
shortShift96Left( term0, term1, term2, 29, &term1, &term2, &allZero );
shortShift64Left( aSig0, aSig1, 29, &aSig0, &allZero );
sub64( aSig0, 0, term1, term2, &aSig0, &aSig1 );
expDiff -= 29;
}
if ( -32 < expDiff ) {
q = estimateDiv64To32( aSig0, aSig1, bSig0 );
q = ( 4 < q ) ? q - 4 : 0;
q >>= - expDiff;
shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 );
expDiff += 24;
if ( expDiff < 0 ) {
shift64Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
}
else {
shortShift64Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
}
mul64By32To96( bSig0, bSig1, q, &term0, &term1, &term2 );
sub64( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
}
else {
shift64Right( aSig0, aSig1, 8, &aSig0, &aSig1 );
shift64Right( bSig0, bSig1, 8, &bSig0, &bSig1 );
}
do {
alternateASig0 = aSig0;
alternateASig1 = aSig1;
++q;
sub64( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
} while ( 0 <= (sbits32) aSig0 );
add64(
aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 );
if ( ( sigMean0 < 0 )
|| ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
aSig0 = alternateASig0;
aSig1 = alternateASig1;
}
zSign = ( (sbits32) aSig0 < 0 );
if ( zSign ) sub64( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
return
normalizeRoundAndPackFloat64( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
}
#endif
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns the square root of the double-precision floating-point value `a'.
The operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_sqrt( float64 a )
{
flag aSign;
int16 aExp, zExp;
bits32 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
bits32 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
float64 z;
aSig1 = extractFloat64Frac1( a );
aSig0 = extractFloat64Frac0( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig0 | aSig1 ) return propagateFloat64NaN( a, a );
if ( ! aSign ) return a;
goto invalid;
}
if ( aSign ) {
if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
invalid:
float_raise( float_flag_invalid );
return float64_default_nan;
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat64( 0, 0, 0, 0 );
normalizeFloat64Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
aSig0 |= 0x00100000;
shortShift64Left( aSig0, aSig1, 11, &term0, &term1 );
zSig0 = ( estimateSqrt32( aExp, term0 )>>1 ) + 1;
if ( zSig0 == 0 ) zSig0 = 0x7FFFFFFF;
doubleZSig0 = zSig0 + zSig0;
shortShift64Left( aSig0, aSig1, 9 - ( aExp & 1 ), &aSig0, &aSig1 );
mul32To64( zSig0, zSig0, &term0, &term1 );
sub64( aSig0, aSig1, term0, term1, &rem0, &rem1 );
while ( (sbits32) rem0 < 0 ) {
--zSig0;
doubleZSig0 -= 2;
add64( rem0, rem1, 0, doubleZSig0 | 1, &rem0, &rem1 );
}
zSig1 = estimateDiv64To32( rem1, 0, doubleZSig0 );
if ( ( zSig1 & 0x1FF ) <= 5 ) {
if ( zSig1 == 0 ) zSig1 = 1;
mul32To64( doubleZSig0, zSig1, &term1, &term2 );
sub64( rem1, 0, term1, term2, &rem1, &rem2 );
mul32To64( zSig1, zSig1, &term2, &term3 );
sub96( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
while ( (sbits32) rem1 < 0 ) {
--zSig1;
shortShift64Left( 0, zSig1, 1, &term2, &term3 );
term3 |= 1;
term2 |= doubleZSig0;
add96( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
}
zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
}
shift64ExtraRightJamming( zSig0, zSig1, 0, 10, &zSig0, &zSig1, &zSig2 );
return roundAndPackFloat64( 0, zExp, zSig0, zSig1, zSig2 );
}
#endif
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_eq( float64 a, float64 b )
{
if ( ( ( extractFloat64Exp( a ) == 0x7FF )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF )
&& ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
return ( a == b ) ||
( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than
or equal to the corresponding value `b', and 0 otherwise. The comparison
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_le( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF )
&& ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign )
return aSign ||
( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) ==
0 );
return ( a == b ) ||
( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_lt( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF )
&& ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign )
return aSign &&
( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) !=
0 );
return ( a != b ) &&
( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The invalid exception is
raised if either operand is a NaN. Otherwise, the comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_eq_signaling( float64 a, float64 b )
{
if ( ( ( extractFloat64Exp( a ) == 0x7FF )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF )
&& ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
) {
float_raise( float_flag_invalid );
return 0;
}
return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than or
equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
cause an exception. Otherwise, the comparison is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_le_quiet( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF )
&& ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
return ( a == b ) || ( aSign ^ ( a < b ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
exception. Otherwise, the comparison is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_lt_quiet( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF )
&& ( extractFloat64Frac0( a ) | extractFloat64Frac1( a ) ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF )
&& ( extractFloat64Frac0( b ) | extractFloat64Frac1( b ) ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
return ( a != b ) && ( aSign ^ ( a < b ) );
}
#endif
diff --git a/lib/libc/softfloat/bits64/softfloat.c b/lib/libc/softfloat/bits64/softfloat.c
index 6295a787cb6b..b072588b33fb 100644
--- a/lib/libc/softfloat/bits64/softfloat.c
+++ b/lib/libc/softfloat/bits64/softfloat.c
@@ -1,5597 +1,5596 @@
/* $NetBSD: softfloat.c,v 1.8 2011/07/10 04:52:23 matt Exp $ */
/*
* This version hacked for use with gcc -msoft-float by bjh21.
* (Mostly a case of #ifdefing out things GCC doesn't need or provides
* itself).
*/
/*
* Things you may want to define:
*
* SOFTFLOAT_FOR_GCC - build only those functions necessary for GCC (with
* -msoft-float) to work. Include "softfloat-for-gcc.h" to get them
* properly renamed.
*/
/*
===============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2a.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these four paragraphs for those parts of
this code that are retained.
===============================================================================
*/
-#include <sys/cdefs.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
/*
* Conversions between floats as stored in memory and floats as
* SoftFloat uses them
*/
#ifndef FLOAT64_DEMANGLE
#define FLOAT64_DEMANGLE(a) (a)
#endif
#ifndef FLOAT64_MANGLE
#define FLOAT64_MANGLE(a) (a)
#endif
/*
-------------------------------------------------------------------------------
Floating-point rounding mode, extended double-precision rounding precision,
and exception flags.
-------------------------------------------------------------------------------
*/
int float_rounding_mode = float_round_nearest_even;
int float_exception_flags = 0;
#ifdef FLOATX80
int8 floatx80_rounding_precision = 80;
#endif
/*
-------------------------------------------------------------------------------
Primitive arithmetic functions, including multi-word arithmetic, and
division and square root approximations. (Can be specialized to target if
desired.)
-------------------------------------------------------------------------------
*/
#include "softfloat-macros"
/*
-------------------------------------------------------------------------------
Functions and definitions to determine: (1) whether tininess for underflow
is detected before or after rounding by default, (2) what (if anything)
happens when exceptions are raised, (3) how signaling NaNs are distinguished
from quiet NaNs, (4) the default generated quiet NaNs, and (5) how NaNs
are propagated from function inputs to output. These details are target-
specific.
-------------------------------------------------------------------------------
*/
#include "softfloat-specialize"
#if !defined(SOFTFLOAT_FOR_GCC) || defined(FLOATX80) || defined(FLOAT128)
/*
-------------------------------------------------------------------------------
Takes a 64-bit fixed-point value `absZ' with binary point between bits 6
and 7, and returns the properly rounded 32-bit integer corresponding to the
input. If `zSign' is 1, the input is negated before being converted to an
integer. Bit 63 of `absZ' must be zero. Ordinarily, the fixed-point input
is simply rounded to an integer, with the inexact exception raised if the
input cannot be represented exactly as an integer. However, if the fixed-
point input is too large, the invalid exception is raised and the largest
positive or negative integer is returned.
-------------------------------------------------------------------------------
*/
static int32 roundAndPackInt32( flag zSign, bits64 absZ )
{
int8 roundingMode;
flag roundNearestEven;
int8 roundIncrement, roundBits;
int32 z;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
roundIncrement = 0x40;
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
else {
roundIncrement = 0x7F;
if ( zSign ) {
if ( roundingMode == float_round_up ) roundIncrement = 0;
}
else {
if ( roundingMode == float_round_down ) roundIncrement = 0;
}
}
}
roundBits = absZ & 0x7F;
absZ = ( absZ + roundIncrement )>>7;
absZ &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
z = absZ;
if ( zSign ) z = - z;
if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) {
float_raise( float_flag_invalid );
return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
}
if ( roundBits ) float_exception_flags |= float_flag_inexact;
return z;
}
/*
-------------------------------------------------------------------------------
Takes the 128-bit fixed-point value formed by concatenating `absZ0' and
`absZ1', with binary point between bits 63 and 64 (between the input words),
and returns the properly rounded 64-bit integer corresponding to the input.
If `zSign' is 1, the input is negated before being converted to an integer.
Ordinarily, the fixed-point input is simply rounded to an integer, with
the inexact exception raised if the input cannot be represented exactly as
an integer. However, if the fixed-point input is too large, the invalid
exception is raised and the largest positive or negative integer is
returned.
-------------------------------------------------------------------------------
*/
static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 )
{
int8 roundingMode;
flag roundNearestEven, increment;
int64 z;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
increment = ( (sbits64) absZ1 < 0 );
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
increment = 0;
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && absZ1;
}
else {
increment = ( roundingMode == float_round_up ) && absZ1;
}
}
}
if ( increment ) {
++absZ0;
if ( absZ0 == 0 ) goto overflow;
absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven );
}
z = absZ0;
if ( zSign ) z = - z;
if ( z && ( ( z < 0 ) ^ zSign ) ) {
overflow:
float_raise( float_flag_invalid );
return
zSign ? (sbits64) LIT64( 0x8000000000000000 )
: LIT64( 0x7FFFFFFFFFFFFFFF );
}
if ( absZ1 ) float_exception_flags |= float_flag_inexact;
return z;
}
#endif
/*
-------------------------------------------------------------------------------
Returns the fraction bits of the single-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits32 extractFloat32Frac( float32 a )
{
return a & 0x007FFFFF;
}
/*
-------------------------------------------------------------------------------
Returns the exponent bits of the single-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE int16 extractFloat32Exp( float32 a )
{
return ( a>>23 ) & 0xFF;
}
/*
-------------------------------------------------------------------------------
Returns the sign bit of the single-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE flag extractFloat32Sign( float32 a )
{
return a>>31;
}
/*
-------------------------------------------------------------------------------
Normalizes the subnormal single-precision floating-point value represented
by the denormalized significand `aSig'. The normalized exponent and
significand are stored at the locations pointed to by `zExpPtr' and
`zSigPtr', respectively.
-------------------------------------------------------------------------------
*/
static void
normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr )
{
int8 shiftCount;
shiftCount = countLeadingZeros32( aSig ) - 8;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*
-------------------------------------------------------------------------------
Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
single-precision floating-point value, returning the result. After being
shifted into the proper positions, the three fields are simply added
together to form the result. This means that any integer portion of `zSig'
will be added into the exponent. Since a properly normalized significand
will have an integer portion equal to 1, the `zExp' input should be 1 less
than the desired result exponent whenever `zSig' is a complete, normalized
significand.
-------------------------------------------------------------------------------
*/
INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig )
{
return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig;
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand `zSig', and returns the proper single-precision floating-
point value corresponding to the abstract input. Ordinarily, the abstract
value is simply rounded and packed into the single-precision format, with
the inexact exception raised if the abstract input cannot be represented
exactly. However, if the abstract value is too large, the overflow and
inexact exceptions are raised and an infinity or maximal finite value is
returned. If the abstract value is too small, the input value is rounded to
a subnormal number, and the underflow and inexact exceptions are raised if
the abstract input cannot be represented exactly as a subnormal single-
precision floating-point number.
The input significand `zSig' has its binary point between bits 30
and 29, which is 7 bits to the left of the usual location. This shifted
significand must be normalized or smaller. If `zSig' is not normalized,
`zExp' must be 0; in that case, the result returned is a subnormal number,
and it must not require rounding. In the usual case that `zSig' is
normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
The handling of underflow and overflow follows the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
{
int8 roundingMode;
flag roundNearestEven;
int8 roundIncrement, roundBits;
flag isTiny;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
roundIncrement = 0x40;
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
else {
roundIncrement = 0x7F;
if ( zSign ) {
if ( roundingMode == float_round_up ) roundIncrement = 0;
}
else {
if ( roundingMode == float_round_down ) roundIncrement = 0;
}
}
}
roundBits = zSig & 0x7F;
if ( 0xFD <= (bits16) zExp ) {
if ( ( 0xFD < zExp )
|| ( ( zExp == 0xFD )
&& ( (sbits32) ( zSig + roundIncrement ) < 0 ) )
) {
float_raise( float_flag_overflow | float_flag_inexact );
return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 );
}
if ( zExp < 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < -1 )
|| ( zSig + roundIncrement < 0x80000000 );
shift32RightJamming( zSig, - zExp, &zSig );
zExp = 0;
roundBits = zSig & 0x7F;
if ( isTiny && roundBits ) float_raise( float_flag_underflow );
}
}
if ( roundBits ) float_exception_flags |= float_flag_inexact;
zSig = ( zSig + roundIncrement )>>7;
zSig &= ~ ( ( ( roundBits ^ 0x40 ) == 0 ) & roundNearestEven );
if ( zSig == 0 ) zExp = 0;
return packFloat32( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand `zSig', and returns the proper single-precision floating-
point value corresponding to the abstract input. This routine is just like
`roundAndPackFloat32' except that `zSig' does not have to be normalized.
Bit 31 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
floating-point exponent.
-------------------------------------------------------------------------------
*/
static float32
normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig )
{
int8 shiftCount;
shiftCount = countLeadingZeros32( zSig ) - 1;
return roundAndPackFloat32( zSign, zExp - shiftCount, zSig<<shiftCount );
}
/*
-------------------------------------------------------------------------------
Returns the fraction bits of the double-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits64 extractFloat64Frac( float64 a )
{
return FLOAT64_DEMANGLE(a) & LIT64( 0x000FFFFFFFFFFFFF );
}
/*
-------------------------------------------------------------------------------
Returns the exponent bits of the double-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE int16 extractFloat64Exp( float64 a )
{
return ( FLOAT64_DEMANGLE(a)>>52 ) & 0x7FF;
}
/*
-------------------------------------------------------------------------------
Returns the sign bit of the double-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE flag extractFloat64Sign( float64 a )
{
return FLOAT64_DEMANGLE(a)>>63;
}
/*
-------------------------------------------------------------------------------
Normalizes the subnormal double-precision floating-point value represented
by the denormalized significand `aSig'. The normalized exponent and
significand are stored at the locations pointed to by `zExpPtr' and
`zSigPtr', respectively.
-------------------------------------------------------------------------------
*/
static void
normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr )
{
int8 shiftCount;
shiftCount = countLeadingZeros64( aSig ) - 11;
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*
-------------------------------------------------------------------------------
Packs the sign `zSign', exponent `zExp', and significand `zSig' into a
double-precision floating-point value, returning the result. After being
shifted into the proper positions, the three fields are simply added
together to form the result. This means that any integer portion of `zSig'
will be added into the exponent. Since a properly normalized significand
will have an integer portion equal to 1, the `zExp' input should be 1 less
than the desired result exponent whenever `zSig' is a complete, normalized
significand.
-------------------------------------------------------------------------------
*/
INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig )
{
return FLOAT64_MANGLE( ( ( (bits64) zSign )<<63 ) +
( ( (bits64) zExp )<<52 ) + zSig );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand `zSig', and returns the proper double-precision floating-
point value corresponding to the abstract input. Ordinarily, the abstract
value is simply rounded and packed into the double-precision format, with
the inexact exception raised if the abstract input cannot be represented
exactly. However, if the abstract value is too large, the overflow and
inexact exceptions are raised and an infinity or maximal finite value is
returned. If the abstract value is too small, the input value is rounded to
a subnormal number, and the underflow and inexact exceptions are raised if
the abstract input cannot be represented exactly as a subnormal double-
precision floating-point number.
The input significand `zSig' has its binary point between bits 62
and 61, which is 10 bits to the left of the usual location. This shifted
significand must be normalized or smaller. If `zSig' is not normalized,
`zExp' must be 0; in that case, the result returned is a subnormal number,
and it must not require rounding. In the usual case that `zSig' is
normalized, `zExp' must be 1 less than the ``true'' floating-point exponent.
The handling of underflow and overflow follows the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig )
{
int8 roundingMode;
flag roundNearestEven;
int16 roundIncrement, roundBits;
flag isTiny;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
roundIncrement = 0x200;
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
else {
roundIncrement = 0x3FF;
if ( zSign ) {
if ( roundingMode == float_round_up ) roundIncrement = 0;
}
else {
if ( roundingMode == float_round_down ) roundIncrement = 0;
}
}
}
roundBits = zSig & 0x3FF;
if ( 0x7FD <= (bits16) zExp ) {
if ( ( 0x7FD < zExp )
|| ( ( zExp == 0x7FD )
&& ( (sbits64) ( zSig + roundIncrement ) < 0 ) )
) {
float_raise( float_flag_overflow | float_flag_inexact );
return FLOAT64_MANGLE(
FLOAT64_DEMANGLE(packFloat64( zSign, 0x7FF, 0 )) -
( roundIncrement == 0 ));
}
if ( zExp < 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < -1 )
|| ( zSig + roundIncrement < LIT64( 0x8000000000000000 ) );
shift64RightJamming( zSig, - zExp, &zSig );
zExp = 0;
roundBits = zSig & 0x3FF;
if ( isTiny && roundBits ) float_raise( float_flag_underflow );
}
}
if ( roundBits ) float_exception_flags |= float_flag_inexact;
zSig = ( zSig + roundIncrement )>>10;
zSig &= ~ ( ( ( roundBits ^ 0x200 ) == 0 ) & roundNearestEven );
if ( zSig == 0 ) zExp = 0;
return packFloat64( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand `zSig', and returns the proper double-precision floating-
point value corresponding to the abstract input. This routine is just like
`roundAndPackFloat64' except that `zSig' does not have to be normalized.
Bit 63 of `zSig' must be zero, and `zExp' must be 1 less than the ``true''
floating-point exponent.
-------------------------------------------------------------------------------
*/
static float64
normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig )
{
int8 shiftCount;
shiftCount = countLeadingZeros64( zSig ) - 1;
return roundAndPackFloat64( zSign, zExp - shiftCount, zSig<<shiftCount );
}
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Returns the fraction bits of the extended double-precision floating-point
value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits64 extractFloatx80Frac( floatx80 a )
{
return a.low;
}
/*
-------------------------------------------------------------------------------
Returns the exponent bits of the extended double-precision floating-point
value `a'.
-------------------------------------------------------------------------------
*/
INLINE int32 extractFloatx80Exp( floatx80 a )
{
return a.high & 0x7FFF;
}
/*
-------------------------------------------------------------------------------
Returns the sign bit of the extended double-precision floating-point value
`a'.
-------------------------------------------------------------------------------
*/
INLINE flag extractFloatx80Sign( floatx80 a )
{
return a.high>>15;
}
/*
-------------------------------------------------------------------------------
Normalizes the subnormal extended double-precision floating-point value
represented by the denormalized significand `aSig'. The normalized exponent
and significand are stored at the locations pointed to by `zExpPtr' and
`zSigPtr', respectively.
-------------------------------------------------------------------------------
*/
static void
normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr )
{
int8 shiftCount;
shiftCount = countLeadingZeros64( aSig );
*zSigPtr = aSig<<shiftCount;
*zExpPtr = 1 - shiftCount;
}
/*
-------------------------------------------------------------------------------
Packs the sign `zSign', exponent `zExp', and significand `zSig' into an
extended double-precision floating-point value, returning the result.
-------------------------------------------------------------------------------
*/
INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig )
{
floatx80 z;
z.low = zSig;
z.high = ( ( (bits16) zSign )<<15 ) + zExp;
return z;
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and extended significand formed by the concatenation of `zSig0' and `zSig1',
and returns the proper extended double-precision floating-point value
corresponding to the abstract input. Ordinarily, the abstract value is
rounded and packed into the extended double-precision format, with the
inexact exception raised if the abstract input cannot be represented
exactly. However, if the abstract value is too large, the overflow and
inexact exceptions are raised and an infinity or maximal finite value is
returned. If the abstract value is too small, the input value is rounded to
a subnormal number, and the underflow and inexact exceptions are raised if
the abstract input cannot be represented exactly as a subnormal extended
double-precision floating-point number.
If `roundingPrecision' is 32 or 64, the result is rounded to the same
number of bits as single or double precision, respectively. Otherwise, the
result is rounded to the full precision of the extended double-precision
format.
The input significand must be normalized or smaller. If the input
significand is not normalized, `zExp' must be 0; in that case, the result
returned is a subnormal number, and it must not require rounding. The
handling of underflow and overflow follows the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static floatx80
roundAndPackFloatx80(
int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
)
{
int8 roundingMode;
flag roundNearestEven, increment, isTiny;
int64 roundIncrement, roundMask, roundBits;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
if ( roundingPrecision == 80 ) goto precision80;
if ( roundingPrecision == 64 ) {
roundIncrement = LIT64( 0x0000000000000400 );
roundMask = LIT64( 0x00000000000007FF );
}
else if ( roundingPrecision == 32 ) {
roundIncrement = LIT64( 0x0000008000000000 );
roundMask = LIT64( 0x000000FFFFFFFFFF );
}
else {
goto precision80;
}
zSig0 |= ( zSig1 != 0 );
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
roundIncrement = 0;
}
else {
roundIncrement = roundMask;
if ( zSign ) {
if ( roundingMode == float_round_up ) roundIncrement = 0;
}
else {
if ( roundingMode == float_round_down ) roundIncrement = 0;
}
}
}
roundBits = zSig0 & roundMask;
if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
if ( ( 0x7FFE < zExp )
|| ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
) {
goto overflow;
}
if ( zExp <= 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < 0 )
|| ( zSig0 <= zSig0 + roundIncrement );
shift64RightJamming( zSig0, 1 - zExp, &zSig0 );
zExp = 0;
roundBits = zSig0 & roundMask;
if ( isTiny && roundBits ) float_raise( float_flag_underflow );
if ( roundBits ) float_exception_flags |= float_flag_inexact;
zSig0 += roundIncrement;
if ( (sbits64) zSig0 < 0 ) zExp = 1;
roundIncrement = roundMask + 1;
if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
roundMask |= roundIncrement;
}
zSig0 &= ~ roundMask;
return packFloatx80( zSign, zExp, zSig0 );
}
}
if ( roundBits ) float_exception_flags |= float_flag_inexact;
zSig0 += roundIncrement;
if ( zSig0 < roundIncrement ) {
++zExp;
zSig0 = LIT64( 0x8000000000000000 );
}
roundIncrement = roundMask + 1;
if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
roundMask |= roundIncrement;
}
zSig0 &= ~ roundMask;
if ( zSig0 == 0 ) zExp = 0;
return packFloatx80( zSign, zExp, zSig0 );
precision80:
increment = ( (sbits64) zSig1 < 0 );
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
increment = 0;
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig1;
}
else {
increment = ( roundingMode == float_round_up ) && zSig1;
}
}
}
if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
if ( ( 0x7FFE < zExp )
|| ( ( zExp == 0x7FFE )
&& ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) )
&& increment
)
) {
roundMask = 0;
overflow:
float_raise( float_flag_overflow | float_flag_inexact );
if ( ( roundingMode == float_round_to_zero )
|| ( zSign && ( roundingMode == float_round_up ) )
|| ( ! zSign && ( roundingMode == float_round_down ) )
) {
return packFloatx80( zSign, 0x7FFE, ~ roundMask );
}
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( zExp <= 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < 0 )
|| ! increment
|| ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) );
shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 );
zExp = 0;
if ( isTiny && zSig1 ) float_raise( float_flag_underflow );
if ( zSig1 ) float_exception_flags |= float_flag_inexact;
if ( roundNearestEven ) {
increment = ( (sbits64) zSig1 < 0 );
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig1;
}
else {
increment = ( roundingMode == float_round_up ) && zSig1;
}
}
if ( increment ) {
++zSig0;
zSig0 &=
~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven );
if ( (sbits64) zSig0 < 0 ) zExp = 1;
}
return packFloatx80( zSign, zExp, zSig0 );
}
}
if ( zSig1 ) float_exception_flags |= float_flag_inexact;
if ( increment ) {
++zSig0;
if ( zSig0 == 0 ) {
++zExp;
zSig0 = LIT64( 0x8000000000000000 );
}
else {
zSig0 &= ~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven );
}
}
else {
if ( zSig0 == 0 ) zExp = 0;
}
return packFloatx80( zSign, zExp, zSig0 );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent
`zExp', and significand formed by the concatenation of `zSig0' and `zSig1',
and returns the proper extended double-precision floating-point value
corresponding to the abstract input. This routine is just like
`roundAndPackFloatx80' except that the input significand does not have to be
normalized.
-------------------------------------------------------------------------------
*/
static floatx80
normalizeRoundAndPackFloatx80(
int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
)
{
int8 shiftCount;
if ( zSig0 == 0 ) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 64;
}
shiftCount = countLeadingZeros64( zSig0 );
shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
zExp -= shiftCount;
return
roundAndPackFloatx80( roundingPrecision, zSign, zExp, zSig0, zSig1 );
}
#endif
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Returns the least-significant 64 fraction bits of the quadruple-precision
floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits64 extractFloat128Frac1( float128 a )
{
return a.low;
}
/*
-------------------------------------------------------------------------------
Returns the most-significant 48 fraction bits of the quadruple-precision
floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE bits64 extractFloat128Frac0( float128 a )
{
return a.high & LIT64( 0x0000FFFFFFFFFFFF );
}
/*
-------------------------------------------------------------------------------
Returns the exponent bits of the quadruple-precision floating-point value
`a'.
-------------------------------------------------------------------------------
*/
INLINE int32 extractFloat128Exp( float128 a )
{
return ( a.high>>48 ) & 0x7FFF;
}
/*
-------------------------------------------------------------------------------
Returns the sign bit of the quadruple-precision floating-point value `a'.
-------------------------------------------------------------------------------
*/
INLINE flag extractFloat128Sign( float128 a )
{
return a.high>>63;
}
/*
-------------------------------------------------------------------------------
Normalizes the subnormal quadruple-precision floating-point value
represented by the denormalized significand formed by the concatenation of
`aSig0' and `aSig1'. The normalized exponent is stored at the location
pointed to by `zExpPtr'. The most significant 49 bits of the normalized
significand are stored at the location pointed to by `zSig0Ptr', and the
least significant 64 bits of the normalized significand are stored at the
location pointed to by `zSig1Ptr'.
-------------------------------------------------------------------------------
*/
static void
normalizeFloat128Subnormal(
bits64 aSig0,
bits64 aSig1,
int32 *zExpPtr,
bits64 *zSig0Ptr,
bits64 *zSig1Ptr
)
{
int8 shiftCount;
if ( aSig0 == 0 ) {
shiftCount = countLeadingZeros64( aSig1 ) - 15;
if ( shiftCount < 0 ) {
*zSig0Ptr = aSig1>>( - shiftCount );
*zSig1Ptr = aSig1<<( shiftCount & 63 );
}
else {
*zSig0Ptr = aSig1<<shiftCount;
*zSig1Ptr = 0;
}
*zExpPtr = - shiftCount - 63;
}
else {
shiftCount = countLeadingZeros64( aSig0 ) - 15;
shortShift128Left( aSig0, aSig1, shiftCount, zSig0Ptr, zSig1Ptr );
*zExpPtr = 1 - shiftCount;
}
}
/*
-------------------------------------------------------------------------------
Packs the sign `zSign', the exponent `zExp', and the significand formed
by the concatenation of `zSig0' and `zSig1' into a quadruple-precision
floating-point value, returning the result. After being shifted into the
proper positions, the three fields `zSign', `zExp', and `zSig0' are simply
added together to form the most significant 32 bits of the result. This
means that any integer portion of `zSig0' will be added into the exponent.
Since a properly normalized significand will have an integer portion equal
to 1, the `zExp' input should be 1 less than the desired result exponent
whenever `zSig0' and `zSig1' concatenated form a complete, normalized
significand.
-------------------------------------------------------------------------------
*/
INLINE float128
packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
{
float128 z;
z.low = zSig1;
z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0;
return z;
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and extended significand formed by the concatenation of `zSig0', `zSig1',
and `zSig2', and returns the proper quadruple-precision floating-point value
corresponding to the abstract input. Ordinarily, the abstract value is
simply rounded and packed into the quadruple-precision format, with the
inexact exception raised if the abstract input cannot be represented
exactly. However, if the abstract value is too large, the overflow and
inexact exceptions are raised and an infinity or maximal finite value is
returned. If the abstract value is too small, the input value is rounded to
a subnormal number, and the underflow and inexact exceptions are raised if
the abstract input cannot be represented exactly as a subnormal quadruple-
precision floating-point number.
The input significand must be normalized or smaller. If the input
significand is not normalized, `zExp' must be 0; in that case, the result
returned is a subnormal number, and it must not require rounding. In the
usual case that the input significand is normalized, `zExp' must be 1 less
than the ``true'' floating-point exponent. The handling of underflow and
overflow follows the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float128
roundAndPackFloat128(
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 )
{
int8 roundingMode;
flag roundNearestEven, increment, isTiny;
roundingMode = float_rounding_mode;
roundNearestEven = ( roundingMode == float_round_nearest_even );
increment = ( (sbits64) zSig2 < 0 );
if ( ! roundNearestEven ) {
if ( roundingMode == float_round_to_zero ) {
increment = 0;
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig2;
}
else {
increment = ( roundingMode == float_round_up ) && zSig2;
}
}
}
if ( 0x7FFD <= (bits32) zExp ) {
if ( ( 0x7FFD < zExp )
|| ( ( zExp == 0x7FFD )
&& eq128(
LIT64( 0x0001FFFFFFFFFFFF ),
LIT64( 0xFFFFFFFFFFFFFFFF ),
zSig0,
zSig1
)
&& increment
)
) {
float_raise( float_flag_overflow | float_flag_inexact );
if ( ( roundingMode == float_round_to_zero )
|| ( zSign && ( roundingMode == float_round_up ) )
|| ( ! zSign && ( roundingMode == float_round_down ) )
) {
return
packFloat128(
zSign,
0x7FFE,
LIT64( 0x0000FFFFFFFFFFFF ),
LIT64( 0xFFFFFFFFFFFFFFFF )
);
}
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( zExp < 0 ) {
isTiny =
( float_detect_tininess == float_tininess_before_rounding )
|| ( zExp < -1 )
|| ! increment
|| lt128(
zSig0,
zSig1,
LIT64( 0x0001FFFFFFFFFFFF ),
LIT64( 0xFFFFFFFFFFFFFFFF )
);
shift128ExtraRightJamming(
zSig0, zSig1, zSig2, - zExp, &zSig0, &zSig1, &zSig2 );
zExp = 0;
if ( isTiny && zSig2 ) float_raise( float_flag_underflow );
if ( roundNearestEven ) {
increment = ( (sbits64) zSig2 < 0 );
}
else {
if ( zSign ) {
increment = ( roundingMode == float_round_down ) && zSig2;
}
else {
increment = ( roundingMode == float_round_up ) && zSig2;
}
}
}
}
if ( zSig2 ) float_exception_flags |= float_flag_inexact;
if ( increment ) {
add128( zSig0, zSig1, 0, 1, &zSig0, &zSig1 );
zSig1 &= ~ ( ( zSig2 + zSig2 == 0 ) & roundNearestEven );
}
else {
if ( ( zSig0 | zSig1 ) == 0 ) zExp = 0;
}
return packFloat128( zSign, zExp, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and significand formed by the concatenation of `zSig0' and `zSig1', and
returns the proper quadruple-precision floating-point value corresponding
to the abstract input. This routine is just like `roundAndPackFloat128'
except that the input significand has fewer bits and does not have to be
normalized. In all cases, `zExp' must be 1 less than the ``true'' floating-
point exponent.
-------------------------------------------------------------------------------
*/
static float128
normalizeRoundAndPackFloat128(
flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 )
{
int8 shiftCount;
bits64 zSig2;
if ( zSig0 == 0 ) {
zSig0 = zSig1;
zSig1 = 0;
zExp -= 64;
}
shiftCount = countLeadingZeros64( zSig0 ) - 15;
if ( 0 <= shiftCount ) {
zSig2 = 0;
shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
}
else {
shift128ExtraRightJamming(
zSig0, zSig1, 0, - shiftCount, &zSig0, &zSig1, &zSig2 );
}
zExp -= shiftCount;
return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
}
#endif
/*
-------------------------------------------------------------------------------
Returns the result of converting the 32-bit two's complement integer `a'
to the single-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 int32_to_float32( int32 a )
{
flag zSign;
if ( a == 0 ) return 0;
if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 );
zSign = ( a < 0 );
return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a );
}
#ifndef SOFTFLOAT_FOR_GCC /* __floatunsisf is in libgcc */
float32 uint32_to_float32( uint32 a )
{
if ( a == 0 ) return 0;
if ( a & (bits32) 0x80000000 )
return normalizeRoundAndPackFloat32( 0, 0x9D, a >> 1 );
return normalizeRoundAndPackFloat32( 0, 0x9C, a );
}
#endif
/*
-------------------------------------------------------------------------------
Returns the result of converting the 32-bit two's complement integer `a'
to the double-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 int32_to_float64( int32 a )
{
flag zSign;
uint32 absA;
int8 shiftCount;
bits64 zSig;
if ( a == 0 ) return 0;
zSign = ( a < 0 );
absA = zSign ? - a : a;
shiftCount = countLeadingZeros32( absA ) + 21;
zSig = absA;
return packFloat64( zSign, 0x432 - shiftCount, zSig<<shiftCount );
}
#ifndef SOFTFLOAT_FOR_GCC /* __floatunsidf is in libgcc */
float64 uint32_to_float64( uint32 a )
{
int8 shiftCount;
bits64 zSig = a;
if ( a == 0 ) return 0;
shiftCount = countLeadingZeros32( a ) + 21;
return packFloat64( 0, 0x432 - shiftCount, zSig<<shiftCount );
}
#endif
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Returns the result of converting the 32-bit two's complement integer `a'
to the extended double-precision floating-point format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 int32_to_floatx80( int32 a )
{
flag zSign;
uint32 absA;
int8 shiftCount;
bits64 zSig;
if ( a == 0 ) return packFloatx80( 0, 0, 0 );
zSign = ( a < 0 );
absA = zSign ? - a : a;
shiftCount = countLeadingZeros32( absA ) + 32;
zSig = absA;
return packFloatx80( zSign, 0x403E - shiftCount, zSig<<shiftCount );
}
floatx80 uint32_to_floatx80( uint32 a )
{
int8 shiftCount;
bits64 zSig = a;
if ( a == 0 ) return packFloatx80( 0, 0, 0 );
shiftCount = countLeadingZeros32( a ) + 32;
return packFloatx80( 0, 0x403E - shiftCount, zSig<<shiftCount );
}
#endif
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Returns the result of converting the 32-bit two's complement integer `a' to
the quadruple-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 int32_to_float128( int32 a )
{
flag zSign;
uint32 absA;
int8 shiftCount;
bits64 zSig0;
if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
zSign = ( a < 0 );
absA = zSign ? - a : a;
shiftCount = countLeadingZeros32( absA ) + 17;
zSig0 = absA;
return packFloat128( zSign, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
}
float128 uint32_to_float128( uint32 a )
{
int8 shiftCount;
bits64 zSig0 = a;
if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
shiftCount = countLeadingZeros32( a ) + 17;
return packFloat128( 0, 0x402E - shiftCount, zSig0<<shiftCount, 0 );
}
#endif
#ifndef SOFTFLOAT_FOR_GCC /* __floatdi?f is in libgcc2.c */
/*
-------------------------------------------------------------------------------
Returns the result of converting the 64-bit two's complement integer `a'
to the single-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 int64_to_float32( int64 a )
{
flag zSign;
uint64 absA;
int8 shiftCount;
if ( a == 0 ) return 0;
zSign = ( a < 0 );
absA = zSign ? - a : a;
shiftCount = countLeadingZeros64( absA ) - 40;
if ( 0 <= shiftCount ) {
return packFloat32( zSign, 0x95 - shiftCount, absA<<shiftCount );
}
else {
shiftCount += 7;
if ( shiftCount < 0 ) {
shift64RightJamming( absA, - shiftCount, &absA );
}
else {
absA <<= shiftCount;
}
return roundAndPackFloat32( zSign, 0x9C - shiftCount, absA );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the 64-bit two's complement integer `a'
to the double-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 int64_to_float64( int64 a )
{
flag zSign;
if ( a == 0 ) return 0;
if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) {
return packFloat64( 1, 0x43E, 0 );
}
zSign = ( a < 0 );
return normalizeRoundAndPackFloat64( zSign, 0x43C, zSign ? - a : a );
}
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Returns the result of converting the 64-bit two's complement integer `a'
to the extended double-precision floating-point format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 int64_to_floatx80( int64 a )
{
flag zSign;
uint64 absA;
int8 shiftCount;
if ( a == 0 ) return packFloatx80( 0, 0, 0 );
zSign = ( a < 0 );
absA = zSign ? - a : a;
shiftCount = countLeadingZeros64( absA );
return packFloatx80( zSign, 0x403E - shiftCount, absA<<shiftCount );
}
#endif
#endif /* !SOFTFLOAT_FOR_GCC */
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Returns the result of converting the 64-bit two's complement integer `a' to
the quadruple-precision floating-point format. The conversion is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 int64_to_float128( int64 a )
{
flag zSign;
uint64 absA;
int8 shiftCount;
int32 zExp;
bits64 zSig0, zSig1;
if ( a == 0 ) return packFloat128( 0, 0, 0, 0 );
zSign = ( a < 0 );
absA = zSign ? - a : a;
shiftCount = countLeadingZeros64( absA ) + 49;
zExp = 0x406E - shiftCount;
if ( 64 <= shiftCount ) {
zSig1 = 0;
zSig0 = absA;
shiftCount -= 64;
}
else {
zSig1 = absA;
zSig0 = 0;
}
shortShift128Left( zSig0, zSig1, shiftCount, &zSig0, &zSig1 );
return packFloat128( zSign, zExp, zSig0, zSig1 );
}
#endif
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int32 float32_to_int32( float32 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig;
bits64 aSig64;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( ( aExp == 0xFF ) && aSig ) aSign = 0;
if ( aExp ) aSig |= 0x00800000;
shiftCount = 0xAF - aExp;
aSig64 = aSig;
aSig64 <<= 32;
if ( 0 < shiftCount ) shift64RightJamming( aSig64, shiftCount, &aSig64 );
return roundAndPackInt32( aSign, aSig64 );
}
#endif /* !SOFTFLOAT_FOR_GCC */
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero.
If `a' is a NaN, the largest positive integer is returned. Otherwise, if
the conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int32 float32_to_int32_round_to_zero( float32 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig;
int32 z;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
shiftCount = aExp - 0x9E;
if ( 0 <= shiftCount ) {
if ( a != 0xCF000000 ) {
float_raise( float_flag_invalid );
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF;
}
return (sbits32) 0x80000000;
}
else if ( aExp <= 0x7E ) {
if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
aSig = ( aSig | 0x00800000 )<<8;
z = aSig>>( - shiftCount );
if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) {
float_exception_flags |= float_flag_inexact;
}
if ( aSign ) z = - z;
return z;
}
#ifndef SOFTFLOAT_FOR_GCC /* __fix?fdi provided by libgcc2.c */
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the 64-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int64 float32_to_int64( float32 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig;
bits64 aSig64, aSigExtra;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
shiftCount = 0xBE - aExp;
if ( shiftCount < 0 ) {
float_raise( float_flag_invalid );
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
return (sbits64) LIT64( 0x8000000000000000 );
}
if ( aExp ) aSig |= 0x00800000;
aSig64 = aSig;
aSig64 <<= 40;
shift64ExtraRightJamming( aSig64, 0, shiftCount, &aSig64, &aSigExtra );
return roundAndPackInt64( aSign, aSig64, aSigExtra );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the 64-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero. If
`a' is a NaN, the largest positive integer is returned. Otherwise, if the
conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int64 float32_to_int64_round_to_zero( float32 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig;
bits64 aSig64;
int64 z;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
shiftCount = aExp - 0xBE;
if ( 0 <= shiftCount ) {
if ( a != 0xDF000000 ) {
float_raise( float_flag_invalid );
if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
}
return (sbits64) LIT64( 0x8000000000000000 );
}
else if ( aExp <= 0x7E ) {
if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
aSig64 = aSig | 0x00800000;
aSig64 <<= 40;
z = aSig64>>( - shiftCount );
if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) {
float_exception_flags |= float_flag_inexact;
}
if ( aSign ) z = - z;
return z;
}
#endif /* !SOFTFLOAT_FOR_GCC */
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the double-precision floating-point format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float32_to_float64( float32 a )
{
flag aSign;
int16 aExp;
bits32 aSig;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a ) );
return packFloat64( aSign, 0x7FF, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat64( aSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
--aExp;
}
return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 );
}
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the extended double-precision floating-point format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 float32_to_floatx80( float32 a )
{
flag aSign;
int16 aExp;
bits32 aSig;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a ) );
return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
aSig |= 0x00800000;
return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 );
}
#endif
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the double-precision floating-point format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float32_to_float128( float32 a )
{
flag aSign;
int16 aExp;
bits32 aSig;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a ) );
return packFloat128( aSign, 0x7FFF, 0, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
--aExp;
}
return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 );
}
#endif
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Rounds the single-precision floating-point value `a' to an integer, and
returns the result as a single-precision floating-point value. The
operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_round_to_int( float32 a )
{
flag aSign;
int16 aExp;
bits32 lastBitMask, roundBitsMask;
int8 roundingMode;
float32 z;
aExp = extractFloat32Exp( a );
if ( 0x96 <= aExp ) {
if ( ( aExp == 0xFF ) && extractFloat32Frac( a ) ) {
return propagateFloat32NaN( a, a );
}
return a;
}
if ( aExp <= 0x7E ) {
if ( (bits32) ( a<<1 ) == 0 ) return a;
float_exception_flags |= float_flag_inexact;
aSign = extractFloat32Sign( a );
switch ( float_rounding_mode ) {
case float_round_nearest_even:
if ( ( aExp == 0x7E ) && extractFloat32Frac( a ) ) {
return packFloat32( aSign, 0x7F, 0 );
}
break;
case float_round_to_zero:
break;
case float_round_down:
return aSign ? 0xBF800000 : 0;
case float_round_up:
return aSign ? 0x80000000 : 0x3F800000;
}
return packFloat32( aSign, 0, 0 );
}
lastBitMask = 1;
lastBitMask <<= 0x96 - aExp;
roundBitsMask = lastBitMask - 1;
z = a;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
z += lastBitMask>>1;
if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) {
z += roundBitsMask;
}
}
z &= ~ roundBitsMask;
if ( z != a ) float_exception_flags |= float_flag_inexact;
return z;
}
#endif /* !SOFTFLOAT_FOR_GCC */
/*
-------------------------------------------------------------------------------
Returns the result of adding the absolute values of the single-precision
floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
before being returned. `zSign' is ignored if the result is a NaN.
The addition is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float32 addFloat32Sigs( float32 a, float32 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
expDiff = aExp - bExp;
aSig <<= 6;
bSig <<= 6;
if ( 0 < expDiff ) {
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= 0x20000000;
}
shift32RightJamming( bSig, expDiff, &bSig );
zExp = aExp;
}
else if ( expDiff < 0 ) {
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign, 0xFF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= 0x20000000;
}
shift32RightJamming( aSig, - expDiff, &aSig );
zExp = bExp;
}
else {
if ( aExp == 0xFF ) {
if ( aSig | bSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 );
zSig = 0x40000000 + aSig + bSig;
zExp = aExp;
goto roundAndPack;
}
aSig |= 0x20000000;
zSig = ( aSig + bSig )<<1;
--zExp;
if ( (sbits32) zSig < 0 ) {
zSig = aSig + bSig;
++zExp;
}
roundAndPack:
return roundAndPackFloat32( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the absolute values of the single-
precision floating-point values `a' and `b'. If `zSign' is 1, the
difference is negated before being returned. `zSign' is ignored if the
result is a NaN. The subtraction is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float32 subFloat32Sigs( float32 a, float32 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
expDiff = aExp - bExp;
aSig <<= 7;
bSig <<= 7;
if ( 0 < expDiff ) goto aExpBigger;
if ( expDiff < 0 ) goto bExpBigger;
if ( aExp == 0xFF ) {
if ( aSig | bSig ) return propagateFloat32NaN( a, b );
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( aExp == 0 ) {
aExp = 1;
bExp = 1;
}
if ( bSig < aSig ) goto aBigger;
if ( aSig < bSig ) goto bBigger;
return packFloat32( float_rounding_mode == float_round_down, 0, 0 );
bExpBigger:
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign ^ 1, 0xFF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= 0x40000000;
}
shift32RightJamming( aSig, - expDiff, &aSig );
bSig |= 0x40000000;
bBigger:
zSig = bSig - aSig;
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= 0x40000000;
}
shift32RightJamming( bSig, expDiff, &bSig );
aSig |= 0x40000000;
aBigger:
zSig = aSig - bSig;
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat32( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the single-precision floating-point values `a'
and `b'. The operation is performed according to the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_add( float32 a, float32 b )
{
flag aSign, bSign;
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign == bSign ) {
return addFloat32Sigs( a, b, aSign );
}
else {
return subFloat32Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the single-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_sub( float32 a, float32 b )
{
flag aSign, bSign;
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign == bSign ) {
return subFloat32Sigs( a, b, aSign );
}
else {
return addFloat32Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of multiplying the single-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_mul( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig, bSig;
bits64 zSig64;
bits32 zSig;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0xFF ) {
if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
return propagateFloat32NaN( a, b );
}
if ( ( bExp | bSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
if ( ( aExp | aSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
}
zExp = aExp + bExp - 0x7F;
aSig = ( aSig | 0x00800000 )<<7;
bSig = ( bSig | 0x00800000 )<<8;
shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 );
zSig = zSig64;
if ( 0 <= (sbits32) ( zSig<<1 ) ) {
zSig <<= 1;
--zExp;
}
return roundAndPackFloat32( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of dividing the single-precision floating-point value `a'
by the corresponding value `b'. The operation is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_div( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits32 aSig, bSig, zSig;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, b );
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
float_raise( float_flag_invalid );
return float32_default_nan;
}
return packFloat32( zSign, 0xFF, 0 );
}
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return packFloat32( zSign, 0, 0 );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
if ( ( aExp | aSig ) == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
float_raise( float_flag_divbyzero );
return packFloat32( zSign, 0xFF, 0 );
}
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat32( zSign, 0, 0 );
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
zExp = aExp - bExp + 0x7D;
aSig = ( aSig | 0x00800000 )<<7;
bSig = ( bSig | 0x00800000 )<<8;
if ( bSig <= ( aSig + aSig ) ) {
aSig >>= 1;
++zExp;
}
zSig = ( ( (bits64) aSig )<<32 ) / bSig;
if ( ( zSig & 0x3F ) == 0 ) {
zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 );
}
return roundAndPackFloat32( zSign, zExp, zSig );
}
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns the remainder of the single-precision floating-point value `a'
with respect to the corresponding value `b'. The operation is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_rem( float32 a, float32 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, expDiff;
bits32 aSig, bSig;
bits32 q;
bits64 aSig64, bSig64, q64;
bits32 alternateASig;
sbits32 sigMean;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
bSig = extractFloat32Frac( b );
bExp = extractFloat32Exp( b );
bSign = extractFloat32Sign( b );
if ( aExp == 0xFF ) {
if ( aSig || ( ( bExp == 0xFF ) && bSig ) ) {
return propagateFloat32NaN( a, b );
}
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( bExp == 0xFF ) {
if ( bSig ) return propagateFloat32NaN( a, b );
return a;
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
float_raise( float_flag_invalid );
return float32_default_nan;
}
normalizeFloat32Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return a;
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
expDiff = aExp - bExp;
aSig |= 0x00800000;
bSig |= 0x00800000;
if ( expDiff < 32 ) {
aSig <<= 8;
bSig <<= 8;
if ( expDiff < 0 ) {
if ( expDiff < -1 ) return a;
aSig >>= 1;
}
q = ( bSig <= aSig );
if ( q ) aSig -= bSig;
if ( 0 < expDiff ) {
q = ( ( (bits64) aSig )<<32 ) / bSig;
q >>= 32 - expDiff;
bSig >>= 2;
aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
}
else {
aSig >>= 2;
bSig >>= 2;
}
}
else {
if ( bSig <= aSig ) aSig -= bSig;
aSig64 = ( (bits64) aSig )<<40;
bSig64 = ( (bits64) bSig )<<40;
expDiff -= 64;
while ( 0 < expDiff ) {
q64 = estimateDiv128To64( aSig64, 0, bSig64 );
q64 = ( 2 < q64 ) ? q64 - 2 : 0;
aSig64 = - ( ( bSig * q64 )<<38 );
expDiff -= 62;
}
expDiff += 64;
q64 = estimateDiv128To64( aSig64, 0, bSig64 );
q64 = ( 2 < q64 ) ? q64 - 2 : 0;
q = q64>>( 64 - expDiff );
bSig <<= 6;
aSig = ( ( aSig64>>33 )<<( expDiff - 1 ) ) - bSig * q;
}
do {
alternateASig = aSig;
++q;
aSig -= bSig;
} while ( 0 <= (sbits32) aSig );
sigMean = aSig + alternateASig;
if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
aSig = alternateASig;
}
zSign = ( (sbits32) aSig < 0 );
if ( zSign ) aSig = - aSig;
return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig );
}
#endif /* !SOFTFLOAT_FOR_GCC */
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns the square root of the single-precision floating-point value `a'.
The operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float32_sqrt( float32 a )
{
flag aSign;
int16 aExp, zExp;
bits32 aSig, zSig;
bits64 rem, term;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if ( aSig ) return propagateFloat32NaN( a, 0 );
if ( ! aSign ) return a;
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( aSign ) {
if ( ( aExp | aSig ) == 0 ) return a;
float_raise( float_flag_invalid );
return float32_default_nan;
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return 0;
normalizeFloat32Subnormal( aSig, &aExp, &aSig );
}
zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E;
aSig = ( aSig | 0x00800000 )<<8;
zSig = estimateSqrt32( aExp, aSig ) + 2;
if ( ( zSig & 0x7F ) <= 5 ) {
if ( zSig < 2 ) {
zSig = 0x7FFFFFFF;
goto roundAndPack;
}
aSig >>= aExp & 1;
term = ( (bits64) zSig ) * zSig;
rem = ( ( (bits64) aSig )<<32 ) - term;
while ( (sbits64) rem < 0 ) {
--zSig;
rem += ( ( (bits64) zSig )<<1 ) | 1;
}
zSig |= ( rem != 0 );
}
shift32RightJamming( zSig, 1, &zSig );
roundAndPack:
return roundAndPackFloat32( 0, zExp, zSig );
}
#endif /* !SOFTFLOAT_FOR_GCC */
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_eq( float32 a, float32 b )
{
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than
or equal to the corresponding value `b', and 0 otherwise. The comparison
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_le( float32 a, float32 b )
{
flag aSign, bSign;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
return ( a == b ) || ( aSign ^ ( a < b ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_lt( float32 a, float32 b )
{
flag aSign, bSign;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
return ( a != b ) && ( aSign ^ ( a < b ) );
}
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The invalid exception is
raised if either operand is a NaN. Otherwise, the comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_eq_signaling( float32 a, float32 b )
{
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than or
equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
cause an exception. Otherwise, the comparison is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_le_quiet( float32 a, float32 b )
{
flag aSign, bSign;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 );
return ( a == b ) || ( aSign ^ ( a < b ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the single-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
exception. Otherwise, the comparison is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float32_lt_quiet( float32 a, float32 b )
{
flag aSign, bSign;
if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) )
|| ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) )
) {
if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat32Sign( a );
bSign = extractFloat32Sign( b );
if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 );
return ( a != b ) && ( aSign ^ ( a < b ) );
}
#endif /* !SOFTFLOAT_FOR_GCC */
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int32 float64_to_int32( float64 a )
{
flag aSign;
int16 aExp, shiftCount;
bits64 aSig;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
shiftCount = 0x42C - aExp;
if ( 0 < shiftCount ) shift64RightJamming( aSig, shiftCount, &aSig );
return roundAndPackInt32( aSign, aSig );
}
#endif /* !SOFTFLOAT_FOR_GCC */
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the 32-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero.
If `a' is a NaN, the largest positive integer is returned. Otherwise, if
the conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int32 float64_to_int32_round_to_zero( float64 a )
{
flag aSign;
int16 aExp, shiftCount;
bits64 aSig, savedASig;
int32 z;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( 0x41E < aExp ) {
if ( ( aExp == 0x7FF ) && aSig ) aSign = 0;
goto invalid;
}
else if ( aExp < 0x3FF ) {
if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
aSig |= LIT64( 0x0010000000000000 );
shiftCount = 0x433 - aExp;
savedASig = aSig;
aSig >>= shiftCount;
z = aSig;
if ( aSign ) z = - z;
if ( ( z < 0 ) ^ aSign ) {
invalid:
float_raise( float_flag_invalid );
return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
}
if ( ( aSig<<shiftCount ) != savedASig ) {
float_exception_flags |= float_flag_inexact;
}
return z;
}
#ifndef SOFTFLOAT_FOR_GCC /* Not needed */
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the 64-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int64 float64_to_int64( float64 a )
{
flag aSign;
int16 aExp, shiftCount;
bits64 aSig, aSigExtra;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
shiftCount = 0x433 - aExp;
if ( shiftCount <= 0 ) {
if ( 0x43E < aExp ) {
float_raise( float_flag_invalid );
if ( ! aSign
|| ( ( aExp == 0x7FF )
&& ( aSig != LIT64( 0x0010000000000000 ) ) )
) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
return (sbits64) LIT64( 0x8000000000000000 );
}
aSigExtra = 0;
aSig <<= - shiftCount;
}
else {
shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra );
}
return roundAndPackInt64( aSign, aSig, aSigExtra );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the 64-bit two's complement integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero.
If `a' is a NaN, the largest positive integer is returned. Otherwise, if
the conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int64 float64_to_int64_round_to_zero( float64 a )
{
flag aSign;
int16 aExp, shiftCount;
bits64 aSig;
int64 z;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp ) aSig |= LIT64( 0x0010000000000000 );
shiftCount = aExp - 0x433;
if ( 0 <= shiftCount ) {
if ( 0x43E <= aExp ) {
if ( a != LIT64( 0xC3E0000000000000 ) ) {
float_raise( float_flag_invalid );
if ( ! aSign
|| ( ( aExp == 0x7FF )
&& ( aSig != LIT64( 0x0010000000000000 ) ) )
) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
}
return (sbits64) LIT64( 0x8000000000000000 );
}
z = aSig<<shiftCount;
}
else {
if ( aExp < 0x3FE ) {
if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
z = aSig>>( - shiftCount );
if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) {
float_exception_flags |= float_flag_inexact;
}
}
if ( aSign ) z = - z;
return z;
}
#endif /* !SOFTFLOAT_FOR_GCC */
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the single-precision floating-point format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float64_to_float32( float64 a )
{
flag aSign;
int16 aExp;
bits64 aSig;
bits32 zSig;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a ) );
return packFloat32( aSign, 0xFF, 0 );
}
shift64RightJamming( aSig, 22, &aSig );
zSig = aSig;
if ( aExp || zSig ) {
zSig |= 0x40000000;
aExp -= 0x381;
}
return roundAndPackFloat32( aSign, aExp, zSig );
}
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the extended double-precision floating-point format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 float64_to_floatx80( float64 a )
{
flag aSign;
int16 aExp;
bits64 aSig;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a ) );
return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( aSign, 0, 0 );
normalizeFloat64Subnormal( aSig, &aExp, &aSig );
}
return
packFloatx80(
aSign, aExp + 0x3C00, ( aSig | LIT64( 0x0010000000000000 ) )<<11 );
}
#endif
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the quadruple-precision floating-point format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float64_to_float128( float64 a )
{
flag aSign;
int16 aExp;
bits64 aSig, zSig0, zSig1;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a ) );
return packFloat128( aSign, 0x7FFF, 0, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat128( aSign, 0, 0, 0 );
normalizeFloat64Subnormal( aSig, &aExp, &aSig );
--aExp;
}
shift128Right( aSig, 0, 4, &zSig0, &zSig1 );
return packFloat128( aSign, aExp + 0x3C00, zSig0, zSig1 );
}
#endif
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Rounds the double-precision floating-point value `a' to an integer, and
returns the result as a double-precision floating-point value. The
operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_round_to_int( float64 a )
{
flag aSign;
int16 aExp;
bits64 lastBitMask, roundBitsMask;
int8 roundingMode;
float64 z;
aExp = extractFloat64Exp( a );
if ( 0x433 <= aExp ) {
if ( ( aExp == 0x7FF ) && extractFloat64Frac( a ) ) {
return propagateFloat64NaN( a, a );
}
return a;
}
if ( aExp < 0x3FF ) {
if ( (bits64) ( a<<1 ) == 0 ) return a;
float_exception_flags |= float_flag_inexact;
aSign = extractFloat64Sign( a );
switch ( float_rounding_mode ) {
case float_round_nearest_even:
if ( ( aExp == 0x3FE ) && extractFloat64Frac( a ) ) {
return packFloat64( aSign, 0x3FF, 0 );
}
break;
case float_round_to_zero:
break;
case float_round_down:
return aSign ? LIT64( 0xBFF0000000000000 ) : 0;
case float_round_up:
return
aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 );
}
return packFloat64( aSign, 0, 0 );
}
lastBitMask = 1;
lastBitMask <<= 0x433 - aExp;
roundBitsMask = lastBitMask - 1;
z = a;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
z += lastBitMask>>1;
if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask;
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) {
z += roundBitsMask;
}
}
z &= ~ roundBitsMask;
if ( z != a ) float_exception_flags |= float_flag_inexact;
return z;
}
#endif
/*
-------------------------------------------------------------------------------
Returns the result of adding the absolute values of the double-precision
floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
before being returned. `zSign' is ignored if the result is a NaN.
The addition is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float64 addFloat64Sigs( float64 a, float64 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits64 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
bSig = extractFloat64Frac( b );
bExp = extractFloat64Exp( b );
expDiff = aExp - bExp;
aSig <<= 9;
bSig <<= 9;
if ( 0 < expDiff ) {
if ( aExp == 0x7FF ) {
if ( aSig ) return propagateFloat64NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= LIT64( 0x2000000000000000 );
}
shift64RightJamming( bSig, expDiff, &bSig );
zExp = aExp;
}
else if ( expDiff < 0 ) {
if ( bExp == 0x7FF ) {
if ( bSig ) return propagateFloat64NaN( a, b );
return packFloat64( zSign, 0x7FF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= LIT64( 0x2000000000000000 );
}
shift64RightJamming( aSig, - expDiff, &aSig );
zExp = bExp;
}
else {
if ( aExp == 0x7FF ) {
if ( aSig | bSig ) return propagateFloat64NaN( a, b );
return a;
}
if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 );
zSig = LIT64( 0x4000000000000000 ) + aSig + bSig;
zExp = aExp;
goto roundAndPack;
}
aSig |= LIT64( 0x2000000000000000 );
zSig = ( aSig + bSig )<<1;
--zExp;
if ( (sbits64) zSig < 0 ) {
zSig = aSig + bSig;
++zExp;
}
roundAndPack:
return roundAndPackFloat64( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the absolute values of the double-
precision floating-point values `a' and `b'. If `zSign' is 1, the
difference is negated before being returned. `zSign' is ignored if the
result is a NaN. The subtraction is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float64 subFloat64Sigs( float64 a, float64 b, flag zSign )
{
int16 aExp, bExp, zExp;
bits64 aSig, bSig, zSig;
int16 expDiff;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
bSig = extractFloat64Frac( b );
bExp = extractFloat64Exp( b );
expDiff = aExp - bExp;
aSig <<= 10;
bSig <<= 10;
if ( 0 < expDiff ) goto aExpBigger;
if ( expDiff < 0 ) goto bExpBigger;
if ( aExp == 0x7FF ) {
if ( aSig | bSig ) return propagateFloat64NaN( a, b );
float_raise( float_flag_invalid );
return float64_default_nan;
}
if ( aExp == 0 ) {
aExp = 1;
bExp = 1;
}
if ( bSig < aSig ) goto aBigger;
if ( aSig < bSig ) goto bBigger;
return packFloat64( float_rounding_mode == float_round_down, 0, 0 );
bExpBigger:
if ( bExp == 0x7FF ) {
if ( bSig ) return propagateFloat64NaN( a, b );
return packFloat64( zSign ^ 1, 0x7FF, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig |= LIT64( 0x4000000000000000 );
}
shift64RightJamming( aSig, - expDiff, &aSig );
bSig |= LIT64( 0x4000000000000000 );
bBigger:
zSig = bSig - aSig;
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0x7FF ) {
if ( aSig ) return propagateFloat64NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig |= LIT64( 0x4000000000000000 );
}
shift64RightJamming( bSig, expDiff, &bSig );
aSig |= LIT64( 0x4000000000000000 );
aBigger:
zSig = aSig - bSig;
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat64( zSign, zExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the double-precision floating-point values `a'
and `b'. The operation is performed according to the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_add( float64 a, float64 b )
{
flag aSign, bSign;
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign == bSign ) {
return addFloat64Sigs( a, b, aSign );
}
else {
return subFloat64Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the double-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_sub( float64 a, float64 b )
{
flag aSign, bSign;
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign == bSign ) {
return subFloat64Sigs( a, b, aSign );
}
else {
return addFloat64Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of multiplying the double-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_mul( float64 a, float64 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits64 aSig, bSig, zSig0, zSig1;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
bSig = extractFloat64Frac( b );
bExp = extractFloat64Exp( b );
bSign = extractFloat64Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FF ) {
if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
return propagateFloat64NaN( a, b );
}
if ( ( bExp | bSig ) == 0 ) {
float_raise( float_flag_invalid );
return float64_default_nan;
}
return packFloat64( zSign, 0x7FF, 0 );
}
if ( bExp == 0x7FF ) {
if ( bSig ) return propagateFloat64NaN( a, b );
if ( ( aExp | aSig ) == 0 ) {
float_raise( float_flag_invalid );
return float64_default_nan;
}
return packFloat64( zSign, 0x7FF, 0 );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
normalizeFloat64Subnormal( aSig, &aExp, &aSig );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) return packFloat64( zSign, 0, 0 );
normalizeFloat64Subnormal( bSig, &bExp, &bSig );
}
zExp = aExp + bExp - 0x3FF;
aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
mul64To128( aSig, bSig, &zSig0, &zSig1 );
zSig0 |= ( zSig1 != 0 );
if ( 0 <= (sbits64) ( zSig0<<1 ) ) {
zSig0 <<= 1;
--zExp;
}
return roundAndPackFloat64( zSign, zExp, zSig0 );
}
/*
-------------------------------------------------------------------------------
Returns the result of dividing the double-precision floating-point value `a'
by the corresponding value `b'. The operation is performed according to
the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_div( float64 a, float64 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, zExp;
bits64 aSig, bSig, zSig;
bits64 rem0, rem1;
bits64 term0, term1;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
bSig = extractFloat64Frac( b );
bExp = extractFloat64Exp( b );
bSign = extractFloat64Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FF ) {
if ( aSig ) return propagateFloat64NaN( a, b );
if ( bExp == 0x7FF ) {
if ( bSig ) return propagateFloat64NaN( a, b );
float_raise( float_flag_invalid );
return float64_default_nan;
}
return packFloat64( zSign, 0x7FF, 0 );
}
if ( bExp == 0x7FF ) {
if ( bSig ) return propagateFloat64NaN( a, b );
return packFloat64( zSign, 0, 0 );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
if ( ( aExp | aSig ) == 0 ) {
float_raise( float_flag_invalid );
return float64_default_nan;
}
float_raise( float_flag_divbyzero );
return packFloat64( zSign, 0x7FF, 0 );
}
normalizeFloat64Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloat64( zSign, 0, 0 );
normalizeFloat64Subnormal( aSig, &aExp, &aSig );
}
zExp = aExp - bExp + 0x3FD;
aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<10;
bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
if ( bSig <= ( aSig + aSig ) ) {
aSig >>= 1;
++zExp;
}
zSig = estimateDiv128To64( aSig, 0, bSig );
if ( ( zSig & 0x1FF ) <= 2 ) {
mul64To128( bSig, zSig, &term0, &term1 );
sub128( aSig, 0, term0, term1, &rem0, &rem1 );
while ( (sbits64) rem0 < 0 ) {
--zSig;
add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
}
zSig |= ( rem1 != 0 );
}
return roundAndPackFloat64( zSign, zExp, zSig );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns the remainder of the double-precision floating-point value `a'
with respect to the corresponding value `b'. The operation is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_rem( float64 a, float64 b )
{
flag aSign, bSign, zSign;
int16 aExp, bExp, expDiff;
bits64 aSig, bSig;
bits64 q, alternateASig;
sbits64 sigMean;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
bSig = extractFloat64Frac( b );
bExp = extractFloat64Exp( b );
bSign = extractFloat64Sign( b );
if ( aExp == 0x7FF ) {
if ( aSig || ( ( bExp == 0x7FF ) && bSig ) ) {
return propagateFloat64NaN( a, b );
}
float_raise( float_flag_invalid );
return float64_default_nan;
}
if ( bExp == 0x7FF ) {
if ( bSig ) return propagateFloat64NaN( a, b );
return a;
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
float_raise( float_flag_invalid );
return float64_default_nan;
}
normalizeFloat64Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return a;
normalizeFloat64Subnormal( aSig, &aExp, &aSig );
}
expDiff = aExp - bExp;
aSig = ( aSig | LIT64( 0x0010000000000000 ) )<<11;
bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11;
if ( expDiff < 0 ) {
if ( expDiff < -1 ) return a;
aSig >>= 1;
}
q = ( bSig <= aSig );
if ( q ) aSig -= bSig;
expDiff -= 64;
while ( 0 < expDiff ) {
q = estimateDiv128To64( aSig, 0, bSig );
q = ( 2 < q ) ? q - 2 : 0;
aSig = - ( ( bSig>>2 ) * q );
expDiff -= 62;
}
expDiff += 64;
if ( 0 < expDiff ) {
q = estimateDiv128To64( aSig, 0, bSig );
q = ( 2 < q ) ? q - 2 : 0;
q >>= 64 - expDiff;
bSig >>= 2;
aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q;
}
else {
aSig >>= 2;
bSig >>= 2;
}
do {
alternateASig = aSig;
++q;
aSig -= bSig;
} while ( 0 <= (sbits64) aSig );
sigMean = aSig + alternateASig;
if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) {
aSig = alternateASig;
}
zSign = ( (sbits64) aSig < 0 );
if ( zSign ) aSig = - aSig;
return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig );
}
/*
-------------------------------------------------------------------------------
Returns the square root of the double-precision floating-point value `a'.
The operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float64_sqrt( float64 a )
{
flag aSign;
int16 aExp, zExp;
bits64 aSig, zSig, doubleZSig;
bits64 rem0, rem1, term0, term1;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if ( aSig ) return propagateFloat64NaN( a, a );
if ( ! aSign ) return a;
float_raise( float_flag_invalid );
return float64_default_nan;
}
if ( aSign ) {
if ( ( aExp | aSig ) == 0 ) return a;
float_raise( float_flag_invalid );
return float64_default_nan;
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return 0;
normalizeFloat64Subnormal( aSig, &aExp, &aSig );
}
zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE;
aSig |= LIT64( 0x0010000000000000 );
zSig = estimateSqrt32( aExp, aSig>>21 );
aSig <<= 9 - ( aExp & 1 );
zSig = estimateDiv128To64( aSig, 0, zSig<<32 ) + ( zSig<<30 );
if ( ( zSig & 0x1FF ) <= 5 ) {
doubleZSig = zSig<<1;
mul64To128( zSig, zSig, &term0, &term1 );
sub128( aSig, 0, term0, term1, &rem0, &rem1 );
while ( (sbits64) rem0 < 0 ) {
--zSig;
doubleZSig -= 2;
add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 );
}
zSig |= ( ( rem0 | rem1 ) != 0 );
}
return roundAndPackFloat64( 0, zExp, zSig );
}
#endif
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is equal to the
corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_eq( float64 a, float64 b )
{
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
return ( a == b ) ||
( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than or
equal to the corresponding value `b', and 0 otherwise. The comparison is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_le( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign )
return aSign ||
( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) ==
0 );
return ( a == b ) ||
( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_lt( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign )
return aSign &&
( (bits64) ( ( FLOAT64_DEMANGLE(a) | FLOAT64_DEMANGLE(b) )<<1 ) !=
0 );
return ( a != b ) &&
( aSign ^ ( FLOAT64_DEMANGLE(a) < FLOAT64_DEMANGLE(b) ) );
}
#ifndef SOFTFLOAT_FOR_GCC
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is equal to the
corresponding value `b', and 0 otherwise. The invalid exception is raised
if either operand is a NaN. Otherwise, the comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_eq_signaling( float64 a, float64 b )
{
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
float_raise( float_flag_invalid );
return 0;
}
return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than or
equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
cause an exception. Otherwise, the comparison is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_le_quiet( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 );
return ( a == b ) || ( aSign ^ ( a < b ) );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the double-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
exception. Otherwise, the comparison is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float64_lt_quiet( float64 a, float64 b )
{
flag aSign, bSign;
if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) )
|| ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) )
) {
if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat64Sign( a );
bSign = extractFloat64Sign( b );
if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 );
return ( a != b ) && ( aSign ^ ( a < b ) );
}
#endif
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point value `a' to the 32-bit two's complement integer format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic---which means in particular that the conversion
is rounded according to the current rounding mode. If `a' is a NaN, the
largest positive integer is returned. Otherwise, if the conversion
overflows, the largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int32 floatx80_to_int32( floatx80 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
shiftCount = 0x4037 - aExp;
if ( shiftCount <= 0 ) shiftCount = 1;
shift64RightJamming( aSig, shiftCount, &aSig );
return roundAndPackInt32( aSign, aSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point value `a' to the 32-bit two's complement integer format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic, except that the conversion is always rounded
toward zero. If `a' is a NaN, the largest positive integer is returned.
Otherwise, if the conversion overflows, the largest integer with the same
sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int32 floatx80_to_int32_round_to_zero( floatx80 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig, savedASig;
int32 z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( 0x401E < aExp ) {
if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0;
goto invalid;
}
else if ( aExp < 0x3FFF ) {
if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
shiftCount = 0x403E - aExp;
savedASig = aSig;
aSig >>= shiftCount;
z = aSig;
if ( aSign ) z = - z;
if ( ( z < 0 ) ^ aSign ) {
invalid:
float_raise( float_flag_invalid );
return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
}
if ( ( aSig<<shiftCount ) != savedASig ) {
float_exception_flags |= float_flag_inexact;
}
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point value `a' to the 64-bit two's complement integer format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic---which means in particular that the conversion
is rounded according to the current rounding mode. If `a' is a NaN,
the largest positive integer is returned. Otherwise, if the conversion
overflows, the largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int64 floatx80_to_int64( floatx80 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig, aSigExtra;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
shiftCount = 0x403E - aExp;
if ( shiftCount <= 0 ) {
if ( shiftCount ) {
float_raise( float_flag_invalid );
if ( ! aSign
|| ( ( aExp == 0x7FFF )
&& ( aSig != LIT64( 0x8000000000000000 ) ) )
) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
return (sbits64) LIT64( 0x8000000000000000 );
}
aSigExtra = 0;
}
else {
shift64ExtraRightJamming( aSig, 0, shiftCount, &aSig, &aSigExtra );
}
return roundAndPackInt64( aSign, aSig, aSigExtra );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point value `a' to the 64-bit two's complement integer format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic, except that the conversion is always rounded
toward zero. If `a' is a NaN, the largest positive integer is returned.
Otherwise, if the conversion overflows, the largest integer with the same
sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int64 floatx80_to_int64_round_to_zero( floatx80 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig;
int64 z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
shiftCount = aExp - 0x403E;
if ( 0 <= shiftCount ) {
aSig &= LIT64( 0x7FFFFFFFFFFFFFFF );
if ( ( a.high != 0xC03E ) || aSig ) {
float_raise( float_flag_invalid );
if ( ! aSign || ( ( aExp == 0x7FFF ) && aSig ) ) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
}
return (sbits64) LIT64( 0x8000000000000000 );
}
else if ( aExp < 0x3FFF ) {
if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
z = aSig>>( - shiftCount );
if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) {
float_exception_flags |= float_flag_inexact;
}
if ( aSign ) z = - z;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point value `a' to the single-precision floating-point format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float32 floatx80_to_float32( floatx80 a )
{
flag aSign;
int32 aExp;
bits64 aSig;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig<<1 ) ) {
return commonNaNToFloat32( floatx80ToCommonNaN( a ) );
}
return packFloat32( aSign, 0xFF, 0 );
}
shift64RightJamming( aSig, 33, &aSig );
if ( aExp || aSig ) aExp -= 0x3F81;
return roundAndPackFloat32( aSign, aExp, aSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point value `a' to the double-precision floating-point format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float64 floatx80_to_float64( floatx80 a )
{
flag aSign;
int32 aExp;
bits64 aSig, zSig;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig<<1 ) ) {
return commonNaNToFloat64( floatx80ToCommonNaN( a ) );
}
return packFloat64( aSign, 0x7FF, 0 );
}
shift64RightJamming( aSig, 1, &zSig );
if ( aExp || aSig ) aExp -= 0x3C01;
return roundAndPackFloat64( aSign, aExp, zSig );
}
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Returns the result of converting the extended double-precision floating-
point value `a' to the quadruple-precision floating-point format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 floatx80_to_float128( floatx80 a )
{
flag aSign;
int16 aExp;
bits64 aSig, zSig0, zSig1;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
return commonNaNToFloat128( floatx80ToCommonNaN( a ) );
}
shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
return packFloat128( aSign, aExp, zSig0, zSig1 );
}
#endif
/*
-------------------------------------------------------------------------------
Rounds the extended double-precision floating-point value `a' to an integer,
and returns the result as an extended quadruple-precision floating-point
value. The operation is performed according to the IEC/IEEE Standard for
Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_round_to_int( floatx80 a )
{
flag aSign;
int32 aExp;
bits64 lastBitMask, roundBitsMask;
int8 roundingMode;
floatx80 z;
aExp = extractFloatx80Exp( a );
if ( 0x403E <= aExp ) {
if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) {
return propagateFloatx80NaN( a, a );
}
return a;
}
if ( aExp < 0x3FFF ) {
if ( ( aExp == 0 )
&& ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
return a;
}
float_exception_flags |= float_flag_inexact;
aSign = extractFloatx80Sign( a );
switch ( float_rounding_mode ) {
case float_round_nearest_even:
if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 )
) {
return
packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) );
}
break;
case float_round_to_zero:
break;
case float_round_down:
return
aSign ?
packFloatx80( 1, 0x3FFF, LIT64( 0x8000000000000000 ) )
: packFloatx80( 0, 0, 0 );
case float_round_up:
return
aSign ? packFloatx80( 1, 0, 0 )
: packFloatx80( 0, 0x3FFF, LIT64( 0x8000000000000000 ) );
}
return packFloatx80( aSign, 0, 0 );
}
lastBitMask = 1;
lastBitMask <<= 0x403E - aExp;
roundBitsMask = lastBitMask - 1;
z = a;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
z.low += lastBitMask>>1;
if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloatx80Sign( z ) ^ ( roundingMode == float_round_up ) ) {
z.low += roundBitsMask;
}
}
z.low &= ~ roundBitsMask;
if ( z.low == 0 ) {
++z.high;
z.low = LIT64( 0x8000000000000000 );
}
if ( z.low != a.low ) float_exception_flags |= float_flag_inexact;
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the absolute values of the extended double-
precision floating-point values `a' and `b'. If `zSign' is 1, the sum is
negated before being returned. `zSign' is ignored if the result is a NaN.
The addition is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
{
int32 aExp, bExp, zExp;
bits64 aSig, bSig, zSig0, zSig1;
int32 expDiff;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
bSig = extractFloatx80Frac( b );
bExp = extractFloatx80Exp( b );
expDiff = aExp - bExp;
if ( 0 < expDiff ) {
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
return a;
}
if ( bExp == 0 ) --expDiff;
shift64ExtraRightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
zExp = aExp;
}
else if ( expDiff < 0 ) {
if ( bExp == 0x7FFF ) {
if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( aExp == 0 ) ++expDiff;
shift64ExtraRightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
zExp = bExp;
}
else {
if ( aExp == 0x7FFF ) {
if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
return propagateFloatx80NaN( a, b );
}
return a;
}
zSig1 = 0;
zSig0 = aSig + bSig;
if ( aExp == 0 ) {
normalizeFloatx80Subnormal( zSig0, &zExp, &zSig0 );
goto roundAndPack;
}
zExp = aExp;
goto shiftRight1;
}
zSig0 = aSig + bSig;
if ( (sbits64) zSig0 < 0 ) goto roundAndPack;
shiftRight1:
shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 );
zSig0 |= LIT64( 0x8000000000000000 );
++zExp;
roundAndPack:
return
roundAndPackFloatx80(
floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the absolute values of the extended
double-precision floating-point values `a' and `b'. If `zSign' is 1, the
difference is negated before being returned. `zSign' is ignored if the
result is a NaN. The subtraction is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign )
{
int32 aExp, bExp, zExp;
bits64 aSig, bSig, zSig0, zSig1;
int32 expDiff;
floatx80 z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
bSig = extractFloatx80Frac( b );
bExp = extractFloatx80Exp( b );
expDiff = aExp - bExp;
if ( 0 < expDiff ) goto aExpBigger;
if ( expDiff < 0 ) goto bExpBigger;
if ( aExp == 0x7FFF ) {
if ( (bits64) ( ( aSig | bSig )<<1 ) ) {
return propagateFloatx80NaN( a, b );
}
float_raise( float_flag_invalid );
z.low = floatx80_default_nan_low;
z.high = floatx80_default_nan_high;
return z;
}
if ( aExp == 0 ) {
aExp = 1;
bExp = 1;
}
zSig1 = 0;
if ( bSig < aSig ) goto aBigger;
if ( aSig < bSig ) goto bBigger;
return packFloatx80( float_rounding_mode == float_round_down, 0, 0 );
bExpBigger:
if ( bExp == 0x7FFF ) {
if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( aExp == 0 ) ++expDiff;
shift128RightJamming( aSig, 0, - expDiff, &aSig, &zSig1 );
bBigger:
sub128( bSig, 0, aSig, zSig1, &zSig0, &zSig1 );
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
return a;
}
if ( bExp == 0 ) --expDiff;
shift128RightJamming( bSig, 0, expDiff, &bSig, &zSig1 );
aBigger:
sub128( aSig, 0, bSig, zSig1, &zSig0, &zSig1 );
zExp = aExp;
normalizeRoundAndPack:
return
normalizeRoundAndPackFloatx80(
floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the extended double-precision floating-point
values `a' and `b'. The operation is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_add( floatx80 a, floatx80 b )
{
flag aSign, bSign;
aSign = extractFloatx80Sign( a );
bSign = extractFloatx80Sign( b );
if ( aSign == bSign ) {
return addFloatx80Sigs( a, b, aSign );
}
else {
return subFloatx80Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the extended double-precision floating-
point values `a' and `b'. The operation is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_sub( floatx80 a, floatx80 b )
{
flag aSign, bSign;
aSign = extractFloatx80Sign( a );
bSign = extractFloatx80Sign( b );
if ( aSign == bSign ) {
return subFloatx80Sigs( a, b, aSign );
}
else {
return addFloatx80Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of multiplying the extended double-precision floating-
point values `a' and `b'. The operation is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_mul( floatx80 a, floatx80 b )
{
flag aSign, bSign, zSign;
int32 aExp, bExp, zExp;
bits64 aSig, bSig, zSig0, zSig1;
floatx80 z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
bSig = extractFloatx80Frac( b );
bExp = extractFloatx80Exp( b );
bSign = extractFloatx80Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig<<1 )
|| ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
return propagateFloatx80NaN( a, b );
}
if ( ( bExp | bSig ) == 0 ) goto invalid;
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( bExp == 0x7FFF ) {
if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
if ( ( aExp | aSig ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
z.low = floatx80_default_nan_low;
z.high = floatx80_default_nan_high;
return z;
}
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) return packFloatx80( zSign, 0, 0 );
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
}
zExp = aExp + bExp - 0x3FFE;
mul64To128( aSig, bSig, &zSig0, &zSig1 );
if ( 0 < (sbits64) zSig0 ) {
shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 );
--zExp;
}
return
roundAndPackFloatx80(
floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the result of dividing the extended double-precision floating-point
value `a' by the corresponding value `b'. The operation is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_div( floatx80 a, floatx80 b )
{
flag aSign, bSign, zSign;
int32 aExp, bExp, zExp;
bits64 aSig, bSig, zSig0, zSig1;
bits64 rem0, rem1, rem2, term0, term1, term2;
floatx80 z;
aSig = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
bSig = extractFloatx80Frac( b );
bExp = extractFloatx80Exp( b );
bSign = extractFloatx80Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b );
if ( bExp == 0x7FFF ) {
if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
goto invalid;
}
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( bExp == 0x7FFF ) {
if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
return packFloatx80( zSign, 0, 0 );
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
if ( ( aExp | aSig ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
z.low = floatx80_default_nan_low;
z.high = floatx80_default_nan_high;
return z;
}
float_raise( float_flag_divbyzero );
return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( aSig == 0 ) return packFloatx80( zSign, 0, 0 );
normalizeFloatx80Subnormal( aSig, &aExp, &aSig );
}
zExp = aExp - bExp + 0x3FFE;
rem1 = 0;
if ( bSig <= aSig ) {
shift128Right( aSig, 0, 1, &aSig, &rem1 );
++zExp;
}
zSig0 = estimateDiv128To64( aSig, rem1, bSig );
mul64To128( bSig, zSig0, &term0, &term1 );
sub128( aSig, rem1, term0, term1, &rem0, &rem1 );
while ( (sbits64) rem0 < 0 ) {
--zSig0;
add128( rem0, rem1, 0, bSig, &rem0, &rem1 );
}
zSig1 = estimateDiv128To64( rem1, 0, bSig );
if ( (bits64) ( zSig1<<1 ) <= 8 ) {
mul64To128( bSig, zSig1, &term1, &term2 );
sub128( rem1, 0, term1, term2, &rem1, &rem2 );
while ( (sbits64) rem1 < 0 ) {
--zSig1;
add128( rem1, rem2, 0, bSig, &rem1, &rem2 );
}
zSig1 |= ( ( rem1 | rem2 ) != 0 );
}
return
roundAndPackFloatx80(
floatx80_rounding_precision, zSign, zExp, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the remainder of the extended double-precision floating-point value
`a' with respect to the corresponding value `b'. The operation is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_rem( floatx80 a, floatx80 b )
{
flag aSign, bSign, zSign;
int32 aExp, bExp, expDiff;
bits64 aSig0, aSig1, bSig;
bits64 q, term0, term1, alternateASig0, alternateASig1;
floatx80 z;
aSig0 = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
bSig = extractFloatx80Frac( b );
bExp = extractFloatx80Exp( b );
bSign = extractFloatx80Sign( b );
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig0<<1 )
|| ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) {
return propagateFloatx80NaN( a, b );
}
goto invalid;
}
if ( bExp == 0x7FFF ) {
if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b );
return a;
}
if ( bExp == 0 ) {
if ( bSig == 0 ) {
invalid:
float_raise( float_flag_invalid );
z.low = floatx80_default_nan_low;
z.high = floatx80_default_nan_high;
return z;
}
normalizeFloatx80Subnormal( bSig, &bExp, &bSig );
}
if ( aExp == 0 ) {
if ( (bits64) ( aSig0<<1 ) == 0 ) return a;
normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
}
bSig |= LIT64( 0x8000000000000000 );
zSign = aSign;
expDiff = aExp - bExp;
aSig1 = 0;
if ( expDiff < 0 ) {
if ( expDiff < -1 ) return a;
shift128Right( aSig0, 0, 1, &aSig0, &aSig1 );
expDiff = 0;
}
q = ( bSig <= aSig0 );
if ( q ) aSig0 -= bSig;
expDiff -= 64;
while ( 0 < expDiff ) {
q = estimateDiv128To64( aSig0, aSig1, bSig );
q = ( 2 < q ) ? q - 2 : 0;
mul64To128( bSig, q, &term0, &term1 );
sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
shortShift128Left( aSig0, aSig1, 62, &aSig0, &aSig1 );
expDiff -= 62;
}
expDiff += 64;
if ( 0 < expDiff ) {
q = estimateDiv128To64( aSig0, aSig1, bSig );
q = ( 2 < q ) ? q - 2 : 0;
q >>= 64 - expDiff;
mul64To128( bSig, q<<( 64 - expDiff ), &term0, &term1 );
sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
shortShift128Left( 0, bSig, 64 - expDiff, &term0, &term1 );
while ( le128( term0, term1, aSig0, aSig1 ) ) {
++q;
sub128( aSig0, aSig1, term0, term1, &aSig0, &aSig1 );
}
}
else {
term1 = 0;
term0 = bSig;
}
sub128( term0, term1, aSig0, aSig1, &alternateASig0, &alternateASig1 );
if ( lt128( alternateASig0, alternateASig1, aSig0, aSig1 )
|| ( eq128( alternateASig0, alternateASig1, aSig0, aSig1 )
&& ( q & 1 ) )
) {
aSig0 = alternateASig0;
aSig1 = alternateASig1;
zSign = ! zSign;
}
return
normalizeRoundAndPackFloatx80(
80, zSign, bExp + expDiff, aSig0, aSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the square root of the extended double-precision floating-point
value `a'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 floatx80_sqrt( floatx80 a )
{
flag aSign;
int32 aExp, zExp;
bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0;
bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
floatx80 z;
aSig0 = extractFloatx80Frac( a );
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FFF ) {
if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a );
if ( ! aSign ) return a;
goto invalid;
}
if ( aSign ) {
if ( ( aExp | aSig0 ) == 0 ) return a;
invalid:
float_raise( float_flag_invalid );
z.low = floatx80_default_nan_low;
z.high = floatx80_default_nan_high;
return z;
}
if ( aExp == 0 ) {
if ( aSig0 == 0 ) return packFloatx80( 0, 0, 0 );
normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 );
}
zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFF;
zSig0 = estimateSqrt32( aExp, aSig0>>32 );
shift128Right( aSig0, 0, 2 + ( aExp & 1 ), &aSig0, &aSig1 );
zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 );
doubleZSig0 = zSig0<<1;
mul64To128( zSig0, zSig0, &term0, &term1 );
sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
while ( (sbits64) rem0 < 0 ) {
--zSig0;
doubleZSig0 -= 2;
add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
}
zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 );
if ( ( zSig1 & LIT64( 0x3FFFFFFFFFFFFFFF ) ) <= 5 ) {
if ( zSig1 == 0 ) zSig1 = 1;
mul64To128( doubleZSig0, zSig1, &term1, &term2 );
sub128( rem1, 0, term1, term2, &rem1, &rem2 );
mul64To128( zSig1, zSig1, &term2, &term3 );
sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
while ( (sbits64) rem1 < 0 ) {
--zSig1;
shortShift128Left( 0, zSig1, 1, &term2, &term3 );
term3 |= 1;
term2 |= doubleZSig0;
add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
}
zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
}
shortShift128Left( 0, zSig1, 1, &zSig0, &zSig1 );
zSig0 |= doubleZSig0;
return
roundAndPackFloatx80(
floatx80_rounding_precision, 0, zExp, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is
equal to the corresponding value `b', and 0 otherwise. The comparison is
performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
flag floatx80_eq( floatx80 a, floatx80 b )
{
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( b )<<1 ) )
) {
if ( floatx80_is_signaling_nan( a )
|| floatx80_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
return
( a.low == b.low )
&& ( ( a.high == b.high )
|| ( ( a.low == 0 )
&& ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
);
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is
less than or equal to the corresponding value `b', and 0 otherwise. The
comparison is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag floatx80_le( floatx80 a, floatx80 b )
{
flag aSign, bSign;
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( b )<<1 ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloatx80Sign( a );
bSign = extractFloatx80Sign( b );
if ( aSign != bSign ) {
return
aSign
|| ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
== 0 );
}
return
aSign ? le128( b.high, b.low, a.high, a.low )
: le128( a.high, a.low, b.high, b.low );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is
less than the corresponding value `b', and 0 otherwise. The comparison
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
flag floatx80_lt( floatx80 a, floatx80 b )
{
flag aSign, bSign;
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( b )<<1 ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloatx80Sign( a );
bSign = extractFloatx80Sign( b );
if ( aSign != bSign ) {
return
aSign
&& ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
!= 0 );
}
return
aSign ? lt128( b.high, b.low, a.high, a.low )
: lt128( a.high, a.low, b.high, b.low );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is equal
to the corresponding value `b', and 0 otherwise. The invalid exception is
raised if either operand is a NaN. Otherwise, the comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag floatx80_eq_signaling( floatx80 a, floatx80 b )
{
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( b )<<1 ) )
) {
float_raise( float_flag_invalid );
return 0;
}
return
( a.low == b.low )
&& ( ( a.high == b.high )
|| ( ( a.low == 0 )
&& ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) )
);
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is less
than or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs
do not cause an exception. Otherwise, the comparison is performed according
to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag floatx80_le_quiet( floatx80 a, floatx80 b )
{
flag aSign, bSign;
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( b )<<1 ) )
) {
if ( floatx80_is_signaling_nan( a )
|| floatx80_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloatx80Sign( a );
bSign = extractFloatx80Sign( b );
if ( aSign != bSign ) {
return
aSign
|| ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
== 0 );
}
return
aSign ? le128( b.high, b.low, a.high, a.low )
: le128( a.high, a.low, b.high, b.low );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the extended double-precision floating-point value `a' is less
than the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause
an exception. Otherwise, the comparison is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag floatx80_lt_quiet( floatx80 a, floatx80 b )
{
flag aSign, bSign;
if ( ( ( extractFloatx80Exp( a ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( a )<<1 ) )
|| ( ( extractFloatx80Exp( b ) == 0x7FFF )
&& (bits64) ( extractFloatx80Frac( b )<<1 ) )
) {
if ( floatx80_is_signaling_nan( a )
|| floatx80_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloatx80Sign( a );
bSign = extractFloatx80Sign( b );
if ( aSign != bSign ) {
return
aSign
&& ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
!= 0 );
}
return
aSign ? lt128( b.high, b.low, a.high, a.low )
: lt128( a.high, a.low, b.high, b.low );
}
#endif
#ifdef FLOAT128
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point
value `a' to the 32-bit two's complement integer format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int32 float128_to_int32( float128 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig0, aSig1;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) aSign = 0;
if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
aSig0 |= ( aSig1 != 0 );
shiftCount = 0x4028 - aExp;
if ( 0 < shiftCount ) shift64RightJamming( aSig0, shiftCount, &aSig0 );
return roundAndPackInt32( aSign, aSig0 );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point
value `a' to the 32-bit two's complement integer format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero. If
`a' is a NaN, the largest positive integer is returned. Otherwise, if the
conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int32 float128_to_int32_round_to_zero( float128 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig0, aSig1, savedASig;
int32 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
aSig0 |= ( aSig1 != 0 );
if ( 0x401E < aExp ) {
if ( ( aExp == 0x7FFF ) && aSig0 ) aSign = 0;
goto invalid;
}
else if ( aExp < 0x3FFF ) {
if ( aExp || aSig0 ) float_exception_flags |= float_flag_inexact;
return 0;
}
aSig0 |= LIT64( 0x0001000000000000 );
shiftCount = 0x402F - aExp;
savedASig = aSig0;
aSig0 >>= shiftCount;
z = aSig0;
if ( aSign ) z = - z;
if ( ( z < 0 ) ^ aSign ) {
invalid:
float_raise( float_flag_invalid );
return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF;
}
if ( ( aSig0<<shiftCount ) != savedASig ) {
float_exception_flags |= float_flag_inexact;
}
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point
value `a' to the 64-bit two's complement integer format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic---which means in particular that the conversion is rounded
according to the current rounding mode. If `a' is a NaN, the largest
positive integer is returned. Otherwise, if the conversion overflows, the
largest integer with the same sign as `a' is returned.
-------------------------------------------------------------------------------
*/
int64 float128_to_int64( float128 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig0, aSig1;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
shiftCount = 0x402F - aExp;
if ( shiftCount <= 0 ) {
if ( 0x403E < aExp ) {
float_raise( float_flag_invalid );
if ( ! aSign
|| ( ( aExp == 0x7FFF )
&& ( aSig1 || ( aSig0 != LIT64( 0x0001000000000000 ) ) )
)
) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
return (sbits64) LIT64( 0x8000000000000000 );
}
shortShift128Left( aSig0, aSig1, - shiftCount, &aSig0, &aSig1 );
}
else {
shift64ExtraRightJamming( aSig0, aSig1, shiftCount, &aSig0, &aSig1 );
}
return roundAndPackInt64( aSign, aSig0, aSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point
value `a' to the 64-bit two's complement integer format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic, except that the conversion is always rounded toward zero.
If `a' is a NaN, the largest positive integer is returned. Otherwise, if
the conversion overflows, the largest integer with the same sign as `a' is
returned.
-------------------------------------------------------------------------------
*/
int64 float128_to_int64_round_to_zero( float128 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig0, aSig1;
int64 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
shiftCount = aExp - 0x402F;
if ( 0 < shiftCount ) {
if ( 0x403E <= aExp ) {
aSig0 &= LIT64( 0x0000FFFFFFFFFFFF );
if ( ( a.high == LIT64( 0xC03E000000000000 ) )
&& ( aSig1 < LIT64( 0x0002000000000000 ) ) ) {
if ( aSig1 ) float_exception_flags |= float_flag_inexact;
}
else {
float_raise( float_flag_invalid );
if ( ! aSign || ( ( aExp == 0x7FFF ) && ( aSig0 | aSig1 ) ) ) {
return LIT64( 0x7FFFFFFFFFFFFFFF );
}
}
return (sbits64) LIT64( 0x8000000000000000 );
}
z = ( aSig0<<shiftCount ) | ( aSig1>>( ( - shiftCount ) & 63 ) );
if ( (bits64) ( aSig1<<shiftCount ) ) {
float_exception_flags |= float_flag_inexact;
}
}
else {
if ( aExp < 0x3FFF ) {
if ( aExp | aSig0 | aSig1 ) {
float_exception_flags |= float_flag_inexact;
}
return 0;
}
z = aSig0>>( - shiftCount );
if ( aSig1
|| ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) {
float_exception_flags |= float_flag_inexact;
}
}
if ( aSign ) z = - z;
return z;
}
#if (defined(SOFTFLOATSPARC64_FOR_GCC) || defined(SOFTFLOAT_FOR_GCC)) \
&& defined(SOFTFLOAT_NEED_FIXUNS)
/*
* just like above - but do not care for overflow of signed results
*/
uint64 float128_to_uint64_round_to_zero( float128 a )
{
flag aSign;
int32 aExp, shiftCount;
bits64 aSig0, aSig1;
uint64 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp ) aSig0 |= LIT64( 0x0001000000000000 );
shiftCount = aExp - 0x402F;
if ( 0 < shiftCount ) {
if ( 0x403F <= aExp ) {
aSig0 &= LIT64( 0x0000FFFFFFFFFFFF );
if ( ( a.high == LIT64( 0xC03E000000000000 ) )
&& ( aSig1 < LIT64( 0x0002000000000000 ) ) ) {
if ( aSig1 ) float_exception_flags |= float_flag_inexact;
}
else {
float_raise( float_flag_invalid );
}
return LIT64( 0xFFFFFFFFFFFFFFFF );
}
z = ( aSig0<<shiftCount ) | ( aSig1>>( ( - shiftCount ) & 63 ) );
if ( (bits64) ( aSig1<<shiftCount ) ) {
float_exception_flags |= float_flag_inexact;
}
}
else {
if ( aExp < 0x3FFF ) {
if ( aExp | aSig0 | aSig1 ) {
float_exception_flags |= float_flag_inexact;
}
return 0;
}
z = aSig0>>( - shiftCount );
if (aSig1 || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) {
float_exception_flags |= float_flag_inexact;
}
}
if ( aSign ) z = - z;
return z;
}
#endif /* (SOFTFLOATSPARC64_FOR_GCC || SOFTFLOAT_FOR_GCC) && SOFTFLOAT_NEED_FIXUNS */
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point
value `a' to the single-precision floating-point format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float32 float128_to_float32( float128 a )
{
flag aSign;
int32 aExp;
bits64 aSig0, aSig1;
bits32 zSig;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) {
return commonNaNToFloat32( float128ToCommonNaN( a ) );
}
return packFloat32( aSign, 0xFF, 0 );
}
aSig0 |= ( aSig1 != 0 );
shift64RightJamming( aSig0, 18, &aSig0 );
zSig = aSig0;
if ( aExp || zSig ) {
zSig |= 0x40000000;
aExp -= 0x3F81;
}
return roundAndPackFloat32( aSign, aExp, zSig );
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point
value `a' to the double-precision floating-point format. The conversion
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
float64 float128_to_float64( float128 a )
{
flag aSign;
int32 aExp;
bits64 aSig0, aSig1;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) {
return commonNaNToFloat64( float128ToCommonNaN( a ) );
}
return packFloat64( aSign, 0x7FF, 0 );
}
shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
aSig0 |= ( aSig1 != 0 );
if ( aExp || aSig0 ) {
aSig0 |= LIT64( 0x4000000000000000 );
aExp -= 0x3C01;
}
return roundAndPackFloat64( aSign, aExp, aSig0 );
}
#ifdef FLOATX80
/*
-------------------------------------------------------------------------------
Returns the result of converting the quadruple-precision floating-point
value `a' to the extended double-precision floating-point format. The
conversion is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
floatx80 float128_to_floatx80( float128 a )
{
flag aSign;
int32 aExp;
bits64 aSig0, aSig1;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) {
return commonNaNToFloatx80( float128ToCommonNaN( a ) );
}
return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloatx80( aSign, 0, 0 );
normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
else {
aSig0 |= LIT64( 0x0001000000000000 );
}
shortShift128Left( aSig0, aSig1, 15, &aSig0, &aSig1 );
return roundAndPackFloatx80( 80, aSign, aExp, aSig0, aSig1 );
}
#endif
/*
-------------------------------------------------------------------------------
Rounds the quadruple-precision floating-point value `a' to an integer, and
returns the result as a quadruple-precision floating-point value. The
operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float128_round_to_int( float128 a )
{
flag aSign;
int32 aExp;
bits64 lastBitMask, roundBitsMask;
int8 roundingMode;
float128 z;
aExp = extractFloat128Exp( a );
if ( 0x402F <= aExp ) {
if ( 0x406F <= aExp ) {
if ( ( aExp == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) )
) {
return propagateFloat128NaN( a, a );
}
return a;
}
lastBitMask = 1;
lastBitMask = ( lastBitMask<<( 0x406E - aExp ) )<<1;
roundBitsMask = lastBitMask - 1;
z = a;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
if ( lastBitMask ) {
add128( z.high, z.low, 0, lastBitMask>>1, &z.high, &z.low );
if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask;
}
else {
if ( (sbits64) z.low < 0 ) {
++z.high;
if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1;
}
}
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloat128Sign( z )
^ ( roundingMode == float_round_up ) ) {
add128( z.high, z.low, 0, roundBitsMask, &z.high, &z.low );
}
}
z.low &= ~ roundBitsMask;
}
else {
if ( aExp < 0x3FFF ) {
if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a;
float_exception_flags |= float_flag_inexact;
aSign = extractFloat128Sign( a );
switch ( float_rounding_mode ) {
case float_round_nearest_even:
if ( ( aExp == 0x3FFE )
&& ( extractFloat128Frac0( a )
| extractFloat128Frac1( a ) )
) {
return packFloat128( aSign, 0x3FFF, 0, 0 );
}
break;
case float_round_to_zero:
break;
case float_round_down:
return
aSign ? packFloat128( 1, 0x3FFF, 0, 0 )
: packFloat128( 0, 0, 0, 0 );
case float_round_up:
return
aSign ? packFloat128( 1, 0, 0, 0 )
: packFloat128( 0, 0x3FFF, 0, 0 );
}
return packFloat128( aSign, 0, 0, 0 );
}
lastBitMask = 1;
lastBitMask <<= 0x402F - aExp;
roundBitsMask = lastBitMask - 1;
z.low = 0;
z.high = a.high;
roundingMode = float_rounding_mode;
if ( roundingMode == float_round_nearest_even ) {
z.high += lastBitMask>>1;
if ( ( ( z.high & roundBitsMask ) | a.low ) == 0 ) {
z.high &= ~ lastBitMask;
}
}
else if ( roundingMode != float_round_to_zero ) {
if ( extractFloat128Sign( z )
^ ( roundingMode == float_round_up ) ) {
z.high |= ( a.low != 0 );
z.high += roundBitsMask;
}
}
z.high &= ~ roundBitsMask;
}
if ( ( z.low != a.low ) || ( z.high != a.high ) ) {
float_exception_flags |= float_flag_inexact;
}
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the absolute values of the quadruple-precision
floating-point values `a' and `b'. If `zSign' is 1, the sum is negated
before being returned. `zSign' is ignored if the result is a NaN.
The addition is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float128 addFloat128Sigs( float128 a, float128 b, flag zSign )
{
int32 aExp, bExp, zExp;
bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
int32 expDiff;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
bSig1 = extractFloat128Frac1( b );
bSig0 = extractFloat128Frac0( b );
bExp = extractFloat128Exp( b );
expDiff = aExp - bExp;
if ( 0 < expDiff ) {
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig0 |= LIT64( 0x0001000000000000 );
}
shift128ExtraRightJamming(
bSig0, bSig1, 0, expDiff, &bSig0, &bSig1, &zSig2 );
zExp = aExp;
}
else if ( expDiff < 0 ) {
if ( bExp == 0x7FFF ) {
if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig0 |= LIT64( 0x0001000000000000 );
}
shift128ExtraRightJamming(
aSig0, aSig1, 0, - expDiff, &aSig0, &aSig1, &zSig2 );
zExp = bExp;
}
else {
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
return propagateFloat128NaN( a, b );
}
return a;
}
add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 );
zSig2 = 0;
zSig0 |= LIT64( 0x0002000000000000 );
zExp = aExp;
goto shiftRight1;
}
aSig0 |= LIT64( 0x0001000000000000 );
add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
--zExp;
if ( zSig0 < LIT64( 0x0002000000000000 ) ) goto roundAndPack;
++zExp;
shiftRight1:
shift128ExtraRightJamming(
zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
roundAndPack:
return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the absolute values of the quadruple-
precision floating-point values `a' and `b'. If `zSign' is 1, the
difference is negated before being returned. `zSign' is ignored if the
result is a NaN. The subtraction is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
static float128 subFloat128Sigs( float128 a, float128 b, flag zSign )
{
int32 aExp, bExp, zExp;
bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1;
int32 expDiff;
float128 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
bSig1 = extractFloat128Frac1( b );
bSig0 = extractFloat128Frac0( b );
bExp = extractFloat128Exp( b );
expDiff = aExp - bExp;
shortShift128Left( aSig0, aSig1, 14, &aSig0, &aSig1 );
shortShift128Left( bSig0, bSig1, 14, &bSig0, &bSig1 );
if ( 0 < expDiff ) goto aExpBigger;
if ( expDiff < 0 ) goto bExpBigger;
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 | bSig0 | bSig1 ) {
return propagateFloat128NaN( a, b );
}
float_raise( float_flag_invalid );
z.low = float128_default_nan_low;
z.high = float128_default_nan_high;
return z;
}
if ( aExp == 0 ) {
aExp = 1;
bExp = 1;
}
if ( bSig0 < aSig0 ) goto aBigger;
if ( aSig0 < bSig0 ) goto bBigger;
if ( bSig1 < aSig1 ) goto aBigger;
if ( aSig1 < bSig1 ) goto bBigger;
return packFloat128( float_rounding_mode == float_round_down, 0, 0, 0 );
bExpBigger:
if ( bExp == 0x7FFF ) {
if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
return packFloat128( zSign ^ 1, 0x7FFF, 0, 0 );
}
if ( aExp == 0 ) {
++expDiff;
}
else {
aSig0 |= LIT64( 0x4000000000000000 );
}
shift128RightJamming( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
bSig0 |= LIT64( 0x4000000000000000 );
bBigger:
sub128( bSig0, bSig1, aSig0, aSig1, &zSig0, &zSig1 );
zExp = bExp;
zSign ^= 1;
goto normalizeRoundAndPack;
aExpBigger:
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
return a;
}
if ( bExp == 0 ) {
--expDiff;
}
else {
bSig0 |= LIT64( 0x4000000000000000 );
}
shift128RightJamming( bSig0, bSig1, expDiff, &bSig0, &bSig1 );
aSig0 |= LIT64( 0x4000000000000000 );
aBigger:
sub128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 );
zExp = aExp;
normalizeRoundAndPack:
--zExp;
return normalizeRoundAndPackFloat128( zSign, zExp - 14, zSig0, zSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the result of adding the quadruple-precision floating-point values
`a' and `b'. The operation is performed according to the IEC/IEEE Standard
for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float128_add( float128 a, float128 b )
{
flag aSign, bSign;
aSign = extractFloat128Sign( a );
bSign = extractFloat128Sign( b );
if ( aSign == bSign ) {
return addFloat128Sigs( a, b, aSign );
}
else {
return subFloat128Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of subtracting the quadruple-precision floating-point
values `a' and `b'. The operation is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float128_sub( float128 a, float128 b )
{
flag aSign, bSign;
aSign = extractFloat128Sign( a );
bSign = extractFloat128Sign( b );
if ( aSign == bSign ) {
return subFloat128Sigs( a, b, aSign );
}
else {
return addFloat128Sigs( a, b, aSign );
}
}
/*
-------------------------------------------------------------------------------
Returns the result of multiplying the quadruple-precision floating-point
values `a' and `b'. The operation is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float128_mul( float128 a, float128 b )
{
flag aSign, bSign, zSign;
int32 aExp, bExp, zExp;
bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3;
float128 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
bSig1 = extractFloat128Frac1( b );
bSig0 = extractFloat128Frac0( b );
bExp = extractFloat128Exp( b );
bSign = extractFloat128Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FFF ) {
if ( ( aSig0 | aSig1 )
|| ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
return propagateFloat128NaN( a, b );
}
if ( ( bExp | bSig0 | bSig1 ) == 0 ) goto invalid;
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( bExp == 0x7FFF ) {
if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
z.low = float128_default_nan_low;
z.high = float128_default_nan_high;
return z;
}
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
if ( bExp == 0 ) {
if ( ( bSig0 | bSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
}
zExp = aExp + bExp - 0x4000;
aSig0 |= LIT64( 0x0001000000000000 );
shortShift128Left( bSig0, bSig1, 16, &bSig0, &bSig1 );
mul128To256( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1, &zSig2, &zSig3 );
add128( zSig0, zSig1, aSig0, aSig1, &zSig0, &zSig1 );
zSig2 |= ( zSig3 != 0 );
if ( LIT64( 0x0002000000000000 ) <= zSig0 ) {
shift128ExtraRightJamming(
zSig0, zSig1, zSig2, 1, &zSig0, &zSig1, &zSig2 );
++zExp;
}
return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
}
/*
-------------------------------------------------------------------------------
Returns the result of dividing the quadruple-precision floating-point value
`a' by the corresponding value `b'. The operation is performed according to
the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float128_div( float128 a, float128 b )
{
flag aSign, bSign, zSign;
int32 aExp, bExp, zExp;
bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2;
bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
float128 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
bSig1 = extractFloat128Frac1( b );
bSig0 = extractFloat128Frac0( b );
bExp = extractFloat128Exp( b );
bSign = extractFloat128Sign( b );
zSign = aSign ^ bSign;
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, b );
if ( bExp == 0x7FFF ) {
if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
goto invalid;
}
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
if ( bExp == 0x7FFF ) {
if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
return packFloat128( zSign, 0, 0, 0 );
}
if ( bExp == 0 ) {
if ( ( bSig0 | bSig1 ) == 0 ) {
if ( ( aExp | aSig0 | aSig1 ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
z.low = float128_default_nan_low;
z.high = float128_default_nan_high;
return z;
}
float_raise( float_flag_divbyzero );
return packFloat128( zSign, 0x7FFF, 0, 0 );
}
normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( zSign, 0, 0, 0 );
normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
zExp = aExp - bExp + 0x3FFD;
shortShift128Left(
aSig0 | LIT64( 0x0001000000000000 ), aSig1, 15, &aSig0, &aSig1 );
shortShift128Left(
bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
if ( le128( bSig0, bSig1, aSig0, aSig1 ) ) {
shift128Right( aSig0, aSig1, 1, &aSig0, &aSig1 );
++zExp;
}
zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 );
mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 );
sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 );
while ( (sbits64) rem0 < 0 ) {
--zSig0;
add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 );
}
zSig1 = estimateDiv128To64( rem1, rem2, bSig0 );
if ( ( zSig1 & 0x3FFF ) <= 4 ) {
mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 );
sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 );
while ( (sbits64) rem1 < 0 ) {
--zSig1;
add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 );
}
zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
}
shift128ExtraRightJamming( zSig0, zSig1, 0, 15, &zSig0, &zSig1, &zSig2 );
return roundAndPackFloat128( zSign, zExp, zSig0, zSig1, zSig2 );
}
/*
-------------------------------------------------------------------------------
Returns the remainder of the quadruple-precision floating-point value `a'
with respect to the corresponding value `b'. The operation is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float128_rem( float128 a, float128 b )
{
flag aSign, bSign, zSign;
int32 aExp, bExp, expDiff;
bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2;
bits64 allZero, alternateASig0, alternateASig1, sigMean1;
sbits64 sigMean0;
float128 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
bSig1 = extractFloat128Frac1( b );
bSig0 = extractFloat128Frac0( b );
bExp = extractFloat128Exp( b );
bSign = extractFloat128Sign( b );
if ( aExp == 0x7FFF ) {
if ( ( aSig0 | aSig1 )
|| ( ( bExp == 0x7FFF ) && ( bSig0 | bSig1 ) ) ) {
return propagateFloat128NaN( a, b );
}
goto invalid;
}
if ( bExp == 0x7FFF ) {
if ( bSig0 | bSig1 ) return propagateFloat128NaN( a, b );
return a;
}
if ( bExp == 0 ) {
if ( ( bSig0 | bSig1 ) == 0 ) {
invalid:
float_raise( float_flag_invalid );
z.low = float128_default_nan_low;
z.high = float128_default_nan_high;
return z;
}
normalizeFloat128Subnormal( bSig0, bSig1, &bExp, &bSig0, &bSig1 );
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return a;
normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
expDiff = aExp - bExp;
if ( expDiff < -1 ) return a;
shortShift128Left(
aSig0 | LIT64( 0x0001000000000000 ),
aSig1,
15 - ( expDiff < 0 ),
&aSig0,
&aSig1
);
shortShift128Left(
bSig0 | LIT64( 0x0001000000000000 ), bSig1, 15, &bSig0, &bSig1 );
q = le128( bSig0, bSig1, aSig0, aSig1 );
if ( q ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
expDiff -= 64;
while ( 0 < expDiff ) {
q = estimateDiv128To64( aSig0, aSig1, bSig0 );
q = ( 4 < q ) ? q - 4 : 0;
mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
shortShift192Left( term0, term1, term2, 61, &term1, &term2, &allZero );
shortShift128Left( aSig0, aSig1, 61, &aSig0, &allZero );
sub128( aSig0, 0, term1, term2, &aSig0, &aSig1 );
expDiff -= 61;
}
if ( -64 < expDiff ) {
q = estimateDiv128To64( aSig0, aSig1, bSig0 );
q = ( 4 < q ) ? q - 4 : 0;
q >>= - expDiff;
shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
expDiff += 52;
if ( expDiff < 0 ) {
shift128Right( aSig0, aSig1, - expDiff, &aSig0, &aSig1 );
}
else {
shortShift128Left( aSig0, aSig1, expDiff, &aSig0, &aSig1 );
}
mul128By64To192( bSig0, bSig1, q, &term0, &term1, &term2 );
sub128( aSig0, aSig1, term1, term2, &aSig0, &aSig1 );
}
else {
shift128Right( aSig0, aSig1, 12, &aSig0, &aSig1 );
shift128Right( bSig0, bSig1, 12, &bSig0, &bSig1 );
}
do {
alternateASig0 = aSig0;
alternateASig1 = aSig1;
++q;
sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 );
} while ( 0 <= (sbits64) aSig0 );
add128(
aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 );
if ( ( sigMean0 < 0 )
|| ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) {
aSig0 = alternateASig0;
aSig1 = alternateASig1;
}
zSign = ( (sbits64) aSig0 < 0 );
if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 );
return
normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 );
}
/*
-------------------------------------------------------------------------------
Returns the square root of the quadruple-precision floating-point value `a'.
The operation is performed according to the IEC/IEEE Standard for Binary
Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
float128 float128_sqrt( float128 a )
{
flag aSign;
int32 aExp, zExp;
bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0;
bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3;
float128 z;
aSig1 = extractFloat128Frac1( a );
aSig0 = extractFloat128Frac0( a );
aExp = extractFloat128Exp( a );
aSign = extractFloat128Sign( a );
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) return propagateFloat128NaN( a, a );
if ( ! aSign ) return a;
goto invalid;
}
if ( aSign ) {
if ( ( aExp | aSig0 | aSig1 ) == 0 ) return a;
invalid:
float_raise( float_flag_invalid );
z.low = float128_default_nan_low;
z.high = float128_default_nan_high;
return z;
}
if ( aExp == 0 ) {
if ( ( aSig0 | aSig1 ) == 0 ) return packFloat128( 0, 0, 0, 0 );
normalizeFloat128Subnormal( aSig0, aSig1, &aExp, &aSig0, &aSig1 );
}
zExp = ( ( aExp - 0x3FFF )>>1 ) + 0x3FFE;
aSig0 |= LIT64( 0x0001000000000000 );
zSig0 = estimateSqrt32( aExp, aSig0>>17 );
shortShift128Left( aSig0, aSig1, 13 - ( aExp & 1 ), &aSig0, &aSig1 );
zSig0 = estimateDiv128To64( aSig0, aSig1, zSig0<<32 ) + ( zSig0<<30 );
doubleZSig0 = zSig0<<1;
mul64To128( zSig0, zSig0, &term0, &term1 );
sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 );
while ( (sbits64) rem0 < 0 ) {
--zSig0;
doubleZSig0 -= 2;
add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 );
}
zSig1 = estimateDiv128To64( rem1, 0, doubleZSig0 );
if ( ( zSig1 & 0x1FFF ) <= 5 ) {
if ( zSig1 == 0 ) zSig1 = 1;
mul64To128( doubleZSig0, zSig1, &term1, &term2 );
sub128( rem1, 0, term1, term2, &rem1, &rem2 );
mul64To128( zSig1, zSig1, &term2, &term3 );
sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 );
while ( (sbits64) rem1 < 0 ) {
--zSig1;
shortShift128Left( 0, zSig1, 1, &term2, &term3 );
term3 |= 1;
term2 |= doubleZSig0;
add192( rem1, rem2, rem3, 0, term2, term3, &rem1, &rem2, &rem3 );
}
zSig1 |= ( ( rem1 | rem2 | rem3 ) != 0 );
}
shift128ExtraRightJamming( zSig0, zSig1, 0, 14, &zSig0, &zSig1, &zSig2 );
return roundAndPackFloat128( 0, zExp, zSig0, zSig1, zSig2 );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float128_eq( float128 a, float128 b )
{
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
if ( float128_is_signaling_nan( a )
|| float128_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
return
( a.low == b.low )
&& ( ( a.high == b.high )
|| ( ( a.low == 0 )
&& ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
);
}
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is less than
or equal to the corresponding value `b', and 0 otherwise. The comparison
is performed according to the IEC/IEEE Standard for Binary Floating-Point
Arithmetic.
-------------------------------------------------------------------------------
*/
flag float128_le( float128 a, float128 b )
{
flag aSign, bSign;
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat128Sign( a );
bSign = extractFloat128Sign( b );
if ( aSign != bSign ) {
return
aSign
|| ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
== 0 );
}
return
aSign ? le128( b.high, b.low, a.high, a.low )
: le128( a.high, a.low, b.high, b.low );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. The comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float128_lt( float128 a, float128 b )
{
flag aSign, bSign;
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
float_raise( float_flag_invalid );
return 0;
}
aSign = extractFloat128Sign( a );
bSign = extractFloat128Sign( b );
if ( aSign != bSign ) {
return
aSign
&& ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
!= 0 );
}
return
aSign ? lt128( b.high, b.low, a.high, a.low )
: lt128( a.high, a.low, b.high, b.low );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is equal to
the corresponding value `b', and 0 otherwise. The invalid exception is
raised if either operand is a NaN. Otherwise, the comparison is performed
according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float128_eq_signaling( float128 a, float128 b )
{
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
float_raise( float_flag_invalid );
return 0;
}
return
( a.low == b.low )
&& ( ( a.high == b.high )
|| ( ( a.low == 0 )
&& ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) )
);
}
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is less than
or equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not
cause an exception. Otherwise, the comparison is performed according to the
IEC/IEEE Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float128_le_quiet( float128 a, float128 b )
{
flag aSign, bSign;
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
if ( float128_is_signaling_nan( a )
|| float128_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat128Sign( a );
bSign = extractFloat128Sign( b );
if ( aSign != bSign ) {
return
aSign
|| ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
== 0 );
}
return
aSign ? le128( b.high, b.low, a.high, a.low )
: le128( a.high, a.low, b.high, b.low );
}
/*
-------------------------------------------------------------------------------
Returns 1 if the quadruple-precision floating-point value `a' is less than
the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an
exception. Otherwise, the comparison is performed according to the IEC/IEEE
Standard for Binary Floating-Point Arithmetic.
-------------------------------------------------------------------------------
*/
flag float128_lt_quiet( float128 a, float128 b )
{
flag aSign, bSign;
if ( ( ( extractFloat128Exp( a ) == 0x7FFF )
&& ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) )
|| ( ( extractFloat128Exp( b ) == 0x7FFF )
&& ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) )
) {
if ( float128_is_signaling_nan( a )
|| float128_is_signaling_nan( b ) ) {
float_raise( float_flag_invalid );
}
return 0;
}
aSign = extractFloat128Sign( a );
bSign = extractFloat128Sign( b );
if ( aSign != bSign ) {
return
aSign
&& ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low )
!= 0 );
}
return
aSign ? lt128( b.high, b.low, a.high, a.low )
: lt128( a.high, a.low, b.high, b.low );
}
#endif
#if defined(SOFTFLOAT_FOR_GCC) && defined(SOFTFLOAT_NEED_FIXUNS)
/*
* These two routines are not part of the original softfloat distribution.
*
* They are based on the corresponding conversions to integer but return
* unsigned numbers instead since these functions are required by GCC.
*
* Added by Mark Brinicombe <mark@NetBSD.org> 27/09/97
*
* float64 version overhauled for SoftFloat 2a [bjh21 2000-07-15]
*/
/*
-------------------------------------------------------------------------------
Returns the result of converting the double-precision floating-point value
`a' to the 32-bit unsigned integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-point
Arithmetic, except that the conversion is always rounded toward zero. If
`a' is a NaN, the largest positive integer is returned. If the conversion
overflows, the largest integer positive is returned.
-------------------------------------------------------------------------------
*/
uint32 float64_to_uint32_round_to_zero( float64 a )
{
flag aSign;
int16 aExp, shiftCount;
bits64 aSig, savedASig;
uint32 z;
aSig = extractFloat64Frac( a );
aExp = extractFloat64Exp( a );
aSign = extractFloat64Sign( a );
if (aSign) {
float_raise( float_flag_invalid );
return(0);
}
if ( 0x41E < aExp ) {
float_raise( float_flag_invalid );
return 0xffffffff;
}
else if ( aExp < 0x3FF ) {
if ( aExp || aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
aSig |= LIT64( 0x0010000000000000 );
shiftCount = 0x433 - aExp;
savedASig = aSig;
aSig >>= shiftCount;
z = aSig;
if ( ( aSig<<shiftCount ) != savedASig ) {
float_exception_flags |= float_flag_inexact;
}
return z;
}
/*
-------------------------------------------------------------------------------
Returns the result of converting the single-precision floating-point value
`a' to the 32-bit unsigned integer format. The conversion is
performed according to the IEC/IEEE Standard for Binary Floating-point
Arithmetic, except that the conversion is always rounded toward zero. If
`a' is a NaN, the largest positive integer is returned. If the conversion
overflows, the largest positive integer is returned.
-------------------------------------------------------------------------------
*/
uint32 float32_to_uint32_round_to_zero( float32 a )
{
flag aSign;
int16 aExp, shiftCount;
bits32 aSig;
uint32 z;
aSig = extractFloat32Frac( a );
aExp = extractFloat32Exp( a );
aSign = extractFloat32Sign( a );
shiftCount = aExp - 0x9E;
if (aSign) {
float_raise( float_flag_invalid );
return(0);
}
if ( 0 < shiftCount ) {
float_raise( float_flag_invalid );
return 0xFFFFFFFF;
}
else if ( aExp <= 0x7E ) {
if ( aExp | aSig ) float_exception_flags |= float_flag_inexact;
return 0;
}
aSig = ( aSig | 0x800000 )<<8;
z = aSig>>( - shiftCount );
if ( aSig<<( shiftCount & 31 ) ) {
float_exception_flags |= float_flag_inexact;
}
return z;
}
#endif
diff --git a/lib/libc/softfloat/eqdf2.c b/lib/libc/softfloat/eqdf2.c
index dc4b2d24f285..e642c467aa4a 100644
--- a/lib/libc/softfloat/eqdf2.c
+++ b/lib/libc/softfloat/eqdf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: eqdf2.c,v 1.1 2000/06/06 08:15:02 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
-#include <sys/cdefs.h>
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
flag __eqdf2(float64, float64);
flag
__eqdf2(float64 a, float64 b)
{
/* libgcc1.c says !(a == b) */
return !float64_eq(a, b);
}
diff --git a/lib/libc/softfloat/eqsf2.c b/lib/libc/softfloat/eqsf2.c
index bebb4d1f76a6..866db81bc5ab 100644
--- a/lib/libc/softfloat/eqsf2.c
+++ b/lib/libc/softfloat/eqsf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: eqsf2.c,v 1.1 2000/06/06 08:15:03 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
-#include <sys/cdefs.h>
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
flag __eqsf2(float32, float32);
flag
__eqsf2(float32 a, float32 b)
{
/* libgcc1.c says !(a == b) */
return !float32_eq(a, b);
}
diff --git a/lib/libc/softfloat/eqtf2.c b/lib/libc/softfloat/eqtf2.c
index 8852adafa2ff..b7ae12d265b4 100644
--- a/lib/libc/softfloat/eqtf2.c
+++ b/lib/libc/softfloat/eqtf2.c
@@ -1,22 +1,21 @@
/* $NetBSD: eqtf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
/*
* Written by Matt Thomas, 2011. This file is in the Public Domain.
*/
-#include <sys/cdefs.h>
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
#ifdef FLOAT128
flag __eqtf2(float128, float128);
flag
__eqtf2(float128 a, float128 b)
{
/* libgcc1.c says !(a == b) */
return !float128_eq(a, b);
}
#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/fpgetmask.c b/lib/libc/softfloat/fpgetmask.c
index 78177544538e..c417e163d770 100644
--- a/lib/libc/softfloat/fpgetmask.c
+++ b/lib/libc/softfloat/fpgetmask.c
@@ -1,53 +1,52 @@
/* $NetBSD: fpgetmask.c,v 1.4 2008/04/28 20:23:00 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ieeefp.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
#ifdef __weak_alias
__weak_alias(fpgetmask,_fpgetmask)
#endif
fp_except
fpgetmask(void)
{
return float_exception_mask;
}
diff --git a/lib/libc/softfloat/fpgetround.c b/lib/libc/softfloat/fpgetround.c
index e098ef46c122..2c060d86f5ae 100644
--- a/lib/libc/softfloat/fpgetround.c
+++ b/lib/libc/softfloat/fpgetround.c
@@ -1,53 +1,52 @@
/* $NetBSD: fpgetround.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ieeefp.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
#ifdef __weak_alias
__weak_alias(fpgetround,_fpgetround)
#endif
fp_rnd_t
fpgetround(void)
{
return float_rounding_mode;
}
diff --git a/lib/libc/softfloat/fpgetsticky.c b/lib/libc/softfloat/fpgetsticky.c
index 0caff5b0578f..2d31d9149a21 100644
--- a/lib/libc/softfloat/fpgetsticky.c
+++ b/lib/libc/softfloat/fpgetsticky.c
@@ -1,53 +1,52 @@
/* $NetBSD: fpgetsticky.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ieeefp.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
#ifdef __weak_alias
__weak_alias(fpgetsticky,_fpgetsticky)
#endif
fp_except
fpgetsticky(void)
{
return float_exception_flags;
}
diff --git a/lib/libc/softfloat/fpsetmask.c b/lib/libc/softfloat/fpsetmask.c
index 90f457563513..b65a1e8de350 100644
--- a/lib/libc/softfloat/fpsetmask.c
+++ b/lib/libc/softfloat/fpsetmask.c
@@ -1,56 +1,55 @@
/* $NetBSD: fpsetmask.c,v 1.4 2008/04/28 20:23:00 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ieeefp.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
#ifdef __weak_alias
__weak_alias(fpsetmask,_fpsetmask)
#endif
fp_except
fpsetmask(fp_except mask)
{
fp_except old;
old = float_exception_mask;
float_exception_mask = mask;
return old;
}
diff --git a/lib/libc/softfloat/fpsetround.c b/lib/libc/softfloat/fpsetround.c
index 37fa7064ce84..f48a683bf6d8 100644
--- a/lib/libc/softfloat/fpsetround.c
+++ b/lib/libc/softfloat/fpsetround.c
@@ -1,56 +1,55 @@
/* $NetBSD: fpsetround.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ieeefp.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
#ifdef __weak_alias
__weak_alias(fpsetround,_fpsetround)
#endif
fp_rnd_t
fpsetround(fp_rnd_t rnd_dir)
{
fp_rnd_t old;
old = float_rounding_mode;
float_rounding_mode = rnd_dir;
return old;
}
diff --git a/lib/libc/softfloat/fpsetsticky.c b/lib/libc/softfloat/fpsetsticky.c
index 3916161c8e23..2a056c032645 100644
--- a/lib/libc/softfloat/fpsetsticky.c
+++ b/lib/libc/softfloat/fpsetsticky.c
@@ -1,56 +1,55 @@
/* $NetBSD: fpsetsticky.c,v 1.3 2008/04/28 20:23:00 martin Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Neil A. Carson and Mark Brinicombe
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ieeefp.h>
#ifdef SOFTFLOAT_FOR_GCC
#include "softfloat-for-gcc.h"
#endif
#include "milieu.h"
#include "softfloat.h"
#ifdef __weak_alias
__weak_alias(fpsetsticky,_fpsetsticky)
#endif
fp_except
fpsetsticky(fp_except except)
{
fp_except old;
old = float_exception_flags;
float_exception_flags = except;
return old;
}
diff --git a/lib/libc/softfloat/gedf2.c b/lib/libc/softfloat/gedf2.c
index 75769823991b..2d82ef394b54 100644
--- a/lib/libc/softfloat/gedf2.c
+++ b/lib/libc/softfloat/gedf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: gedf2.c,v 1.1 2000/06/06 08:15:05 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __gedf2(float64, float64);
flag
__gedf2(float64 a, float64 b)
{
/* libgcc1.c says (a >= b) - 1 */
return float64_le(b, a) - 1;
}
diff --git a/lib/libc/softfloat/gesf2.c b/lib/libc/softfloat/gesf2.c
index 1ec47ae32ea6..8822ebecd983 100644
--- a/lib/libc/softfloat/gesf2.c
+++ b/lib/libc/softfloat/gesf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: gesf2.c,v 1.1 2000/06/06 08:15:05 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __gesf2(float32, float32);
flag
__gesf2(float32 a, float32 b)
{
/* libgcc1.c says (a >= b) - 1 */
return float32_le(b, a) - 1;
}
diff --git a/lib/libc/softfloat/getf2.c b/lib/libc/softfloat/getf2.c
index ac4665eedb29..168cd00e2003 100644
--- a/lib/libc/softfloat/getf2.c
+++ b/lib/libc/softfloat/getf2.c
@@ -1,24 +1,23 @@
/* $NetBSD: getf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
/*
* Written by Matt Thomas, 2011. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOAT128
flag __getf2(float128, float128);
flag
__getf2(float128 a, float128 b)
{
/* libgcc1.c says (a >= b) - 1 */
return float128_le(b, a) - 1;
}
#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/gexf2.c b/lib/libc/softfloat/gexf2.c
index 51f98f2ae03a..291b1d040409 100644
--- a/lib/libc/softfloat/gexf2.c
+++ b/lib/libc/softfloat/gexf2.c
@@ -1,23 +1,22 @@
/* $NetBSD: gexf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOATX80
flag __gexf2(floatx80, floatx80);
flag
__gexf2(floatx80 a, floatx80 b)
{
/* libgcc1.c says (a >= b) - 1 */
return floatx80_le(b, a) - 1;
}
#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/gtdf2.c b/lib/libc/softfloat/gtdf2.c
index fc6d2fd06a34..c2a7d5d7264a 100644
--- a/lib/libc/softfloat/gtdf2.c
+++ b/lib/libc/softfloat/gtdf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: gtdf2.c,v 1.1 2000/06/06 08:15:05 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __gtdf2(float64, float64);
flag
__gtdf2(float64 a, float64 b)
{
/* libgcc1.c says a > b */
return float64_lt(b, a);
}
diff --git a/lib/libc/softfloat/gtsf2.c b/lib/libc/softfloat/gtsf2.c
index ae8d7c209106..48988084f753 100644
--- a/lib/libc/softfloat/gtsf2.c
+++ b/lib/libc/softfloat/gtsf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: gtsf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __gtsf2(float32, float32);
flag
__gtsf2(float32 a, float32 b)
{
/* libgcc1.c says a > b */
return float32_lt(b, a);
}
diff --git a/lib/libc/softfloat/gttf2.c b/lib/libc/softfloat/gttf2.c
index 76684e013e35..22ebae560aaa 100644
--- a/lib/libc/softfloat/gttf2.c
+++ b/lib/libc/softfloat/gttf2.c
@@ -1,24 +1,23 @@
/* $NetBSD: gttf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
/*
* Written by Matt Thomas, 2011. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOAT128
flag __gttf2(float128, float128);
flag
__gttf2(float128 a, float128 b)
{
/* libgcc1.c says a > b */
return float128_lt(b, a);
}
#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/gtxf2.c b/lib/libc/softfloat/gtxf2.c
index 284526f0c410..ea883d1fb848 100644
--- a/lib/libc/softfloat/gtxf2.c
+++ b/lib/libc/softfloat/gtxf2.c
@@ -1,23 +1,22 @@
/* $NetBSD: gtxf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOATX80
flag __gtxf2(floatx80, floatx80);
flag
__gtxf2(floatx80 a, floatx80 b)
{
/* libgcc1.c says a > b */
return floatx80_lt(b, a);
}
#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/ledf2.c b/lib/libc/softfloat/ledf2.c
index 689c7d70c1ca..3be7f5e5fa75 100644
--- a/lib/libc/softfloat/ledf2.c
+++ b/lib/libc/softfloat/ledf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: ledf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __ledf2(float64, float64);
flag
__ledf2(float64 a, float64 b)
{
/* libgcc1.c says 1 - (a <= b) */
return 1 - float64_le(a, b);
}
diff --git a/lib/libc/softfloat/lesf2.c b/lib/libc/softfloat/lesf2.c
index 98ba0722525a..e8d60d5733e0 100644
--- a/lib/libc/softfloat/lesf2.c
+++ b/lib/libc/softfloat/lesf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: lesf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __lesf2(float32, float32);
flag
__lesf2(float32 a, float32 b)
{
/* libgcc1.c says 1 - (a <= b) */
return 1 - float32_le(a, b);
}
diff --git a/lib/libc/softfloat/letf2.c b/lib/libc/softfloat/letf2.c
index d5dbd45a106b..a5a25ebe0848 100644
--- a/lib/libc/softfloat/letf2.c
+++ b/lib/libc/softfloat/letf2.c
@@ -1,24 +1,23 @@
/* $NetBSD: letf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
/*
* Written by Matt Thomas, 2011. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOAT128
flag __letf2(float128, float128);
flag
__letf2(float128 a, float128 b)
{
/* libgcc1.c says 1 - (a <= b) */
return 1 - float128_le(a, b);
}
#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/ltdf2.c b/lib/libc/softfloat/ltdf2.c
index 8c5342a3c6ff..fa58b55f24f5 100644
--- a/lib/libc/softfloat/ltdf2.c
+++ b/lib/libc/softfloat/ltdf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: ltdf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __ltdf2(float64, float64);
flag
__ltdf2(float64 a, float64 b)
{
/* libgcc1.c says -(a < b) */
return -float64_lt(a, b);
}
diff --git a/lib/libc/softfloat/ltsf2.c b/lib/libc/softfloat/ltsf2.c
index 9eb9e990bc63..e19b2f4328cf 100644
--- a/lib/libc/softfloat/ltsf2.c
+++ b/lib/libc/softfloat/ltsf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: ltsf2.c,v 1.1 2000/06/06 08:15:06 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __ltsf2(float32, float32);
flag
__ltsf2(float32 a, float32 b)
{
/* libgcc1.c says -(a < b) */
return -float32_lt(a, b);
}
diff --git a/lib/libc/softfloat/lttf2.c b/lib/libc/softfloat/lttf2.c
index ad8e4830d904..ce99f6cfee34 100644
--- a/lib/libc/softfloat/lttf2.c
+++ b/lib/libc/softfloat/lttf2.c
@@ -1,24 +1,23 @@
/* $NetBSD: lttf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
/*
* Written by Matt Thomas, 2011. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOAT128
flag __lttf2(float128, float128);
flag
__lttf2(float128 a, float128 b)
{
/* libgcc1.c says -(a < b) */
return -float128_lt(a, b);
}
#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/nedf2.c b/lib/libc/softfloat/nedf2.c
index 7c1e49643d72..a7af22a9a9e9 100644
--- a/lib/libc/softfloat/nedf2.c
+++ b/lib/libc/softfloat/nedf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: nedf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __nedf2(float64, float64);
flag
__nedf2(float64 a, float64 b)
{
/* libgcc1.c says a != b */
return !float64_eq(a, b);
}
diff --git a/lib/libc/softfloat/negdf2.c b/lib/libc/softfloat/negdf2.c
index 27dfdd5ee688..e42d26d2287b 100644
--- a/lib/libc/softfloat/negdf2.c
+++ b/lib/libc/softfloat/negdf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: negdf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
float64 __negdf2(float64);
float64
__negdf2(float64 a)
{
/* libgcc1.c says -a */
return a ^ FLOAT64_MANGLE(0x8000000000000000ULL);
}
diff --git a/lib/libc/softfloat/negsf2.c b/lib/libc/softfloat/negsf2.c
index 9b4a269132e1..e4f33f3a8422 100644
--- a/lib/libc/softfloat/negsf2.c
+++ b/lib/libc/softfloat/negsf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: negsf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
float32 __negsf2(float32);
float32
__negsf2(float32 a)
{
/* libgcc1.c says INTIFY(-a) */
return a ^ 0x80000000;
}
diff --git a/lib/libc/softfloat/negtf2.c b/lib/libc/softfloat/negtf2.c
index d8cb6a0dc4bc..bb757a3d0a3e 100644
--- a/lib/libc/softfloat/negtf2.c
+++ b/lib/libc/softfloat/negtf2.c
@@ -1,25 +1,24 @@
/* $NetBSD: negtf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
/*
* Written by Matt Thomas, 2011. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOAT128
float128 __negtf2(float128);
float128
__negtf2(float128 a)
{
/* libgcc1.c says -a */
a.high ^= FLOAT64_MANGLE(0x8000000000000000ULL);
return a;
}
#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/negxf2.c b/lib/libc/softfloat/negxf2.c
index fd906c830e28..acc59f0755c8 100644
--- a/lib/libc/softfloat/negxf2.c
+++ b/lib/libc/softfloat/negxf2.c
@@ -1,23 +1,22 @@
/* $NetBSD: negxf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOATX80
floatx80 __negxf2(floatx80);
floatx80
__negxf2(floatx80 a)
{
/* libgcc1.c says -a */
return __mulxf3(a,__floatsixf(-1));
}
#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/nesf2.c b/lib/libc/softfloat/nesf2.c
index d7c580c2ff8c..8f2d93681b61 100644
--- a/lib/libc/softfloat/nesf2.c
+++ b/lib/libc/softfloat/nesf2.c
@@ -1,20 +1,19 @@
/* $NetBSD: nesf2.c,v 1.1 2000/06/06 08:15:07 bjh21 Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __nesf2(float32, float32);
flag
__nesf2(float32 a, float32 b)
{
/* libgcc1.c says a != b */
return !float32_eq(a, b);
}
diff --git a/lib/libc/softfloat/netf2.c b/lib/libc/softfloat/netf2.c
index c54b22b8bf22..17b54da01dd9 100644
--- a/lib/libc/softfloat/netf2.c
+++ b/lib/libc/softfloat/netf2.c
@@ -1,24 +1,23 @@
/* $NetBSD: netf2.c,v 1.1 2011/01/17 10:08:35 matt Exp $ */
/*
* Written by Matt Thomas, 2011. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOAT128
flag __netf2(float128, float128);
flag
__netf2(float128 a, float128 b)
{
/* libgcc1.c says a != b */
return !float128_eq(a, b);
}
#endif /* FLOAT128 */
diff --git a/lib/libc/softfloat/nexf2.c b/lib/libc/softfloat/nexf2.c
index 6d75d164d9e2..e48895d3eca2 100644
--- a/lib/libc/softfloat/nexf2.c
+++ b/lib/libc/softfloat/nexf2.c
@@ -1,23 +1,22 @@
/* $NetBSD: nexf2.c,v 1.2 2004/09/27 10:16:24 he Exp $ */
/*
* Written by Ben Harris, 2000. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
#ifdef FLOATX80
flag __nexf2(floatx80, floatx80);
flag
__nexf2(floatx80 a, floatx80 b)
{
/* libgcc1.c says a != b */
return !floatx80_eq(a, b);
}
#endif /* FLOATX80 */
diff --git a/lib/libc/softfloat/timesoftfloat.c b/lib/libc/softfloat/timesoftfloat.c
index 4abff11e13e6..fc6d196f74ab 100644
--- a/lib/libc/softfloat/timesoftfloat.c
+++ b/lib/libc/softfloat/timesoftfloat.c
@@ -1,2637 +1,2636 @@
/* $NetBSD: timesoftfloat.c,v 1.1 2000/06/06 08:15:11 bjh21 Exp $ */
/*
===============================================================================
This C source file is part of the SoftFloat IEC/IEEE Floating-point
Arithmetic Package, Release 2a.
Written by John R. Hauser. This work was made possible in part by the
International Computer Science Institute, located at Suite 600, 1947 Center
Street, Berkeley, California 94704. Funding was partially provided by the
National Science Foundation under grant MIP-9311980. The original version
of this code was written as part of a project to build a fixed-point vector
processor in collaboration with the University of California at Berkeley,
overseen by Profs. Nelson Morgan and John Wawrzynek. More information
is available through the Web page `http://HTTP.CS.Berkeley.EDU/~jhauser/
arithmetic/SoftFloat.html'.
THIS SOFTWARE IS DISTRIBUTED AS IS, FOR FREE. Although reasonable effort
has been made to avoid it, THIS SOFTWARE MAY CONTAIN FAULTS THAT WILL AT
TIMES RESULT IN INCORRECT BEHAVIOR. USE OF THIS SOFTWARE IS RESTRICTED TO
PERSONS AND ORGANIZATIONS WHO CAN AND WILL TAKE FULL RESPONSIBILITY FOR ANY
AND ALL LOSSES, COSTS, OR OTHER PROBLEMS ARISING FROM ITS USE.
Derivative works are acceptable, even for commercial purposes, so long as
(1) they include prominent notice that the work is derivative, and (2) they
include prominent notice akin to these four paragraphs for those parts of
this code that are retained.
===============================================================================
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "milieu.h"
#include "softfloat.h"
enum {
minIterations = 1000
};
static void fail( const char *message, ... )
{
va_list varArgs;
fputs( "timesoftfloat: ", stderr );
va_start( varArgs, message );
vfprintf( stderr, message, varArgs );
va_end( varArgs );
fputs( ".\n", stderr );
exit( EXIT_FAILURE );
}
static char *functionName;
static char *roundingPrecisionName, *roundingModeName, *tininessModeName;
static void reportTime( int32 count, long clocks )
{
printf(
"%8.1f kops/s: %s",
( count / ( ( (float) clocks ) / CLOCKS_PER_SEC ) ) / 1000,
functionName
);
if ( roundingModeName ) {
if ( roundingPrecisionName ) {
fputs( ", precision ", stdout );
fputs( roundingPrecisionName, stdout );
}
fputs( ", rounding ", stdout );
fputs( roundingModeName, stdout );
if ( tininessModeName ) {
fputs( ", tininess ", stdout );
fputs( tininessModeName, stdout );
fputs( " rounding", stdout );
}
}
fputc( '\n', stdout );
}
enum {
numInputs_int32 = 32
};
static const int32 inputs_int32[ numInputs_int32 ] = {
0xFFFFBB79, 0x405CF80F, 0x00000000, 0xFFFFFD04,
0xFFF20002, 0x0C8EF795, 0xF00011FF, 0x000006CA,
0x00009BFE, 0xFF4862E3, 0x9FFFEFFE, 0xFFFFFFB7,
0x0BFF7FFF, 0x0000F37A, 0x0011DFFE, 0x00000006,
0xFFF02006, 0xFFFFF7D1, 0x10200003, 0xDE8DF765,
0x00003E02, 0x000019E8, 0x0008FFFE, 0xFFFFFB5C,
0xFFDF7FFE, 0x07C42FBF, 0x0FFFE3FF, 0x040B9F13,
0xBFFFFFF8, 0x0001BF56, 0x000017F6, 0x000A908A
};
static void time_a_int32_z_float32( float32 function( int32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_int32_z_float64( float64 function( int32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#ifdef FLOATX80
static void time_a_int32_z_floatx80( floatx80 function( int32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
#ifdef FLOAT128
static void time_a_int32_z_float128( float128 function( int32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
enum {
numInputs_int64 = 32
};
static const int64 inputs_int64[ numInputs_int64 ] = {
LIT64( 0xFBFFC3FFFFFFFFFF ),
LIT64( 0x0000000003C589BC ),
LIT64( 0x00000000400013FE ),
LIT64( 0x0000000000186171 ),
LIT64( 0xFFFFFFFFFFFEFBFA ),
LIT64( 0xFFFFFD79E6DFFC73 ),
LIT64( 0x0000000010001DFF ),
LIT64( 0xDD1A0F0C78513710 ),
LIT64( 0xFFFF83FFFFFEFFFE ),
LIT64( 0x00756EBD1AD0C1C7 ),
LIT64( 0x0003FDFFFFFFFFBE ),
LIT64( 0x0007D0FB2C2CA951 ),
LIT64( 0x0007FC0007FFFFFE ),
LIT64( 0x0000001F942B18BB ),
LIT64( 0x0000080101FFFFFE ),
LIT64( 0xFFFFFFFFFFFF0978 ),
LIT64( 0x000000000008BFFF ),
LIT64( 0x0000000006F5AF08 ),
LIT64( 0xFFDEFF7FFFFFFFFE ),
LIT64( 0x0000000000000003 ),
LIT64( 0x3FFFFFFFFF80007D ),
LIT64( 0x0000000000000078 ),
LIT64( 0xFFF80000007FDFFD ),
LIT64( 0x1BBC775B78016AB0 ),
LIT64( 0xFFF9001FFFFFFFFE ),
LIT64( 0xFFFD4767AB98E43F ),
LIT64( 0xFFFFFEFFFE00001E ),
LIT64( 0xFFFFFFFFFFF04EFD ),
LIT64( 0x07FFFFFFFFFFF7FF ),
LIT64( 0xFFFC9EAA38F89050 ),
LIT64( 0x00000020FBFFFFFE ),
LIT64( 0x0000099AE6455357 )
};
static void time_a_int64_z_float32( float32 function( int64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_int64_z_float64( float64 function( int64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#ifdef FLOATX80
static void time_a_int64_z_floatx80( floatx80 function( int64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
#ifdef FLOAT128
static void time_a_int64_z_float128( float128 function( int64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_int64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_int64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
enum {
numInputs_float32 = 32
};
static const float32 inputs_float32[ numInputs_float32 ] = {
0x4EFA0000, 0xC1D0B328, 0x80000000, 0x3E69A31E,
0xAF803EFF, 0x3F800000, 0x17BF8000, 0xE74A301A,
0x4E010003, 0x7EE3C75D, 0xBD803FE0, 0xBFFEFF00,
0x7981F800, 0x431FFFFC, 0xC100C000, 0x3D87EFFF,
0x4103FEFE, 0xBC000007, 0xBF01F7FF, 0x4E6C6B5C,
0xC187FFFE, 0xC58B9F13, 0x4F88007F, 0xDF004007,
0xB7FFD7FE, 0x7E8001FB, 0x46EFFBFF, 0x31C10000,
0xDB428661, 0x33F89B1F, 0xA3BFEFFF, 0x537BFFBE
};
static void time_a_float32_z_int32( int32 function( float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_float32_z_int64( int64 function( float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_float32_z_float64( float64 function( float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#ifdef FLOATX80
static void time_a_float32_z_floatx80( floatx80 function( float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
#ifdef FLOAT128
static void time_a_float32_z_float128( float128 function( float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
static void time_az_float32( float32 function( float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float32[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_ab_float32_z_flag( flag function( float32, float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function(
inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
function(
inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_abz_float32( float32 function( float32, float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function(
inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
function(
inputs_float32[ inputNumA ], inputs_float32[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float32 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static const float32 inputs_float32_pos[ numInputs_float32 ] = {
0x4EFA0000, 0x41D0B328, 0x00000000, 0x3E69A31E,
0x2F803EFF, 0x3F800000, 0x17BF8000, 0x674A301A,
0x4E010003, 0x7EE3C75D, 0x3D803FE0, 0x3FFEFF00,
0x7981F800, 0x431FFFFC, 0x4100C000, 0x3D87EFFF,
0x4103FEFE, 0x3C000007, 0x3F01F7FF, 0x4E6C6B5C,
0x4187FFFE, 0x458B9F13, 0x4F88007F, 0x5F004007,
0x37FFD7FE, 0x7E8001FB, 0x46EFFBFF, 0x31C10000,
0x5B428661, 0x33F89B1F, 0x23BFEFFF, 0x537BFFBE
};
static void time_az_float32_pos( float32 function( float32 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float32_pos[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float32_pos[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float32 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
enum {
numInputs_float64 = 32
};
static const float64 inputs_float64[ numInputs_float64 ] = {
LIT64( 0x422FFFC008000000 ),
LIT64( 0xB7E0000480000000 ),
LIT64( 0xF3FD2546120B7935 ),
LIT64( 0x3FF0000000000000 ),
LIT64( 0xCE07F766F09588D6 ),
LIT64( 0x8000000000000000 ),
LIT64( 0x3FCE000400000000 ),
LIT64( 0x8313B60F0032BED8 ),
LIT64( 0xC1EFFFFFC0002000 ),
LIT64( 0x3FB3C75D224F2B0F ),
LIT64( 0x7FD00000004000FF ),
LIT64( 0xA12FFF8000001FFF ),
LIT64( 0x3EE0000000FE0000 ),
LIT64( 0x0010000080000004 ),
LIT64( 0x41CFFFFE00000020 ),
LIT64( 0x40303FFFFFFFFFFD ),
LIT64( 0x3FD000003FEFFFFF ),
LIT64( 0xBFD0000010000000 ),
LIT64( 0xB7FC6B5C16CA55CF ),
LIT64( 0x413EEB940B9D1301 ),
LIT64( 0xC7E00200001FFFFF ),
LIT64( 0x47F00021FFFFFFFE ),
LIT64( 0xBFFFFFFFF80000FF ),
LIT64( 0xC07FFFFFE00FFFFF ),
LIT64( 0x001497A63740C5E8 ),
LIT64( 0xC4BFFFE0001FFFFF ),
LIT64( 0x96FFDFFEFFFFFFFF ),
LIT64( 0x403FC000000001FE ),
LIT64( 0xFFD00000000001F6 ),
LIT64( 0x0640400002000000 ),
LIT64( 0x479CEE1E4F789FE0 ),
LIT64( 0xC237FFFFFFFFFDFE )
};
static void time_a_float64_z_int32( int32 function( float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_float64_z_int64( int64 function( float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_float64_z_float32( float32 function( float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#ifdef FLOATX80
static void time_a_float64_z_floatx80( floatx80 function( float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
#ifdef FLOAT128
static void time_a_float64_z_float128( float128 function( float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
static void time_az_float64( float64 function( float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float64[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_ab_float64_z_flag( flag function( float64, float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function(
inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
function(
inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_abz_float64( float64 function( float64, float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function(
inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
function(
inputs_float64[ inputNumA ], inputs_float64[ inputNumB ] );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float64 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static const float64 inputs_float64_pos[ numInputs_float64 ] = {
LIT64( 0x422FFFC008000000 ),
LIT64( 0x37E0000480000000 ),
LIT64( 0x73FD2546120B7935 ),
LIT64( 0x3FF0000000000000 ),
LIT64( 0x4E07F766F09588D6 ),
LIT64( 0x0000000000000000 ),
LIT64( 0x3FCE000400000000 ),
LIT64( 0x0313B60F0032BED8 ),
LIT64( 0x41EFFFFFC0002000 ),
LIT64( 0x3FB3C75D224F2B0F ),
LIT64( 0x7FD00000004000FF ),
LIT64( 0x212FFF8000001FFF ),
LIT64( 0x3EE0000000FE0000 ),
LIT64( 0x0010000080000004 ),
LIT64( 0x41CFFFFE00000020 ),
LIT64( 0x40303FFFFFFFFFFD ),
LIT64( 0x3FD000003FEFFFFF ),
LIT64( 0x3FD0000010000000 ),
LIT64( 0x37FC6B5C16CA55CF ),
LIT64( 0x413EEB940B9D1301 ),
LIT64( 0x47E00200001FFFFF ),
LIT64( 0x47F00021FFFFFFFE ),
LIT64( 0x3FFFFFFFF80000FF ),
LIT64( 0x407FFFFFE00FFFFF ),
LIT64( 0x001497A63740C5E8 ),
LIT64( 0x44BFFFE0001FFFFF ),
LIT64( 0x16FFDFFEFFFFFFFF ),
LIT64( 0x403FC000000001FE ),
LIT64( 0x7FD00000000001F6 ),
LIT64( 0x0640400002000000 ),
LIT64( 0x479CEE1E4F789FE0 ),
LIT64( 0x4237FFFFFFFFFDFE )
};
static void time_az_float64_pos( float64 function( float64 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
function( inputs_float64_pos[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
function( inputs_float64_pos[ inputNum ] );
inputNum = ( inputNum + 1 ) & ( numInputs_float64 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#ifdef FLOATX80
enum {
numInputs_floatx80 = 32
};
static const struct {
bits16 high;
bits64 low;
} inputs_floatx80[ numInputs_floatx80 ] = {
{ 0xC03F, LIT64( 0xA9BE15A19C1E8B62 ) },
{ 0x8000, LIT64( 0x0000000000000000 ) },
{ 0x75A8, LIT64( 0xE59591E4788957A5 ) },
{ 0xBFFF, LIT64( 0xFFF0000000000040 ) },
{ 0x0CD8, LIT64( 0xFC000000000007FE ) },
{ 0x43BA, LIT64( 0x99A4000000000000 ) },
{ 0x3FFF, LIT64( 0x8000000000000000 ) },
{ 0x4081, LIT64( 0x94FBF1BCEB5545F0 ) },
{ 0x403E, LIT64( 0xFFF0000000002000 ) },
{ 0x3FFE, LIT64( 0xC860E3C75D224F28 ) },
{ 0x407E, LIT64( 0xFC00000FFFFFFFFE ) },
{ 0x737A, LIT64( 0x800000007FFDFFFE ) },
{ 0x4044, LIT64( 0xFFFFFF80000FFFFF ) },
{ 0xBBFE, LIT64( 0x8000040000001FFE ) },
{ 0xC002, LIT64( 0xFF80000000000020 ) },
{ 0xDE8D, LIT64( 0xFFFFFFFFFFE00004 ) },
{ 0xC004, LIT64( 0x8000000000003FFB ) },
{ 0x407F, LIT64( 0x800000000003FFFE ) },
{ 0xC000, LIT64( 0xA459EE6A5C16CA55 ) },
{ 0x8003, LIT64( 0xC42CBF7399AEEB94 ) },
{ 0xBF7F, LIT64( 0xF800000000000006 ) },
{ 0xC07F, LIT64( 0xBF56BE8871F28FEA ) },
{ 0xC07E, LIT64( 0xFFFF77FFFFFFFFFE ) },
{ 0xADC9, LIT64( 0x8000000FFFFFFFDE ) },
{ 0xC001, LIT64( 0xEFF7FFFFFFFFFFFF ) },
{ 0x4001, LIT64( 0xBE84F30125C497A6 ) },
{ 0xC06B, LIT64( 0xEFFFFFFFFFFFFFFF ) },
{ 0x4080, LIT64( 0xFFFFFFFFBFFFFFFF ) },
{ 0x87E9, LIT64( 0x81FFFFFFFFFFFBFF ) },
{ 0xA63F, LIT64( 0x801FFFFFFEFFFFFE ) },
{ 0x403C, LIT64( 0x801FFFFFFFF7FFFF ) },
{ 0x4018, LIT64( 0x8000000000080003 ) }
};
static void time_a_floatx80_z_int32( int32 function( floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
floatx80 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_floatx80_z_int64( int64 function( floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
floatx80 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_floatx80_z_float32( float32 function( floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
floatx80 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_floatx80_z_float64( float64 function( floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
floatx80 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#ifdef FLOAT128
static void time_a_floatx80_z_float128( float128 function( floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
floatx80 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
static void time_az_floatx80( floatx80 function( floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
floatx80 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNum ].low;
a.high = inputs_floatx80[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_ab_floatx80_z_flag( flag function( floatx80, floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
floatx80 a, b;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNumA ].low;
a.high = inputs_floatx80[ inputNumA ].high;
b.low = inputs_floatx80[ inputNumB ].low;
b.high = inputs_floatx80[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNumA ].low;
a.high = inputs_floatx80[ inputNumA ].high;
b.low = inputs_floatx80[ inputNumB ].low;
b.high = inputs_floatx80[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_abz_floatx80( floatx80 function( floatx80, floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
floatx80 a, b;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80[ inputNumA ].low;
a.high = inputs_floatx80[ inputNumA ].high;
b.low = inputs_floatx80[ inputNumB ].low;
b.high = inputs_floatx80[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80[ inputNumA ].low;
a.high = inputs_floatx80[ inputNumA ].high;
b.low = inputs_floatx80[ inputNumB ].low;
b.high = inputs_floatx80[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_floatx80 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static const struct {
bits16 high;
bits64 low;
} inputs_floatx80_pos[ numInputs_floatx80 ] = {
{ 0x403F, LIT64( 0xA9BE15A19C1E8B62 ) },
{ 0x0000, LIT64( 0x0000000000000000 ) },
{ 0x75A8, LIT64( 0xE59591E4788957A5 ) },
{ 0x3FFF, LIT64( 0xFFF0000000000040 ) },
{ 0x0CD8, LIT64( 0xFC000000000007FE ) },
{ 0x43BA, LIT64( 0x99A4000000000000 ) },
{ 0x3FFF, LIT64( 0x8000000000000000 ) },
{ 0x4081, LIT64( 0x94FBF1BCEB5545F0 ) },
{ 0x403E, LIT64( 0xFFF0000000002000 ) },
{ 0x3FFE, LIT64( 0xC860E3C75D224F28 ) },
{ 0x407E, LIT64( 0xFC00000FFFFFFFFE ) },
{ 0x737A, LIT64( 0x800000007FFDFFFE ) },
{ 0x4044, LIT64( 0xFFFFFF80000FFFFF ) },
{ 0x3BFE, LIT64( 0x8000040000001FFE ) },
{ 0x4002, LIT64( 0xFF80000000000020 ) },
{ 0x5E8D, LIT64( 0xFFFFFFFFFFE00004 ) },
{ 0x4004, LIT64( 0x8000000000003FFB ) },
{ 0x407F, LIT64( 0x800000000003FFFE ) },
{ 0x4000, LIT64( 0xA459EE6A5C16CA55 ) },
{ 0x0003, LIT64( 0xC42CBF7399AEEB94 ) },
{ 0x3F7F, LIT64( 0xF800000000000006 ) },
{ 0x407F, LIT64( 0xBF56BE8871F28FEA ) },
{ 0x407E, LIT64( 0xFFFF77FFFFFFFFFE ) },
{ 0x2DC9, LIT64( 0x8000000FFFFFFFDE ) },
{ 0x4001, LIT64( 0xEFF7FFFFFFFFFFFF ) },
{ 0x4001, LIT64( 0xBE84F30125C497A6 ) },
{ 0x406B, LIT64( 0xEFFFFFFFFFFFFFFF ) },
{ 0x4080, LIT64( 0xFFFFFFFFBFFFFFFF ) },
{ 0x07E9, LIT64( 0x81FFFFFFFFFFFBFF ) },
{ 0x263F, LIT64( 0x801FFFFFFEFFFFFE ) },
{ 0x403C, LIT64( 0x801FFFFFFFF7FFFF ) },
{ 0x4018, LIT64( 0x8000000000080003 ) }
};
static void time_az_floatx80_pos( floatx80 function( floatx80 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
floatx80 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_floatx80_pos[ inputNum ].low;
a.high = inputs_floatx80_pos[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_floatx80_pos[ inputNum ].low;
a.high = inputs_floatx80_pos[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_floatx80 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
#ifdef FLOAT128
enum {
numInputs_float128 = 32
};
static const struct {
bits64 high, low;
} inputs_float128[ numInputs_float128 ] = {
{ LIT64( 0x3FDA200000100000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x3FFF000000000000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x85F14776190C8306 ), LIT64( 0xD8715F4E3D54BB92 ) },
{ LIT64( 0xF2B00000007FFFFF ), LIT64( 0xFFFFFFFFFFF7FFFF ) },
{ LIT64( 0x8000000000000000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0xBFFFFFFFFFE00000 ), LIT64( 0x0000008000000000 ) },
{ LIT64( 0x407F1719CE722F3E ), LIT64( 0xDA6B3FE5FF29425B ) },
{ LIT64( 0x43FFFF8000000000 ), LIT64( 0x0000000000400000 ) },
{ LIT64( 0x401E000000000100 ), LIT64( 0x0000000000002000 ) },
{ LIT64( 0x3FFED71DACDA8E47 ), LIT64( 0x4860E3C75D224F28 ) },
{ LIT64( 0xBF7ECFC1E90647D1 ), LIT64( 0x7A124FE55623EE44 ) },
{ LIT64( 0x0DF7007FFFFFFFFF ), LIT64( 0xFFFFFFFFEFFFFFFF ) },
{ LIT64( 0x3FE5FFEFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFEFFF ) },
{ LIT64( 0x403FFFFFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFFBFE ) },
{ LIT64( 0xBFFB2FBF7399AFEB ), LIT64( 0xA459EE6A5C16CA55 ) },
{ LIT64( 0xBDB8FFFFFFFFFFFC ), LIT64( 0x0000000000000400 ) },
{ LIT64( 0x3FC8FFDFFFFFFFFF ), LIT64( 0xFFFFFFFFF0000000 ) },
{ LIT64( 0x3FFBFFFFFFDFFFFF ), LIT64( 0xFFF8000000000000 ) },
{ LIT64( 0x407043C11737BE84 ), LIT64( 0xDDD58212ADC937F4 ) },
{ LIT64( 0x8001000000000000 ), LIT64( 0x0000001000000001 ) },
{ LIT64( 0xC036FFFFFFFFFFFF ), LIT64( 0xFE40000000000000 ) },
{ LIT64( 0x4002FFFFFE000002 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x4000C3FEDE897773 ), LIT64( 0x326AC4FD8EFBE6DC ) },
{ LIT64( 0xBFFF0000000FFFFF ), LIT64( 0xFFFFFE0000000000 ) },
{ LIT64( 0x62C3E502146E426D ), LIT64( 0x43F3CAA0DC7DF1A0 ) },
{ LIT64( 0xB5CBD32E52BB570E ), LIT64( 0xBCC477CB11C6236C ) },
{ LIT64( 0xE228FFFFFFC00000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x3F80000000000000 ), LIT64( 0x0000000080000008 ) },
{ LIT64( 0xC1AFFFDFFFFFFFFF ), LIT64( 0xFFFC000000000000 ) },
{ LIT64( 0xC96F000000000000 ), LIT64( 0x00000001FFFBFFFF ) },
{ LIT64( 0x3DE09BFE7923A338 ), LIT64( 0xBCC8FBBD7CEC1F4F ) },
{ LIT64( 0x401CFFFFFFFFFFFF ), LIT64( 0xFFFFFFFEFFFFFF80 ) }
};
static void time_a_float128_z_int32( int32 function( float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
float128 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_float128_z_int64( int64 function( float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
float128 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_float128_z_float32( float32 function( float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
float128 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_a_float128_z_float64( float64 function( float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
float128 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#ifdef FLOATX80
static void time_a_float128_z_floatx80( floatx80 function( float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
float128 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
static void time_az_float128( float128 function( float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
float128 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNum ].low;
a.high = inputs_float128[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_ab_float128_z_flag( flag function( float128, float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
float128 a, b;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNumA ].low;
a.high = inputs_float128[ inputNumA ].high;
b.low = inputs_float128[ inputNumB ].low;
b.high = inputs_float128[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNumA ].low;
a.high = inputs_float128[ inputNumA ].high;
b.low = inputs_float128[ inputNumB ].low;
b.high = inputs_float128[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static void time_abz_float128( float128 function( float128, float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNumA, inputNumB;
float128 a, b;
count = 0;
inputNumA = 0;
inputNumB = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128[ inputNumA ].low;
a.high = inputs_float128[ inputNumA ].high;
b.low = inputs_float128[ inputNumB ].low;
b.high = inputs_float128[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNumA = 0;
inputNumB = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128[ inputNumA ].low;
a.high = inputs_float128[ inputNumA ].high;
b.low = inputs_float128[ inputNumB ].low;
b.high = inputs_float128[ inputNumB ].high;
function( a, b );
inputNumA = ( inputNumA + 1 ) & ( numInputs_float128 - 1 );
if ( inputNumA == 0 ) ++inputNumB;
inputNumB = ( inputNumB + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
static const struct {
bits64 high, low;
} inputs_float128_pos[ numInputs_float128 ] = {
{ LIT64( 0x3FDA200000100000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x3FFF000000000000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x05F14776190C8306 ), LIT64( 0xD8715F4E3D54BB92 ) },
{ LIT64( 0x72B00000007FFFFF ), LIT64( 0xFFFFFFFFFFF7FFFF ) },
{ LIT64( 0x0000000000000000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x3FFFFFFFFFE00000 ), LIT64( 0x0000008000000000 ) },
{ LIT64( 0x407F1719CE722F3E ), LIT64( 0xDA6B3FE5FF29425B ) },
{ LIT64( 0x43FFFF8000000000 ), LIT64( 0x0000000000400000 ) },
{ LIT64( 0x401E000000000100 ), LIT64( 0x0000000000002000 ) },
{ LIT64( 0x3FFED71DACDA8E47 ), LIT64( 0x4860E3C75D224F28 ) },
{ LIT64( 0x3F7ECFC1E90647D1 ), LIT64( 0x7A124FE55623EE44 ) },
{ LIT64( 0x0DF7007FFFFFFFFF ), LIT64( 0xFFFFFFFFEFFFFFFF ) },
{ LIT64( 0x3FE5FFEFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFEFFF ) },
{ LIT64( 0x403FFFFFFFFFFFFF ), LIT64( 0xFFFFFFFFFFFFFBFE ) },
{ LIT64( 0x3FFB2FBF7399AFEB ), LIT64( 0xA459EE6A5C16CA55 ) },
{ LIT64( 0x3DB8FFFFFFFFFFFC ), LIT64( 0x0000000000000400 ) },
{ LIT64( 0x3FC8FFDFFFFFFFFF ), LIT64( 0xFFFFFFFFF0000000 ) },
{ LIT64( 0x3FFBFFFFFFDFFFFF ), LIT64( 0xFFF8000000000000 ) },
{ LIT64( 0x407043C11737BE84 ), LIT64( 0xDDD58212ADC937F4 ) },
{ LIT64( 0x0001000000000000 ), LIT64( 0x0000001000000001 ) },
{ LIT64( 0x4036FFFFFFFFFFFF ), LIT64( 0xFE40000000000000 ) },
{ LIT64( 0x4002FFFFFE000002 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x4000C3FEDE897773 ), LIT64( 0x326AC4FD8EFBE6DC ) },
{ LIT64( 0x3FFF0000000FFFFF ), LIT64( 0xFFFFFE0000000000 ) },
{ LIT64( 0x62C3E502146E426D ), LIT64( 0x43F3CAA0DC7DF1A0 ) },
{ LIT64( 0x35CBD32E52BB570E ), LIT64( 0xBCC477CB11C6236C ) },
{ LIT64( 0x6228FFFFFFC00000 ), LIT64( 0x0000000000000000 ) },
{ LIT64( 0x3F80000000000000 ), LIT64( 0x0000000080000008 ) },
{ LIT64( 0x41AFFFDFFFFFFFFF ), LIT64( 0xFFFC000000000000 ) },
{ LIT64( 0x496F000000000000 ), LIT64( 0x00000001FFFBFFFF ) },
{ LIT64( 0x3DE09BFE7923A338 ), LIT64( 0xBCC8FBBD7CEC1F4F ) },
{ LIT64( 0x401CFFFFFFFFFFFF ), LIT64( 0xFFFFFFFEFFFFFF80 ) }
};
static void time_az_float128_pos( float128 function( float128 ) )
{
clock_t startClock, endClock;
int32 count, i;
int8 inputNum;
float128 a;
count = 0;
inputNum = 0;
startClock = clock();
do {
for ( i = minIterations; i; --i ) {
a.low = inputs_float128_pos[ inputNum ].low;
a.high = inputs_float128_pos[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
count += minIterations;
} while ( clock() - startClock < CLOCKS_PER_SEC );
inputNum = 0;
startClock = clock();
for ( i = count; i; --i ) {
a.low = inputs_float128_pos[ inputNum ].low;
a.high = inputs_float128_pos[ inputNum ].high;
function( a );
inputNum = ( inputNum + 1 ) & ( numInputs_float128 - 1 );
}
endClock = clock();
reportTime( count, endClock - startClock );
}
#endif
enum {
INT32_TO_FLOAT32 = 1,
INT32_TO_FLOAT64,
#ifdef FLOATX80
INT32_TO_FLOATX80,
#endif
#ifdef FLOAT128
INT32_TO_FLOAT128,
#endif
INT64_TO_FLOAT32,
INT64_TO_FLOAT64,
#ifdef FLOATX80
INT64_TO_FLOATX80,
#endif
#ifdef FLOAT128
INT64_TO_FLOAT128,
#endif
FLOAT32_TO_INT32,
FLOAT32_TO_INT32_ROUND_TO_ZERO,
FLOAT32_TO_INT64,
FLOAT32_TO_INT64_ROUND_TO_ZERO,
FLOAT32_TO_FLOAT64,
#ifdef FLOATX80
FLOAT32_TO_FLOATX80,
#endif
#ifdef FLOAT128
FLOAT32_TO_FLOAT128,
#endif
FLOAT32_ROUND_TO_INT,
FLOAT32_ADD,
FLOAT32_SUB,
FLOAT32_MUL,
FLOAT32_DIV,
FLOAT32_REM,
FLOAT32_SQRT,
FLOAT32_EQ,
FLOAT32_LE,
FLOAT32_LT,
FLOAT32_EQ_SIGNALING,
FLOAT32_LE_QUIET,
FLOAT32_LT_QUIET,
FLOAT64_TO_INT32,
FLOAT64_TO_INT32_ROUND_TO_ZERO,
FLOAT64_TO_INT64,
FLOAT64_TO_INT64_ROUND_TO_ZERO,
FLOAT64_TO_FLOAT32,
#ifdef FLOATX80
FLOAT64_TO_FLOATX80,
#endif
#ifdef FLOAT128
FLOAT64_TO_FLOAT128,
#endif
FLOAT64_ROUND_TO_INT,
FLOAT64_ADD,
FLOAT64_SUB,
FLOAT64_MUL,
FLOAT64_DIV,
FLOAT64_REM,
FLOAT64_SQRT,
FLOAT64_EQ,
FLOAT64_LE,
FLOAT64_LT,
FLOAT64_EQ_SIGNALING,
FLOAT64_LE_QUIET,
FLOAT64_LT_QUIET,
#ifdef FLOATX80
FLOATX80_TO_INT32,
FLOATX80_TO_INT32_ROUND_TO_ZERO,
FLOATX80_TO_INT64,
FLOATX80_TO_INT64_ROUND_TO_ZERO,
FLOATX80_TO_FLOAT32,
FLOATX80_TO_FLOAT64,
#ifdef FLOAT128
FLOATX80_TO_FLOAT128,
#endif
FLOATX80_ROUND_TO_INT,
FLOATX80_ADD,
FLOATX80_SUB,
FLOATX80_MUL,
FLOATX80_DIV,
FLOATX80_REM,
FLOATX80_SQRT,
FLOATX80_EQ,
FLOATX80_LE,
FLOATX80_LT,
FLOATX80_EQ_SIGNALING,
FLOATX80_LE_QUIET,
FLOATX80_LT_QUIET,
#endif
#ifdef FLOAT128
FLOAT128_TO_INT32,
FLOAT128_TO_INT32_ROUND_TO_ZERO,
FLOAT128_TO_INT64,
FLOAT128_TO_INT64_ROUND_TO_ZERO,
FLOAT128_TO_FLOAT32,
FLOAT128_TO_FLOAT64,
#ifdef FLOATX80
FLOAT128_TO_FLOATX80,
#endif
FLOAT128_ROUND_TO_INT,
FLOAT128_ADD,
FLOAT128_SUB,
FLOAT128_MUL,
FLOAT128_DIV,
FLOAT128_REM,
FLOAT128_SQRT,
FLOAT128_EQ,
FLOAT128_LE,
FLOAT128_LT,
FLOAT128_EQ_SIGNALING,
FLOAT128_LE_QUIET,
FLOAT128_LT_QUIET,
#endif
NUM_FUNCTIONS
};
static struct {
char *name;
int8 numInputs;
flag roundingPrecision, roundingMode;
flag tininessMode, tininessModeAtReducedPrecision;
} functions[ NUM_FUNCTIONS ] = {
{ 0, 0, 0, 0, 0, 0 },
{ "int32_to_float32", 1, FALSE, TRUE, FALSE, FALSE },
{ "int32_to_float64", 1, FALSE, FALSE, FALSE, FALSE },
#ifdef FLOATX80
{ "int32_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
#endif
#ifdef FLOAT128
{ "int32_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
#endif
{ "int64_to_float32", 1, FALSE, TRUE, FALSE, FALSE },
{ "int64_to_float64", 1, FALSE, TRUE, FALSE, FALSE },
#ifdef FLOATX80
{ "int64_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
#endif
#ifdef FLOAT128
{ "int64_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
#endif
{ "float32_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
{ "float32_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "float32_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
{ "float32_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "float32_to_float64", 1, FALSE, FALSE, FALSE, FALSE },
#ifdef FLOATX80
{ "float32_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
#endif
#ifdef FLOAT128
{ "float32_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
#endif
{ "float32_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
{ "float32_add", 2, FALSE, TRUE, FALSE, FALSE },
{ "float32_sub", 2, FALSE, TRUE, FALSE, FALSE },
{ "float32_mul", 2, FALSE, TRUE, TRUE, FALSE },
{ "float32_div", 2, FALSE, TRUE, FALSE, FALSE },
{ "float32_rem", 2, FALSE, FALSE, FALSE, FALSE },
{ "float32_sqrt", 1, FALSE, TRUE, FALSE, FALSE },
{ "float32_eq", 2, FALSE, FALSE, FALSE, FALSE },
{ "float32_le", 2, FALSE, FALSE, FALSE, FALSE },
{ "float32_lt", 2, FALSE, FALSE, FALSE, FALSE },
{ "float32_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
{ "float32_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
{ "float32_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
{ "float64_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
{ "float64_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "float64_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
{ "float64_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "float64_to_float32", 1, FALSE, TRUE, TRUE, FALSE },
#ifdef FLOATX80
{ "float64_to_floatx80", 1, FALSE, FALSE, FALSE, FALSE },
#endif
#ifdef FLOAT128
{ "float64_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
#endif
{ "float64_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
{ "float64_add", 2, FALSE, TRUE, FALSE, FALSE },
{ "float64_sub", 2, FALSE, TRUE, FALSE, FALSE },
{ "float64_mul", 2, FALSE, TRUE, TRUE, FALSE },
{ "float64_div", 2, FALSE, TRUE, FALSE, FALSE },
{ "float64_rem", 2, FALSE, FALSE, FALSE, FALSE },
{ "float64_sqrt", 1, FALSE, TRUE, FALSE, FALSE },
{ "float64_eq", 2, FALSE, FALSE, FALSE, FALSE },
{ "float64_le", 2, FALSE, FALSE, FALSE, FALSE },
{ "float64_lt", 2, FALSE, FALSE, FALSE, FALSE },
{ "float64_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
{ "float64_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
{ "float64_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
#ifdef FLOATX80
{ "floatx80_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
{ "floatx80_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
{ "floatx80_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_to_float32", 1, FALSE, TRUE, TRUE, FALSE },
{ "floatx80_to_float64", 1, FALSE, TRUE, TRUE, FALSE },
#ifdef FLOAT128
{ "floatx80_to_float128", 1, FALSE, FALSE, FALSE, FALSE },
#endif
{ "floatx80_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
{ "floatx80_add", 2, TRUE, TRUE, FALSE, TRUE },
{ "floatx80_sub", 2, TRUE, TRUE, FALSE, TRUE },
{ "floatx80_mul", 2, TRUE, TRUE, TRUE, TRUE },
{ "floatx80_div", 2, TRUE, TRUE, FALSE, TRUE },
{ "floatx80_rem", 2, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_sqrt", 1, TRUE, TRUE, FALSE, FALSE },
{ "floatx80_eq", 2, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_le", 2, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_lt", 2, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
{ "floatx80_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
#endif
#ifdef FLOAT128
{ "float128_to_int32", 1, FALSE, TRUE, FALSE, FALSE },
{ "float128_to_int32_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "float128_to_int64", 1, FALSE, TRUE, FALSE, FALSE },
{ "float128_to_int64_round_to_zero", 1, FALSE, FALSE, FALSE, FALSE },
{ "float128_to_float32", 1, FALSE, TRUE, TRUE, FALSE },
{ "float128_to_float64", 1, FALSE, TRUE, TRUE, FALSE },
#ifdef FLOATX80
{ "float128_to_floatx80", 1, FALSE, TRUE, TRUE, FALSE },
#endif
{ "float128_round_to_int", 1, FALSE, TRUE, FALSE, FALSE },
{ "float128_add", 2, FALSE, TRUE, FALSE, FALSE },
{ "float128_sub", 2, FALSE, TRUE, FALSE, FALSE },
{ "float128_mul", 2, FALSE, TRUE, TRUE, FALSE },
{ "float128_div", 2, FALSE, TRUE, FALSE, FALSE },
{ "float128_rem", 2, FALSE, FALSE, FALSE, FALSE },
{ "float128_sqrt", 1, FALSE, TRUE, FALSE, FALSE },
{ "float128_eq", 2, FALSE, FALSE, FALSE, FALSE },
{ "float128_le", 2, FALSE, FALSE, FALSE, FALSE },
{ "float128_lt", 2, FALSE, FALSE, FALSE, FALSE },
{ "float128_eq_signaling", 2, FALSE, FALSE, FALSE, FALSE },
{ "float128_le_quiet", 2, FALSE, FALSE, FALSE, FALSE },
{ "float128_lt_quiet", 2, FALSE, FALSE, FALSE, FALSE },
#endif
};
enum {
ROUND_NEAREST_EVEN = 1,
ROUND_TO_ZERO,
ROUND_DOWN,
ROUND_UP,
NUM_ROUNDINGMODES
};
enum {
TININESS_BEFORE_ROUNDING = 1,
TININESS_AFTER_ROUNDING,
NUM_TININESSMODES
};
static void
timeFunctionVariety(
uint8 functionCode,
int8 roundingPrecision,
int8 roundingMode,
int8 tininessMode
)
{
uint8 roundingCode;
int8 tininessCode;
functionName = functions[ functionCode ].name;
if ( roundingPrecision == 32 ) {
roundingPrecisionName = "32";
}
else if ( roundingPrecision == 64 ) {
roundingPrecisionName = "64";
}
else if ( roundingPrecision == 80 ) {
roundingPrecisionName = "80";
}
else {
roundingPrecisionName = NULL;
}
#ifdef FLOATX80
floatx80_rounding_precision = roundingPrecision;
#endif
switch ( roundingMode ) {
case 0:
roundingModeName = NULL;
roundingCode = float_round_nearest_even;
break;
case ROUND_NEAREST_EVEN:
roundingModeName = "nearest_even";
roundingCode = float_round_nearest_even;
break;
case ROUND_TO_ZERO:
roundingModeName = "to_zero";
roundingCode = float_round_to_zero;
break;
case ROUND_DOWN:
roundingModeName = "down";
roundingCode = float_round_down;
break;
case ROUND_UP:
roundingModeName = "up";
roundingCode = float_round_up;
break;
}
float_rounding_mode = roundingCode;
switch ( tininessMode ) {
case 0:
tininessModeName = NULL;
tininessCode = float_tininess_after_rounding;
break;
case TININESS_BEFORE_ROUNDING:
tininessModeName = "before";
tininessCode = float_tininess_before_rounding;
break;
case TININESS_AFTER_ROUNDING:
tininessModeName = "after";
tininessCode = float_tininess_after_rounding;
break;
}
float_detect_tininess = tininessCode;
switch ( functionCode ) {
case INT32_TO_FLOAT32:
time_a_int32_z_float32( int32_to_float32 );
break;
case INT32_TO_FLOAT64:
time_a_int32_z_float64( int32_to_float64 );
break;
#ifdef FLOATX80
case INT32_TO_FLOATX80:
time_a_int32_z_floatx80( int32_to_floatx80 );
break;
#endif
#ifdef FLOAT128
case INT32_TO_FLOAT128:
time_a_int32_z_float128( int32_to_float128 );
break;
#endif
case INT64_TO_FLOAT32:
time_a_int64_z_float32( int64_to_float32 );
break;
case INT64_TO_FLOAT64:
time_a_int64_z_float64( int64_to_float64 );
break;
#ifdef FLOATX80
case INT64_TO_FLOATX80:
time_a_int64_z_floatx80( int64_to_floatx80 );
break;
#endif
#ifdef FLOAT128
case INT64_TO_FLOAT128:
time_a_int64_z_float128( int64_to_float128 );
break;
#endif
case FLOAT32_TO_INT32:
time_a_float32_z_int32( float32_to_int32 );
break;
case FLOAT32_TO_INT32_ROUND_TO_ZERO:
time_a_float32_z_int32( float32_to_int32_round_to_zero );
break;
case FLOAT32_TO_INT64:
time_a_float32_z_int64( float32_to_int64 );
break;
case FLOAT32_TO_INT64_ROUND_TO_ZERO:
time_a_float32_z_int64( float32_to_int64_round_to_zero );
break;
case FLOAT32_TO_FLOAT64:
time_a_float32_z_float64( float32_to_float64 );
break;
#ifdef FLOATX80
case FLOAT32_TO_FLOATX80:
time_a_float32_z_floatx80( float32_to_floatx80 );
break;
#endif
#ifdef FLOAT128
case FLOAT32_TO_FLOAT128:
time_a_float32_z_float128( float32_to_float128 );
break;
#endif
case FLOAT32_ROUND_TO_INT:
time_az_float32( float32_round_to_int );
break;
case FLOAT32_ADD:
time_abz_float32( float32_add );
break;
case FLOAT32_SUB:
time_abz_float32( float32_sub );
break;
case FLOAT32_MUL:
time_abz_float32( float32_mul );
break;
case FLOAT32_DIV:
time_abz_float32( float32_div );
break;
case FLOAT32_REM:
time_abz_float32( float32_rem );
break;
case FLOAT32_SQRT:
time_az_float32_pos( float32_sqrt );
break;
case FLOAT32_EQ:
time_ab_float32_z_flag( float32_eq );
break;
case FLOAT32_LE:
time_ab_float32_z_flag( float32_le );
break;
case FLOAT32_LT:
time_ab_float32_z_flag( float32_lt );
break;
case FLOAT32_EQ_SIGNALING:
time_ab_float32_z_flag( float32_eq_signaling );
break;
case FLOAT32_LE_QUIET:
time_ab_float32_z_flag( float32_le_quiet );
break;
case FLOAT32_LT_QUIET:
time_ab_float32_z_flag( float32_lt_quiet );
break;
case FLOAT64_TO_INT32:
time_a_float64_z_int32( float64_to_int32 );
break;
case FLOAT64_TO_INT32_ROUND_TO_ZERO:
time_a_float64_z_int32( float64_to_int32_round_to_zero );
break;
case FLOAT64_TO_INT64:
time_a_float64_z_int64( float64_to_int64 );
break;
case FLOAT64_TO_INT64_ROUND_TO_ZERO:
time_a_float64_z_int64( float64_to_int64_round_to_zero );
break;
case FLOAT64_TO_FLOAT32:
time_a_float64_z_float32( float64_to_float32 );
break;
#ifdef FLOATX80
case FLOAT64_TO_FLOATX80:
time_a_float64_z_floatx80( float64_to_floatx80 );
break;
#endif
#ifdef FLOAT128
case FLOAT64_TO_FLOAT128:
time_a_float64_z_float128( float64_to_float128 );
break;
#endif
case FLOAT64_ROUND_TO_INT:
time_az_float64( float64_round_to_int );
break;
case FLOAT64_ADD:
time_abz_float64( float64_add );
break;
case FLOAT64_SUB:
time_abz_float64( float64_sub );
break;
case FLOAT64_MUL:
time_abz_float64( float64_mul );
break;
case FLOAT64_DIV:
time_abz_float64( float64_div );
break;
case FLOAT64_REM:
time_abz_float64( float64_rem );
break;
case FLOAT64_SQRT:
time_az_float64_pos( float64_sqrt );
break;
case FLOAT64_EQ:
time_ab_float64_z_flag( float64_eq );
break;
case FLOAT64_LE:
time_ab_float64_z_flag( float64_le );
break;
case FLOAT64_LT:
time_ab_float64_z_flag( float64_lt );
break;
case FLOAT64_EQ_SIGNALING:
time_ab_float64_z_flag( float64_eq_signaling );
break;
case FLOAT64_LE_QUIET:
time_ab_float64_z_flag( float64_le_quiet );
break;
case FLOAT64_LT_QUIET:
time_ab_float64_z_flag( float64_lt_quiet );
break;
#ifdef FLOATX80
case FLOATX80_TO_INT32:
time_a_floatx80_z_int32( floatx80_to_int32 );
break;
case FLOATX80_TO_INT32_ROUND_TO_ZERO:
time_a_floatx80_z_int32( floatx80_to_int32_round_to_zero );
break;
case FLOATX80_TO_INT64:
time_a_floatx80_z_int64( floatx80_to_int64 );
break;
case FLOATX80_TO_INT64_ROUND_TO_ZERO:
time_a_floatx80_z_int64( floatx80_to_int64_round_to_zero );
break;
case FLOATX80_TO_FLOAT32:
time_a_floatx80_z_float32( floatx80_to_float32 );
break;
case FLOATX80_TO_FLOAT64:
time_a_floatx80_z_float64( floatx80_to_float64 );
break;
#ifdef FLOAT128
case FLOATX80_TO_FLOAT128:
time_a_floatx80_z_float128( floatx80_to_float128 );
break;
#endif
case FLOATX80_ROUND_TO_INT:
time_az_floatx80( floatx80_round_to_int );
break;
case FLOATX80_ADD:
time_abz_floatx80( floatx80_add );
break;
case FLOATX80_SUB:
time_abz_floatx80( floatx80_sub );
break;
case FLOATX80_MUL:
time_abz_floatx80( floatx80_mul );
break;
case FLOATX80_DIV:
time_abz_floatx80( floatx80_div );
break;
case FLOATX80_REM:
time_abz_floatx80( floatx80_rem );
break;
case FLOATX80_SQRT:
time_az_floatx80_pos( floatx80_sqrt );
break;
case FLOATX80_EQ:
time_ab_floatx80_z_flag( floatx80_eq );
break;
case FLOATX80_LE:
time_ab_floatx80_z_flag( floatx80_le );
break;
case FLOATX80_LT:
time_ab_floatx80_z_flag( floatx80_lt );
break;
case FLOATX80_EQ_SIGNALING:
time_ab_floatx80_z_flag( floatx80_eq_signaling );
break;
case FLOATX80_LE_QUIET:
time_ab_floatx80_z_flag( floatx80_le_quiet );
break;
case FLOATX80_LT_QUIET:
time_ab_floatx80_z_flag( floatx80_lt_quiet );
break;
#endif
#ifdef FLOAT128
case FLOAT128_TO_INT32:
time_a_float128_z_int32( float128_to_int32 );
break;
case FLOAT128_TO_INT32_ROUND_TO_ZERO:
time_a_float128_z_int32( float128_to_int32_round_to_zero );
break;
case FLOAT128_TO_INT64:
time_a_float128_z_int64( float128_to_int64 );
break;
case FLOAT128_TO_INT64_ROUND_TO_ZERO:
time_a_float128_z_int64( float128_to_int64_round_to_zero );
break;
case FLOAT128_TO_FLOAT32:
time_a_float128_z_float32( float128_to_float32 );
break;
case FLOAT128_TO_FLOAT64:
time_a_float128_z_float64( float128_to_float64 );
break;
#ifdef FLOATX80
case FLOAT128_TO_FLOATX80:
time_a_float128_z_floatx80( float128_to_floatx80 );
break;
#endif
case FLOAT128_ROUND_TO_INT:
time_az_float128( float128_round_to_int );
break;
case FLOAT128_ADD:
time_abz_float128( float128_add );
break;
case FLOAT128_SUB:
time_abz_float128( float128_sub );
break;
case FLOAT128_MUL:
time_abz_float128( float128_mul );
break;
case FLOAT128_DIV:
time_abz_float128( float128_div );
break;
case FLOAT128_REM:
time_abz_float128( float128_rem );
break;
case FLOAT128_SQRT:
time_az_float128_pos( float128_sqrt );
break;
case FLOAT128_EQ:
time_ab_float128_z_flag( float128_eq );
break;
case FLOAT128_LE:
time_ab_float128_z_flag( float128_le );
break;
case FLOAT128_LT:
time_ab_float128_z_flag( float128_lt );
break;
case FLOAT128_EQ_SIGNALING:
time_ab_float128_z_flag( float128_eq_signaling );
break;
case FLOAT128_LE_QUIET:
time_ab_float128_z_flag( float128_le_quiet );
break;
case FLOAT128_LT_QUIET:
time_ab_float128_z_flag( float128_lt_quiet );
break;
#endif
}
}
static void
timeFunction(
uint8 functionCode,
int8 roundingPrecisionIn,
int8 roundingModeIn,
int8 tininessModeIn
)
{
int8 roundingPrecision, roundingMode, tininessMode;
roundingPrecision = 32;
for (;;) {
if ( ! functions[ functionCode ].roundingPrecision ) {
roundingPrecision = 0;
}
else if ( roundingPrecisionIn ) {
roundingPrecision = roundingPrecisionIn;
}
for ( roundingMode = 1;
roundingMode < NUM_ROUNDINGMODES;
++roundingMode
) {
if ( ! functions[ functionCode ].roundingMode ) {
roundingMode = 0;
}
else if ( roundingModeIn ) {
roundingMode = roundingModeIn;
}
for ( tininessMode = 1;
tininessMode < NUM_TININESSMODES;
++tininessMode
) {
if ( ( roundingPrecision == 32 )
|| ( roundingPrecision == 64 ) ) {
if ( ! functions[ functionCode ]
.tininessModeAtReducedPrecision
) {
tininessMode = 0;
}
else if ( tininessModeIn ) {
tininessMode = tininessModeIn;
}
}
else {
if ( ! functions[ functionCode ].tininessMode ) {
tininessMode = 0;
}
else if ( tininessModeIn ) {
tininessMode = tininessModeIn;
}
}
timeFunctionVariety(
functionCode, roundingPrecision, roundingMode, tininessMode
);
if ( tininessModeIn || ! tininessMode ) break;
}
if ( roundingModeIn || ! roundingMode ) break;
}
if ( roundingPrecisionIn || ! roundingPrecision ) break;
if ( roundingPrecision == 80 ) {
break;
}
else if ( roundingPrecision == 64 ) {
roundingPrecision = 80;
}
else if ( roundingPrecision == 32 ) {
roundingPrecision = 64;
}
}
}
main( int argc, char **argv )
{
char *argPtr;
flag functionArgument;
uint8 functionCode;
int8 operands, roundingPrecision, roundingMode, tininessMode;
if ( argc <= 1 ) goto writeHelpMessage;
functionArgument = FALSE;
functionCode = 0;
operands = 0;
roundingPrecision = 0;
roundingMode = 0;
tininessMode = 0;
--argc;
++argv;
while ( argc && ( argPtr = argv[ 0 ] ) ) {
if ( argPtr[ 0 ] == '-' ) ++argPtr;
if ( strcmp( argPtr, "help" ) == 0 ) {
writeHelpMessage:
fputs(
"timesoftfloat [<option>...] <function>\n"
" <option>: (* is default)\n"
" -help --Write this message and exit.\n"
#ifdef FLOATX80
" -precision32 --Only time rounding precision equivalent to float32.\n"
" -precision64 --Only time rounding precision equivalent to float64.\n"
" -precision80 --Only time maximum rounding precision.\n"
#endif
" -nearesteven --Only time rounding to nearest/even.\n"
" -tozero --Only time rounding to zero.\n"
" -down --Only time rounding down.\n"
" -up --Only time rounding up.\n"
" -tininessbefore --Only time underflow tininess before rounding.\n"
" -tininessafter --Only time underflow tininess after rounding.\n"
" <function>:\n"
" int32_to_<float> <float>_add <float>_eq\n"
" <float>_to_int32 <float>_sub <float>_le\n"
" <float>_to_int32_round_to_zero <float>_mul <float>_lt\n"
" int64_to_<float> <float>_div <float>_eq_signaling\n"
" <float>_to_int64 <float>_rem <float>_le_quiet\n"
" <float>_to_int64_round_to_zero <float>_lt_quiet\n"
" <float>_to_<float>\n"
" <float>_round_to_int\n"
" <float>_sqrt\n"
" -all1 --All 1-operand functions.\n"
" -all2 --All 2-operand functions.\n"
" -all --All functions.\n"
" <float>:\n"
" float32 --Single precision.\n"
" float64 --Double precision.\n"
#ifdef FLOATX80
" floatx80 --Extended double precision.\n"
#endif
#ifdef FLOAT128
" float128 --Quadruple precision.\n"
#endif
,
stdout
);
return EXIT_SUCCESS;
}
#ifdef FLOATX80
else if ( strcmp( argPtr, "precision32" ) == 0 ) {
roundingPrecision = 32;
}
else if ( strcmp( argPtr, "precision64" ) == 0 ) {
roundingPrecision = 64;
}
else if ( strcmp( argPtr, "precision80" ) == 0 ) {
roundingPrecision = 80;
}
#endif
else if ( ( strcmp( argPtr, "nearesteven" ) == 0 )
|| ( strcmp( argPtr, "nearest_even" ) == 0 ) ) {
roundingMode = ROUND_NEAREST_EVEN;
}
else if ( ( strcmp( argPtr, "tozero" ) == 0 )
|| ( strcmp( argPtr, "to_zero" ) == 0 ) ) {
roundingMode = ROUND_TO_ZERO;
}
else if ( strcmp( argPtr, "down" ) == 0 ) {
roundingMode = ROUND_DOWN;
}
else if ( strcmp( argPtr, "up" ) == 0 ) {
roundingMode = ROUND_UP;
}
else if ( strcmp( argPtr, "tininessbefore" ) == 0 ) {
tininessMode = TININESS_BEFORE_ROUNDING;
}
else if ( strcmp( argPtr, "tininessafter" ) == 0 ) {
tininessMode = TININESS_AFTER_ROUNDING;
}
else if ( strcmp( argPtr, "all1" ) == 0 ) {
functionArgument = TRUE;
functionCode = 0;
operands = 1;
}
else if ( strcmp( argPtr, "all2" ) == 0 ) {
functionArgument = TRUE;
functionCode = 0;
operands = 2;
}
else if ( strcmp( argPtr, "all" ) == 0 ) {
functionArgument = TRUE;
functionCode = 0;
operands = 0;
}
else {
for ( functionCode = 1;
functionCode < NUM_FUNCTIONS;
++functionCode
) {
if ( strcmp( argPtr, functions[ functionCode ].name ) == 0 ) {
break;
}
}
if ( functionCode == NUM_FUNCTIONS ) {
fail( "Invalid option or function `%s'", argv[ 0 ] );
}
functionArgument = TRUE;
}
--argc;
++argv;
}
if ( ! functionArgument ) fail( "Function argument required" );
if ( functionCode ) {
timeFunction(
functionCode, roundingPrecision, roundingMode, tininessMode );
}
else if ( operands == 1 ) {
for ( functionCode = 1; functionCode < NUM_FUNCTIONS; ++functionCode
) {
if ( functions[ functionCode ].numInputs == 1 ) {
timeFunction(
functionCode, roundingPrecision, roundingMode, tininessMode
);
}
}
}
else if ( operands == 2 ) {
for ( functionCode = 1; functionCode < NUM_FUNCTIONS; ++functionCode
) {
if ( functions[ functionCode ].numInputs == 2 ) {
timeFunction(
functionCode, roundingPrecision, roundingMode, tininessMode
);
}
}
}
else {
for ( functionCode = 1; functionCode < NUM_FUNCTIONS; ++functionCode
) {
timeFunction(
functionCode, roundingPrecision, roundingMode, tininessMode );
}
}
return EXIT_SUCCESS;
}
diff --git a/lib/libc/softfloat/unorddf2.c b/lib/libc/softfloat/unorddf2.c
index 44e03792b3f9..7447b6a83de0 100644
--- a/lib/libc/softfloat/unorddf2.c
+++ b/lib/libc/softfloat/unorddf2.c
@@ -1,24 +1,23 @@
/* $NetBSD: unorddf2.c,v 1.1 2003/05/06 08:58:19 rearnsha Exp $ */
/*
* Written by Richard Earnshaw, 2003. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __unorddf2(float64, float64);
flag
__unorddf2(float64 a, float64 b)
{
/*
* The comparison is unordered if either input is a NaN.
* Test for this by comparing each operand with itself.
* We must perform both comparisons to correctly check for
* signalling NaNs.
*/
return 1 ^ (float64_eq(a, a) & float64_eq(b, b));
}
diff --git a/lib/libc/softfloat/unordsf2.c b/lib/libc/softfloat/unordsf2.c
index 3b73ac20ca80..9cc202f7e009 100644
--- a/lib/libc/softfloat/unordsf2.c
+++ b/lib/libc/softfloat/unordsf2.c
@@ -1,24 +1,23 @@
/* $NetBSD: unordsf2.c,v 1.1 2003/05/06 08:58:20 rearnsha Exp $ */
/*
* Written by Richard Earnshaw, 2003. This file is in the Public Domain.
*/
#include "softfloat-for-gcc.h"
#include "milieu.h"
#include "softfloat.h"
-#include <sys/cdefs.h>
flag __unordsf2(float32, float32);
flag
__unordsf2(float32 a, float32 b)
{
/*
* The comparison is unordered if either input is a NaN.
* Test for this by comparing each operand with itself.
* We must perform both comparisons to correctly check for
* signalling NaNs.
*/
return 1 ^ (float32_eq(a, a) & float32_eq(b, b));
}
diff --git a/lib/libc/stdio/_flock_stub.c b/lib/libc/stdio/_flock_stub.c
index 674e88c512bd..5f81f29ac232 100644
--- a/lib/libc/stdio/_flock_stub.c
+++ b/lib/libc/stdio/_flock_stub.c
@@ -1,139 +1,138 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* POSIX stdio FILE locking functions. These assume that the locking
* is only required at FILE structure level, not at file descriptor
* level too.
*
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "un-namespace.h"
#include "local.h"
/*
* Weak symbols for externally visible functions in this file:
*/
__weak_reference(_flockfile, flockfile);
__weak_reference(_flockfile_debug_stub, _flockfile_debug);
__weak_reference(_ftrylockfile, ftrylockfile);
__weak_reference(_funlockfile, funlockfile);
void _flockfile_debug_stub(FILE *, char *, int);
int _ftrylockfile(FILE *);
void
_flockfile(FILE *fp)
{
pthread_t curthread = _pthread_self();
if (fp->_fl_owner == curthread)
fp->_fl_count++;
else {
/*
* Make sure this mutex is treated as a private
* internal mutex:
*/
_pthread_mutex_lock(&fp->_fl_mutex);
fp->_fl_owner = curthread;
fp->_fl_count = 1;
}
}
/*
* This can be overriden by the threads library if it is linked in.
*/
void
_flockfile_debug_stub(FILE *fp, char *fname, int lineno)
{
_flockfile(fp);
}
int
_ftrylockfile(FILE *fp)
{
pthread_t curthread = _pthread_self();
int ret = 0;
if (fp->_fl_owner == curthread)
fp->_fl_count++;
/*
* Make sure this mutex is treated as a private
* internal mutex:
*/
else if (_pthread_mutex_trylock(&fp->_fl_mutex) == 0) {
fp->_fl_owner = curthread;
fp->_fl_count = 1;
}
else
ret = -1;
return (ret);
}
void
_funlockfile(FILE *fp)
{
pthread_t curthread = _pthread_self();
/*
* Check if this file is owned by the current thread:
*/
if (fp->_fl_owner == curthread) {
/*
* Check if this thread has locked the FILE
* more than once:
*/
if (fp->_fl_count > 1)
/*
* Decrement the count of the number of
* times the running thread has locked this
* file:
*/
fp->_fl_count--;
else {
/*
* The running thread will release the
* lock now:
*/
fp->_fl_count = 0;
fp->_fl_owner = NULL;
_pthread_mutex_unlock(&fp->_fl_mutex);
}
}
}
diff --git a/lib/libc/stdio/asprintf.c b/lib/libc/stdio/asprintf.c
index 123345490c43..f0e898c92c0c 100644
--- a/lib/libc/stdio/asprintf.c
+++ b/lib/libc/stdio/asprintf.c
@@ -1,67 +1,66 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdarg.h>
#include <xlocale.h>
int
asprintf(char ** __restrict s, char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vasprintf(s, fmt, ap);
va_end(ap);
return (ret);
}
int
asprintf_l(char ** __restrict s, locale_t locale, char const * __restrict fmt,
...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vasprintf_l(s, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/clrerr.c b/lib/libc/stdio/clrerr.c
index 780172ef3f6d..0f8a4892a2db 100644
--- a/lib/libc/stdio/clrerr.c
+++ b/lib/libc/stdio/clrerr.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)clrerr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#undef clearerr
#undef clearerr_unlocked
void
clearerr(FILE *fp)
{
FLOCKFILE(fp);
__sclearerr(fp);
FUNLOCKFILE(fp);
}
void
clearerr_unlocked(FILE *fp)
{
__sclearerr(fp);
}
diff --git a/lib/libc/stdio/dprintf.c b/lib/libc/stdio/dprintf.c
index 07e20f0709ef..9e976b37379f 100644
--- a/lib/libc/stdio/dprintf.c
+++ b/lib/libc/stdio/dprintf.c
@@ -1,45 +1,44 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdarg.h>
#include <stdio.h>
#include "un-namespace.h"
int
dprintf(int fd, const char * __restrict fmt, ...)
{
va_list ap;
int ret;
va_start(ap, fmt);
ret = vdprintf(fd, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/fclose.c b/lib/libc/stdio/fclose.c
index 7a925f1a1661..43dcf20ec89b 100644
--- a/lib/libc/stdio/fclose.c
+++ b/lib/libc/stdio/fclose.c
@@ -1,138 +1,137 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993 The Regents of the University of California.
* Copyright (c) 2013 Mariusz Zaborski <oshogbo@FreeBSD.org>
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fclose.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "un-namespace.h"
#include <spinlock.h>
#include "libc_private.h"
#include "local.h"
static int
cleanfile(FILE *fp, bool c)
{
int r;
r = fp->_flags & __SWR ? __sflush(fp) : 0;
if (c) {
if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0)
r = EOF;
}
if (fp->_flags & __SMBF)
free((char *)fp->_bf._base);
if (HASUB(fp))
FREEUB(fp);
if (HASLB(fp))
FREELB(fp);
fp->_file = -1;
fp->_r = fp->_w = 0; /* Mess up if reaccessed. */
/*
* Lock the spinlock used to protect __sglue list walk in
* __sfp(). The __sfp() uses fp->_flags == 0 test as an
* indication of the unused FILE.
*
* Taking the lock prevents possible compiler or processor
* reordering of the writes performed before the final _flags
* cleanup, making sure that we are done with the FILE before
* it is considered available.
*/
STDIO_THREAD_LOCK();
fp->_flags = 0; /* Release this FILE for reuse. */
STDIO_THREAD_UNLOCK();
return (r);
}
int
fdclose(FILE *fp, int *fdp)
{
int r, err;
if (fdp != NULL)
*fdp = -1;
if (fp->_flags == 0) { /* not open! */
errno = EBADF;
return (EOF);
}
FLOCKFILE_CANCELSAFE(fp);
r = 0;
if (fp->_close != __sclose) {
r = EOF;
errno = EOPNOTSUPP;
} else if (fp->_file < 0) {
r = EOF;
errno = EBADF;
}
if (r == EOF) {
err = errno;
(void)cleanfile(fp, true);
errno = err;
} else {
if (fdp != NULL)
*fdp = fp->_file;
r = cleanfile(fp, false);
}
FUNLOCKFILE_CANCELSAFE();
return (r);
}
int
fclose(FILE *fp)
{
int r;
if (fp->_flags == 0) { /* not open! */
errno = EBADF;
return (EOF);
}
FLOCKFILE_CANCELSAFE(fp);
r = cleanfile(fp, true);
FUNLOCKFILE_CANCELSAFE();
return (r);
}
diff --git a/lib/libc/stdio/fcloseall.c b/lib/libc/stdio/fcloseall.c
index 83dc8d697bf1..ae6bd151ca9c 100644
--- a/lib/libc/stdio/fcloseall.c
+++ b/lib/libc/stdio/fcloseall.c
@@ -1,39 +1,38 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2006 Daniel M. Eischen. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include "local.h"
__weak_reference(__fcloseall, fcloseall);
void
__fcloseall(void)
{
(void)_fwalk(fclose);
}
diff --git a/lib/libc/stdio/fdopen.c b/lib/libc/stdio/fdopen.c
index 7512e2d4dbba..a4f2ac5b699b 100644
--- a/lib/libc/stdio/fdopen.c
+++ b/lib/libc/stdio/fdopen.c
@@ -1,105 +1,104 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fdopen.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include "un-namespace.h"
#include "local.h"
FILE *
fdopen(int fd, const char *mode)
{
FILE *fp;
int flags, oflags, fdflags, tmp;
/*
* File descriptors are a full int, but _file is only a short.
* If we get a valid file descriptor that is greater than
* SHRT_MAX, then the fd will get sign-extended into an
* invalid file descriptor. Handle this case by failing the
* open.
*/
if (fd > SHRT_MAX) {
errno = EMFILE;
return (NULL);
}
if ((flags = __sflags(mode, &oflags)) == 0)
return (NULL);
/* Make sure the mode the user wants is a subset of the actual mode. */
if ((fdflags = _fcntl(fd, F_GETFL, 0)) < 0)
return (NULL);
/* Work around incorrect O_ACCMODE. */
tmp = fdflags & (O_ACCMODE | O_EXEC);
if (tmp != O_RDWR && (tmp != (oflags & O_ACCMODE))) {
errno = EINVAL;
return (NULL);
}
if ((fp = __sfp()) == NULL)
return (NULL);
if ((oflags & O_CLOEXEC) && _fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
fp->_flags = 0;
return (NULL);
}
fp->_flags = flags;
/*
* If opened for appending, but underlying descriptor does not have
* O_APPEND bit set, assert __SAPP so that __swrite() caller
* will _sseek() to the end before write.
*/
if (fdflags & O_APPEND)
fp->_flags2 |= __S2OAP;
else if (oflags & O_APPEND)
fp->_flags |= __SAPP;
fp->_file = fd;
fp->_cookie = fp;
fp->_read = __sread;
fp->_write = __swrite;
fp->_seek = __sseek;
fp->_close = __sclose;
return (fp);
}
diff --git a/lib/libc/stdio/feof.c b/lib/libc/stdio/feof.c
index f224e1d6d6ba..854a46c6211b 100644
--- a/lib/libc/stdio/feof.c
+++ b/lib/libc/stdio/feof.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)feof.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#undef feof
#undef feof_unlocked
int
feof(FILE *fp)
{
int ret;
FLOCKFILE(fp);
ret= __sfeof(fp);
FUNLOCKFILE(fp);
return (ret);
}
int
feof_unlocked(FILE *fp)
{
return (__sfeof(fp));
}
diff --git a/lib/libc/stdio/ferror.c b/lib/libc/stdio/ferror.c
index bf3b2deaf299..9c63fb111241 100644
--- a/lib/libc/stdio/ferror.c
+++ b/lib/libc/stdio/ferror.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ferror.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#undef ferror
#undef ferror_unlocked
int
ferror(FILE *fp)
{
int ret;
FLOCKFILE(fp);
ret = __sferror(fp);
FUNLOCKFILE(fp);
return (ret);
}
int
ferror_unlocked(FILE *fp)
{
return (__sferror(fp));
}
diff --git a/lib/libc/stdio/fflush.c b/lib/libc/stdio/fflush.c
index a7f9348def50..30bbd1371ff9 100644
--- a/lib/libc/stdio/fflush.c
+++ b/lib/libc/stdio/fflush.c
@@ -1,158 +1,157 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fflush.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
static int sflush_locked(FILE *);
/*
* Flush a single file, or (if fp is NULL) all files.
* MT-safe version
*/
int
fflush(FILE *fp)
{
int retval;
if (fp == NULL)
return (_fwalk(sflush_locked));
FLOCKFILE_CANCELSAFE(fp);
/*
* There is disagreement about the correct behaviour of fflush()
* when passed a file which is not open for writing. According to
* the ISO C standard, the behaviour is undefined.
* Under linux, such an fflush returns success and has no effect;
* under Windows, such an fflush is documented as behaving instead
* as fpurge().
* Given that applications may be written with the expectation of
* either of these two behaviours, the only safe (non-astonishing)
* option is to return EBADF and ask that applications be fixed.
* SUSv3 now requires that fflush() returns success on a read-only
* stream.
*
*/
if ((fp->_flags & (__SWR | __SRW)) == 0)
retval = 0;
else
retval = __sflush(fp);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
/*
* Flush a single file, or (if fp is NULL) all files.
* Non-MT-safe version
*/
int
__fflush(FILE *fp)
{
int retval;
if (fp == NULL)
return (_fwalk(sflush_locked));
if ((fp->_flags & (__SWR | __SRW)) == 0)
retval = 0;
else
retval = __sflush(fp);
return (retval);
}
__weak_reference(__fflush, fflush_unlocked);
int
__sflush(FILE *fp)
{
unsigned char *p, *old_p;
int n, t, old_w;
t = fp->_flags;
if ((t & __SWR) == 0)
return (0);
if ((p = fp->_bf._base) == NULL)
return (0);
n = fp->_p - p; /* write this much */
/*
* Set these immediately to avoid problems with longjmp and to allow
* exchange buffering (via setvbuf) in user write function.
*/
old_p = fp->_p;
fp->_p = p;
old_w = fp->_w;
fp->_w = t & (__SLBF|__SNBF) ? 0 : fp->_bf._size;
for (; n > 0; n -= t, p += t) {
t = _swrite(fp, (char *)p, n);
if (t <= 0) {
/* Reset _p and _w. */
if (p > fp->_p) {
/* Some was written. */
memmove(fp->_p, p, n);
fp->_p += n;
if ((fp->_flags & (__SLBF | __SNBF)) == 0)
fp->_w -= n;
/* conditional to handle setvbuf */
} else if (p == fp->_p && errno == EINTR) {
fp->_p = old_p;
fp->_w = old_w;
}
fp->_flags |= __SERR;
return (EOF);
}
}
return (0);
}
static int
sflush_locked(FILE *fp)
{
int ret;
FLOCKFILE_CANCELSAFE(fp);
ret = __sflush(fp);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
diff --git a/lib/libc/stdio/fgetc.c b/lib/libc/stdio/fgetc.c
index 2919fe31b826..685fc7194a13 100644
--- a/lib/libc/stdio/fgetc.c
+++ b/lib/libc/stdio/fgetc.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fgetc.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
int
fgetc(FILE *fp)
{
int retval;
FLOCKFILE_CANCELSAFE(fp);
/* Orientation set by __sgetc() when buffer is empty. */
/* ORIENT(fp, -1); */
retval = __sgetc(fp);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
diff --git a/lib/libc/stdio/fgetln.c b/lib/libc/stdio/fgetln.c
index a66919711050..8ae44f8af05c 100644
--- a/lib/libc/stdio/fgetln.c
+++ b/lib/libc/stdio/fgetln.c
@@ -1,164 +1,163 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fgetln.c 8.2 (Berkeley) 1/2/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
/*
* Expand the line buffer. Return -1 on error.
*/
int
__slbexpand(FILE *fp, size_t newsize)
{
void *p;
if (fp->_lb._size >= newsize)
return (0);
if (newsize > INT_MAX) {
errno = ENOMEM;
return (-1);
}
if ((p = realloc(fp->_lb._base, newsize)) == NULL)
return (-1);
fp->_lb._base = p;
fp->_lb._size = newsize;
return (0);
}
/*
* Get an input line. The returned pointer often (but not always)
* points into a stdio buffer. Fgetln does not alter the text of
* the returned line (which is thus not a C string because it will
* not necessarily end with '\0'), but does allow callers to modify
* it if they wish. Thus, we set __SMOD in case the caller does.
*/
char *
fgetln(FILE *fp, size_t *lenp)
{
unsigned char *p;
char *ret;
size_t len;
size_t off;
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, -1);
/* make sure there is input */
if (fp->_r <= 0 && __srefill(fp)) {
*lenp = 0;
ret = NULL;
goto end;
}
/* look for a newline in the input */
if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) != NULL) {
/*
* Found one. Flag buffer as modified to keep fseek from
* `optimising' a backward seek, in case the user stomps on
* the text.
*/
p++; /* advance over it */
ret = (char *)fp->_p;
*lenp = len = p - fp->_p;
fp->_flags |= __SMOD;
fp->_r -= len;
fp->_p = p;
goto end;
}
/*
* We have to copy the current buffered data to the line buffer.
* As a bonus, though, we can leave off the __SMOD.
*
* OPTIMISTIC is length that we (optimistically) expect will
* accommodate the `rest' of the string, on each trip through the
* loop below.
*/
#define OPTIMISTIC 80
for (len = fp->_r, off = 0;; len += fp->_r) {
size_t diff;
/*
* Make sure there is room for more bytes. Copy data from
* file buffer to line buffer, refill file and look for
* newline. The loop stops only when we find a newline.
*/
if (__slbexpand(fp, len + OPTIMISTIC))
goto error;
(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
len - off);
off = len;
if (__srefill(fp)) {
if (__sfeof(fp))
break;
goto error;
}
if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) == NULL)
continue;
/* got it: finish up the line (like code above) */
p++;
diff = p - fp->_p;
len += diff;
if (__slbexpand(fp, len))
goto error;
(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
diff);
fp->_r -= diff;
fp->_p = p;
break;
}
*lenp = len;
ret = (char *)fp->_lb._base;
end:
FUNLOCKFILE_CANCELSAFE();
return (ret);
error:
*lenp = 0; /* ??? */
fp->_flags |= __SERR;
ret = NULL;
goto end;
}
diff --git a/lib/libc/stdio/fgetpos.c b/lib/libc/stdio/fgetpos.c
index 4cbd5e1f6e76..c6c119869c95 100644
--- a/lib/libc/stdio/fgetpos.c
+++ b/lib/libc/stdio/fgetpos.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fgetpos.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
int
fgetpos(FILE * __restrict fp, fpos_t * __restrict pos)
{
/*
* ftello is thread-safe; no need to lock fp.
*/
if ((*pos = ftello(fp)) == (fpos_t)-1)
return (-1);
else
return (0);
}
diff --git a/lib/libc/stdio/fgets.c b/lib/libc/stdio/fgets.c
index adac5dc3d6a0..dc74b25bafb3 100644
--- a/lib/libc/stdio/fgets.c
+++ b/lib/libc/stdio/fgets.c
@@ -1,117 +1,116 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fgets.c 8.2 (Berkeley) 12/22/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
/*
* Read at most n-1 characters from the given file.
* Stop when a newline has been read, or the count runs out.
* Return first argument, or NULL if no characters were read.
*/
char *
fgets(char * __restrict buf, int n, FILE * __restrict fp)
{
size_t len;
char *s, *ret;
unsigned char *p, *t;
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, -1);
if (n <= 0) { /* sanity check */
fp->_flags |= __SERR;
errno = EINVAL;
ret = NULL;
goto end;
}
s = buf;
n--; /* leave space for NUL */
while (n != 0) {
/*
* If the buffer is empty, refill it.
*/
if ((len = fp->_r) <= 0) {
if (__srefill(fp)) {
/* EOF/error: stop with partial or no line */
if (!__sfeof(fp) || s == buf) {
ret = NULL;
goto end;
}
break;
}
len = fp->_r;
}
p = fp->_p;
/*
* Scan through at most n bytes of the current buffer,
* looking for '\n'. If found, copy up to and including
* newline, and stop. Otherwise, copy entire chunk
* and loop.
*/
if (len > n)
len = n;
t = memchr((void *)p, '\n', len);
if (t != NULL) {
len = ++t - p;
fp->_r -= len;
fp->_p = t;
(void)memcpy((void *)s, (void *)p, len);
s[len] = 0;
ret = buf;
goto end;
}
fp->_r -= len;
fp->_p += len;
(void)memcpy((void *)s, (void *)p, len);
s += len;
n -= len;
}
*s = 0;
ret = buf;
end:
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
diff --git a/lib/libc/stdio/fgetwc.c b/lib/libc/stdio/fgetwc.c
index 949d93f67007..53d1f9564fe2 100644
--- a/lib/libc/stdio/fgetwc.c
+++ b/lib/libc/stdio/fgetwc.c
@@ -1,109 +1,108 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "mblocal.h"
#include "xlocale_private.h"
/*
* MT-safe version.
*/
wint_t
fgetwc_l(FILE *fp, locale_t locale)
{
wint_t r;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, 1);
r = __fgetwc(fp, locale);
FUNLOCKFILE_CANCELSAFE();
return (r);
}
wint_t
fgetwc(FILE *fp)
{
return fgetwc_l(fp, __get_locale());
}
/*
* Internal (non-MPSAFE) version of fgetwc(). This version takes an
* mbstate_t argument specifying the initial conversion state. For
* wide streams, this should always be fp->_mbstate. On return, *nread
* is set to the number of bytes read.
*/
wint_t
__fgetwc_mbs(FILE *fp, mbstate_t *mbs, int *nread, locale_t locale)
{
wchar_t wc;
size_t nconv;
struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
*nread = 0;
if (fp->_r <= 0 && __srefill(fp))
return (WEOF);
do {
nconv = l->__mbrtowc(&wc, fp->_p, fp->_r, mbs);
if (nconv == (size_t)-1) {
fp->_flags |= __SERR;
return (WEOF);
} else if (nconv == (size_t)-2)
continue;
else if (nconv == 0) {
fp->_p++;
fp->_r--;
(*nread)++;
return (L'\0');
} else {
fp->_p += nconv;
fp->_r -= nconv;
*nread += nconv;
return (wc);
}
} while (__srefill(fp) == 0);
if (__sfeof(fp)) {
fp->_flags |= __SERR;
errno = EILSEQ;
}
return (WEOF);
}
diff --git a/lib/libc/stdio/fgetwln.c b/lib/libc/stdio/fgetwln.c
index 8d74f9d8f3da..3a8e12b30c07 100644
--- a/lib/libc/stdio/fgetwln.c
+++ b/lib/libc/stdio/fgetwln.c
@@ -1,97 +1,96 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
wchar_t *fgetwln_l(FILE * __restrict, size_t *, locale_t);
wchar_t *
fgetwln_l(FILE * __restrict fp, size_t *lenp, locale_t locale)
{
wchar_t *ret;
wint_t wc;
size_t len;
int savserr;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, 1);
savserr = fp->_flags & __SERR;
fp->_flags &= ~__SERR;
len = 0;
while ((wc = __fgetwc(fp, locale)) != WEOF) {
#define GROW 512
if (len * sizeof(wchar_t) >= fp->_lb._size &&
__slbexpand(fp, (len + GROW) * sizeof(wchar_t))) {
fp->_flags |= __SERR;
goto error;
}
*((wchar_t *)fp->_lb._base + len++) = wc;
if (wc == L'\n')
break;
}
/* fgetwc(3) may set both __SEOF and __SERR at once. */
if (__sferror(fp))
goto error;
fp->_flags |= savserr;
if (len == 0)
goto error;
*lenp = len;
ret = (wchar_t *)fp->_lb._base;
end:
FUNLOCKFILE_CANCELSAFE();
return (ret);
error:
*lenp = 0;
ret = NULL;
goto end;
}
wchar_t *
fgetwln(FILE * __restrict fp, size_t *lenp)
{
return fgetwln_l(fp, lenp, __get_locale());
}
diff --git a/lib/libc/stdio/fgetws.c b/lib/libc/stdio/fgetws.c
index 1eaeed708ef1..1aa94e50f186 100644
--- a/lib/libc/stdio/fgetws.c
+++ b/lib/libc/stdio/fgetws.c
@@ -1,130 +1,129 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "mblocal.h"
wchar_t *
fgetws_l(wchar_t * __restrict ws, int n, FILE * __restrict fp, locale_t locale)
{
int sret;
wchar_t *wsp, *ret;
size_t nconv;
const char *src;
unsigned char *nl;
FIX_LOCALE(locale);
struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, 1);
if (n <= 0) {
fp->_flags |= __SERR;
errno = EINVAL;
goto error;
}
wsp = ws;
if (n == 1)
goto ok;
if (fp->_r <= 0 && __srefill(fp))
/* EOF or ferror */
goto error;
sret = 0;
do {
src = fp->_p;
nl = memchr(fp->_p, '\n', fp->_r);
nconv = l->__mbsnrtowcs(wsp, &src,
nl != NULL ? (nl - fp->_p + 1) : fp->_r,
n - 1, &fp->_mbstate);
if (nconv == (size_t)-1) {
/* Conversion error */
fp->_flags |= __SERR;
goto error;
}
if (src == NULL) {
/*
* We hit a null byte. Increment the character count,
* since mbsnrtowcs()'s return value doesn't include
* the terminating null, then resume conversion
* after the null.
*/
nconv++;
src = memchr(fp->_p, '\0', fp->_r);
src++;
}
fp->_r -= (unsigned char *)src - fp->_p;
fp->_p = (unsigned char *)src;
n -= nconv;
wsp += nconv;
} while ((wsp == ws || wsp[-1] != L'\n') && n > 1 && (fp->_r > 0 ||
(sret = __srefill(fp)) == 0));
if (sret && !__sfeof(fp))
/* ferror */
goto error;
if (!l->__mbsinit(&fp->_mbstate)) {
/* Incomplete character */
fp->_flags |= __SERR;
errno = EILSEQ;
goto error;
}
if (wsp == ws)
/* EOF */
goto error;
ok:
*wsp = L'\0';
ret = ws;
end:
FUNLOCKFILE_CANCELSAFE();
return (ret);
error:
ret = NULL;
goto end;
}
wchar_t *
fgetws(wchar_t * __restrict ws, int n, FILE * __restrict fp)
{
return fgetws_l(ws, n, fp, __get_locale());
}
diff --git a/lib/libc/stdio/fileno.c b/lib/libc/stdio/fileno.c
index 272a46abb74a..3adf8dcb959e 100644
--- a/lib/libc/stdio/fileno.c
+++ b/lib/libc/stdio/fileno.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fileno.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#undef fileno
#undef fileno_unlocked
int
fileno(FILE *fp)
{
int fd;
FLOCKFILE(fp);
fd = __sfileno(fp);
FUNLOCKFILE(fp);
return (fd);
}
int
fileno_unlocked(FILE *fp)
{
return (__sfileno(fp));
}
diff --git a/lib/libc/stdio/findfp.c b/lib/libc/stdio/findfp.c
index cf4eccf8807e..0944ed6e8f84 100644
--- a/lib/libc/stdio/findfp.c
+++ b/lib/libc/stdio/findfp.c
@@ -1,219 +1,218 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)findfp.c 8.2 (Berkeley) 1/4/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <machine/atomic.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <spinlock.h>
#include "libc_private.h"
#include "local.h"
#include "glue.h"
int __sdidinit;
#define NDYNAMIC 10 /* add ten more whenever necessary */
#define std(flags, file) { \
._flags = (flags), \
._file = (file), \
._cookie = __sF + (file), \
._close = __sclose, \
._read = __sread, \
._seek = __sseek, \
._write = __swrite, \
._fl_mutex = PTHREAD_MUTEX_INITIALIZER, \
}
/* the usual - (stdin + stdout + stderr) */
static FILE usual[FOPEN_MAX - 3];
static struct glue uglue = { NULL, FOPEN_MAX - 3, usual };
static FILE __sF[3] = {
std(__SRD, STDIN_FILENO),
std(__SWR, STDOUT_FILENO),
std(__SWR|__SNBF, STDERR_FILENO)
};
FILE *__stdinp = &__sF[0];
FILE *__stdoutp = &__sF[1];
FILE *__stderrp = &__sF[2];
struct glue __sglue = { &uglue, 3, __sF };
static struct glue *lastglue = &uglue;
static struct glue * moreglue(int);
spinlock_t __stdio_thread_lock = _SPINLOCK_INITIALIZER;
#if NOT_YET
#define SET_GLUE_PTR(ptr, val) atomic_set_rel_ptr(&(ptr), (uintptr_t)(val))
#else
#define SET_GLUE_PTR(ptr, val) ptr = val
#endif
static struct glue *
moreglue(int n)
{
struct glue *g;
static FILE empty = { ._fl_mutex = PTHREAD_MUTEX_INITIALIZER };
FILE *p;
size_t align;
align = __alignof__(FILE);
g = (struct glue *)malloc(sizeof(*g) + align + n * sizeof(FILE));
if (g == NULL)
return (NULL);
p = (FILE *)roundup((uintptr_t)(g + 1), align);
g->next = NULL;
g->niobs = n;
g->iobs = p;
while (--n >= 0)
*p++ = empty;
return (g);
}
/*
* Find a free FILE for fopen et al.
*/
FILE *
__sfp(void)
{
FILE *fp;
int n;
struct glue *g;
if (!__sdidinit)
__sinit();
/*
* The list must be locked because a FILE may be updated.
*/
STDIO_THREAD_LOCK();
for (g = &__sglue; g != NULL; g = g->next) {
for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
if (fp->_flags == 0)
goto found;
}
STDIO_THREAD_UNLOCK(); /* don't hold lock while malloc()ing. */
if ((g = moreglue(NDYNAMIC)) == NULL)
return (NULL);
STDIO_THREAD_LOCK(); /* reacquire the lock */
SET_GLUE_PTR(lastglue->next, g); /* atomically append glue to list */
lastglue = g; /* not atomic; only accessed when locked */
fp = g->iobs;
found:
fp->_flags = 1; /* reserve this slot; caller sets real flags */
STDIO_THREAD_UNLOCK();
fp->_p = NULL; /* no current pointer */
fp->_w = 0; /* nothing to read or write */
fp->_r = 0;
fp->_bf._base = NULL; /* no buffer */
fp->_bf._size = 0;
fp->_lbfsize = 0; /* not line buffered */
fp->_file = -1; /* no file */
/* fp->_cookie = <any>; */ /* caller sets cookie, _read/_write etc */
fp->_ub._base = NULL; /* no ungetc buffer */
fp->_ub._size = 0;
fp->_lb._base = NULL; /* no line buffer */
fp->_lb._size = 0;
/* fp->_fl_mutex = NULL; */ /* once set always set (reused) */
fp->_orientation = 0;
memset(&fp->_mbstate, 0, sizeof(mbstate_t));
fp->_flags2 = 0;
return (fp);
}
/*
* XXX. Force immediate allocation of internal memory. Not used by stdio,
* but documented historically for certain applications. Bad applications.
*/
__warn_references(f_prealloc,
"warning: this program uses f_prealloc(), which is not recommended.");
void f_prealloc(void);
void
f_prealloc(void)
{
struct glue *g;
int n;
n = getdtablesize() - FOPEN_MAX + 20; /* 20 for slop. */
/*
* It should be safe to walk the list without locking it;
* new nodes are only added to the end and none are ever
* removed.
*/
for (g = &__sglue; (n -= g->niobs) > 0 && g->next; g = g->next)
/* void */;
if ((n > 0) && ((g = moreglue(n)) != NULL)) {
STDIO_THREAD_LOCK();
SET_GLUE_PTR(lastglue->next, g);
lastglue = g;
STDIO_THREAD_UNLOCK();
}
}
/*
* exit() calls _cleanup() through *__cleanup, set whenever we
* open or buffer a file. This chicanery is done so that programs
* that do not use stdio need not link it all in.
*
* The name `_cleanup' is, alas, fairly well known outside stdio.
*/
void
_cleanup(void)
{
/* (void) _fwalk(fclose); */
(void) _fwalk(__sflush); /* `cheating' */
}
/*
* __sinit() is called whenever stdio's internal variables must be set up.
*/
void
__sinit(void)
{
/* Make sure we clean up on exit. */
__cleanup = _cleanup; /* conservative */
__sdidinit = 1;
}
diff --git a/lib/libc/stdio/flags.c b/lib/libc/stdio/flags.c
index 04b67f127986..d4503439a597 100644
--- a/lib/libc/stdio/flags.c
+++ b/lib/libc/stdio/flags.c
@@ -1,117 +1,116 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)flags.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/file.h>
#include <stdio.h>
#include <errno.h>
#include "local.h"
/*
* Return the (stdio) flags for a given mode. Store the flags
* to be passed to an _open() syscall through *optr.
* Return 0 on error.
*/
int
__sflags(const char *mode, int *optr)
{
int ret, m, o, known;
switch (*mode++) {
case 'r': /* open for reading */
ret = __SRD;
m = O_RDONLY;
o = 0;
break;
case 'w': /* open for writing */
ret = __SWR;
m = O_WRONLY;
o = O_CREAT | O_TRUNC;
break;
case 'a': /* open for appending */
ret = __SWR;
m = O_WRONLY;
o = O_CREAT | O_APPEND;
break;
default: /* illegal mode */
errno = EINVAL;
return (0);
}
do {
known = 1;
switch (*mode++) {
case 'b':
/* 'b' (binary) is ignored */
break;
case '+':
/* [rwa][b]\+ means read and write */
ret = __SRW;
m = O_RDWR;
break;
case 'x':
/* 'x' means exclusive (fail if the file exists) */
o |= O_EXCL;
break;
case 'e':
/* set close-on-exec */
o |= O_CLOEXEC;
break;
case 'v':
/* verify */
o |= O_VERIFY;
break;
default:
known = 0;
break;
}
} while (known);
if ((o & O_EXCL) != 0 && m == O_RDONLY) {
errno = EINVAL;
return (0);
}
*optr = m | o;
return (ret);
}
diff --git a/lib/libc/stdio/fmemopen.c b/lib/libc/stdio/fmemopen.c
index 295592ac896f..2f835a34951b 100644
--- a/lib/libc/stdio/fmemopen.c
+++ b/lib/libc/stdio/fmemopen.c
@@ -1,262 +1,261 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include "local.h"
struct fmemopen_cookie
{
char *buf; /* pointer to the memory region */
bool own; /* did we allocate the buffer ourselves? */
char bin; /* is this a binary buffer? */
size_t size; /* buffer length in bytes */
size_t len; /* data length in bytes */
size_t off; /* current offset into the buffer */
};
static int fmemopen_read(void *cookie, char *buf, int nbytes);
static int fmemopen_write(void *cookie, const char *buf, int nbytes);
static fpos_t fmemopen_seek(void *cookie, fpos_t offset, int whence);
static int fmemopen_close(void *cookie);
FILE *
fmemopen(void * __restrict buf, size_t size, const char * __restrict mode)
{
struct fmemopen_cookie *ck;
FILE *f;
int flags, rc;
/*
* POSIX says we shall return EINVAL if size is 0.
*/
if (size == 0) {
errno = EINVAL;
return (NULL);
}
/*
* Retrieve the flags as used by open(2) from the mode argument, and
* validate them.
*/
rc = __sflags(mode, &flags);
if (rc == 0) {
errno = EINVAL;
return (NULL);
}
/*
* There's no point in requiring an automatically allocated buffer
* in write-only mode.
*/
if (!(flags & O_RDWR) && buf == NULL) {
errno = EINVAL;
return (NULL);
}
ck = malloc(sizeof(struct fmemopen_cookie));
if (ck == NULL) {
return (NULL);
}
ck->off = 0;
ck->size = size;
/* Check whether we have to allocate the buffer ourselves. */
ck->own = ((ck->buf = buf) == NULL);
if (ck->own) {
ck->buf = malloc(size);
if (ck->buf == NULL) {
free(ck);
return (NULL);
}
}
/*
* POSIX distinguishes between w+ and r+, in that w+ is supposed to
* truncate the buffer.
*/
if (ck->own || mode[0] == 'w') {
ck->buf[0] = '\0';
}
/* Check for binary mode. */
ck->bin = strchr(mode, 'b') != NULL;
/*
* The size of the current buffer contents is set depending on the
* mode:
*
* for append (text-mode), the position of the first NULL byte, or the
* size of the buffer if none is found
*
* for append (binary-mode), the size of the buffer
*
* for read, the size of the buffer
*
* for write, 0
*/
switch (mode[0]) {
case 'a':
ck->off = ck->len = strnlen(ck->buf, ck->size);
break;
case 'r':
ck->len = size;
break;
case 'w':
ck->len = 0;
break;
}
f = funopen(ck,
flags & O_WRONLY ? NULL : fmemopen_read,
flags & O_RDONLY ? NULL : fmemopen_write,
fmemopen_seek, fmemopen_close);
if (f == NULL) {
if (ck->own)
free(ck->buf);
free(ck);
return (NULL);
}
if (mode[0] == 'a')
f->_flags |= __SAPP;
/*
* Turn off buffering, so a write past the end of the buffer
* correctly returns a short object count.
*/
setvbuf(f, NULL, _IONBF, 0);
return (f);
}
static int
fmemopen_read(void *cookie, char *buf, int nbytes)
{
struct fmemopen_cookie *ck = cookie;
if (nbytes > ck->len - ck->off)
nbytes = ck->len - ck->off;
if (nbytes == 0)
return (0);
memcpy(buf, ck->buf + ck->off, nbytes);
ck->off += nbytes;
return (nbytes);
}
static int
fmemopen_write(void *cookie, const char *buf, int nbytes)
{
struct fmemopen_cookie *ck = cookie;
if (nbytes > ck->size - ck->off)
nbytes = ck->size - ck->off;
if (nbytes == 0)
return (0);
memcpy(ck->buf + ck->off, buf, nbytes);
ck->off += nbytes;
if (ck->off > ck->len)
ck->len = ck->off;
/*
* We append a NULL byte if all these conditions are met:
* - the buffer is not binary
* - the buffer is not full
* - the data just written doesn't already end with a NULL byte
*/
if (!ck->bin && ck->off < ck->size && ck->buf[ck->off - 1] != '\0')
ck->buf[ck->off] = '\0';
return (nbytes);
}
static fpos_t
fmemopen_seek(void *cookie, fpos_t offset, int whence)
{
struct fmemopen_cookie *ck = cookie;
switch (whence) {
case SEEK_SET:
if (offset > ck->size) {
errno = EINVAL;
return (-1);
}
ck->off = offset;
break;
case SEEK_CUR:
if (ck->off + offset > ck->size) {
errno = EINVAL;
return (-1);
}
ck->off += offset;
break;
case SEEK_END:
if (offset > 0 || -offset > ck->len) {
errno = EINVAL;
return (-1);
}
ck->off = ck->len + offset;
break;
default:
errno = EINVAL;
return (-1);
}
return (ck->off);
}
static int
fmemopen_close(void *cookie)
{
struct fmemopen_cookie *ck = cookie;
if (ck->own)
free(ck->buf);
free(ck);
return (0);
}
diff --git a/lib/libc/stdio/fopen.c b/lib/libc/stdio/fopen.c
index 2f2de15345c4..c7eb8ffd7b8c 100644
--- a/lib/libc/stdio/fopen.c
+++ b/lib/libc/stdio/fopen.c
@@ -1,99 +1,98 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fopen.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include "un-namespace.h"
#include "local.h"
FILE *
fopen(const char * __restrict file, const char * __restrict mode)
{
FILE *fp;
int f;
int flags, oflags;
if ((flags = __sflags(mode, &oflags)) == 0)
return (NULL);
if ((fp = __sfp()) == NULL)
return (NULL);
if ((f = _open(file, oflags, DEFFILEMODE)) < 0) {
fp->_flags = 0; /* release */
return (NULL);
}
/*
* File descriptors are a full int, but _file is only a short.
* If we get a valid file descriptor that is greater than
* SHRT_MAX, then the fd will get sign-extended into an
* invalid file descriptor. Handle this case by failing the
* open.
*/
if (f > SHRT_MAX) {
fp->_flags = 0; /* release */
_close(f);
errno = EMFILE;
return (NULL);
}
fp->_file = f;
fp->_flags = flags;
fp->_cookie = fp;
fp->_read = __sread;
fp->_write = __swrite;
fp->_seek = __sseek;
fp->_close = __sclose;
/*
* When opening in append mode, even though we use O_APPEND,
* we need to seek to the end so that ftell() gets the right
* answer. If the user then alters the seek pointer, or
* the file extends, this will fail, but there is not much
* we can do about this. (We could set __SAPP and check in
* fseek and ftell.)
*/
if (oflags & O_APPEND) {
fp->_flags2 |= __S2OAP;
(void)_sseek(fp, (fpos_t)0, SEEK_END);
}
return (fp);
}
diff --git a/lib/libc/stdio/fopencookie.c b/lib/libc/stdio/fopencookie.c
index 9c295ff7bfed..ef49d3d10f16 100644
--- a/lib/libc/stdio/fopencookie.c
+++ b/lib/libc/stdio/fopencookie.c
@@ -1,166 +1,165 @@
/*
* Copyright (c) 2016, EMC / Isilon Storage Division
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "local.h"
struct fopencookie_thunk {
void *foc_cookie;
cookie_io_functions_t foc_io;
};
static int _fopencookie_read(void *, char *, int);
static int _fopencookie_write(void *, const char *, int);
static fpos_t _fopencookie_seek(void *, fpos_t, int);
static int _fopencookie_close(void *);
FILE *
fopencookie(void *cookie, const char *mode, cookie_io_functions_t io_funcs)
{
int (*readfn)(void *, char *, int);
int (*writefn)(void *, const char *, int);
struct fopencookie_thunk *thunk;
FILE *fp;
int flags, oflags;
if ((flags = __sflags(mode, &oflags)) == 0)
return (NULL);
thunk = malloc(sizeof(*thunk));
if (thunk == NULL)
return (NULL);
thunk->foc_cookie = cookie;
thunk->foc_io = io_funcs;
readfn = _fopencookie_read;
writefn = _fopencookie_write;
if (flags == __SWR)
readfn = NULL;
else if (flags == __SRD)
writefn = NULL;
fp = funopen(thunk, readfn, writefn, _fopencookie_seek,
_fopencookie_close);
if (fp == NULL) {
free(thunk);
return (NULL);
}
if ((oflags & O_APPEND) != 0)
fp->_flags |= __SAPP;
return (fp);
}
static int
_fopencookie_read(void *cookie, char *buf, int size)
{
struct fopencookie_thunk *thunk;
thunk = cookie;
/* Reads from a stream with NULL read return EOF. */
if (thunk->foc_io.read == NULL)
return (0);
return ((int)thunk->foc_io.read(thunk->foc_cookie, buf, (size_t)size));
}
static int
_fopencookie_write(void *cookie, const char *buf, int size)
{
struct fopencookie_thunk *thunk;
thunk = cookie;
/* Writes to a stream with NULL write discard data. */
if (thunk->foc_io.write == NULL)
return (size);
return ((int)thunk->foc_io.write(thunk->foc_cookie, buf,
(size_t)size));
}
static fpos_t
_fopencookie_seek(void *cookie, fpos_t offset, int whence)
{
struct fopencookie_thunk *thunk;
off64_t off64;
int res;
switch (whence) {
case SEEK_SET:
case SEEK_CUR:
case SEEK_END:
break;
default:
/* fopencookie(3) only allows these three seek modes. */
errno = EINVAL;
return (-1);
}
thunk = cookie;
/*
* If seek is NULL, it is not possible to perform seek operations on
* the stream.
*/
if (thunk->foc_io.seek == NULL) {
errno = ENOTSUP;
return (-1);
}
off64 = (off64_t)offset;
res = thunk->foc_io.seek(thunk->foc_cookie, &off64, whence);
if (res < 0)
return (res);
return ((fpos_t)off64);
}
static int
_fopencookie_close(void *cookie)
{
struct fopencookie_thunk *thunk;
int ret, serrno;
ret = 0;
thunk = cookie;
if (thunk->foc_io.close != NULL)
ret = thunk->foc_io.close(thunk->foc_cookie);
serrno = errno;
free(thunk);
errno = serrno;
return (ret);
}
diff --git a/lib/libc/stdio/fprintf.c b/lib/libc/stdio/fprintf.c
index c1df55872aa3..8696d1cee469 100644
--- a/lib/libc/stdio/fprintf.c
+++ b/lib/libc/stdio/fprintf.c
@@ -1,70 +1,69 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdarg.h>
#include "xlocale_private.h"
int
fprintf(FILE * __restrict fp, const char * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf_l(fp, __get_locale(), fmt, ap);
va_end(ap);
return (ret);
}
int
fprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt, ...)
{
int ret;
va_list ap;
FIX_LOCALE(locale);
va_start(ap, fmt);
ret = vfprintf_l(fp, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/fpurge.c b/lib/libc/stdio/fpurge.c
index 4ca6a5373050..fc2b434397fa 100644
--- a/lib/libc/stdio/fpurge.c
+++ b/lib/libc/stdio/fpurge.c
@@ -1,69 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fpurge.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
/*
* fpurge: like fflush, but without writing anything: leave the
* given FILE's buffer empty.
*/
int
fpurge(FILE *fp)
{
int retval;
FLOCKFILE(fp);
if (!fp->_flags) {
errno = EBADF;
retval = EOF;
} else {
if (HASUB(fp))
FREEUB(fp);
fp->_p = fp->_bf._base;
fp->_r = 0;
fp->_w = fp->_flags & (__SLBF|__SNBF|__SRD) ? 0 : fp->_bf._size;
retval = 0;
}
FUNLOCKFILE(fp);
return (retval);
}
diff --git a/lib/libc/stdio/fputc.c b/lib/libc/stdio/fputc.c
index 54476b8f2bea..297555bec401 100644
--- a/lib/libc/stdio/fputc.c
+++ b/lib/libc/stdio/fputc.c
@@ -1,65 +1,64 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fputc.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
#undef fputc_unlocked
int
fputc_unlocked(int c, FILE *fp)
{
/* Orientation set by __sputc() when buffer is full. */
/* ORIENT(fp, -1); */
return (__sputc(c, fp));
}
int
fputc(int c, FILE *fp)
{
int retval;
FLOCKFILE_CANCELSAFE(fp);
retval = fputc_unlocked(c, fp);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
diff --git a/lib/libc/stdio/fputs.c b/lib/libc/stdio/fputs.c
index 1b611d50017b..9e1f54e9c761 100644
--- a/lib/libc/stdio/fputs.c
+++ b/lib/libc/stdio/fputs.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fputs.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "un-namespace.h"
#include "fvwrite.h"
#include "libc_private.h"
#include "local.h"
/*
* Write the given string to the given file.
*/
int
fputs_unlocked(const char * __restrict s, FILE * __restrict fp)
{
int retval;
struct __suio uio;
struct __siov iov;
iov.iov_base = (void *)s;
uio.uio_resid = iov.iov_len = strlen(s);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
ORIENT(fp, -1);
retval = __sfvwrite(fp, &uio);
if (retval == 0)
return (iov.iov_len > INT_MAX ? INT_MAX : iov.iov_len);
return (retval);
}
int
fputs(const char * __restrict s, FILE * __restrict fp)
{
int retval;
FLOCKFILE_CANCELSAFE(fp);
retval = fputs_unlocked(s, fp);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
diff --git a/lib/libc/stdio/fputwc.c b/lib/libc/stdio/fputwc.c
index 197c57cc374a..7955a4e811b2 100644
--- a/lib/libc/stdio/fputwc.c
+++ b/lib/libc/stdio/fputwc.c
@@ -1,88 +1,87 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "mblocal.h"
/*
* Non-MT-safe version.
*/
wint_t
__fputwc(wchar_t wc, FILE *fp, locale_t locale)
{
char buf[MB_LEN_MAX];
size_t i, len;
struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
fp->_flags |= __SERR;
return (WEOF);
}
for (i = 0; i < len; i++)
if (__sputc((unsigned char)buf[i], fp) == EOF)
return (WEOF);
return ((wint_t)wc);
}
/*
* MT-safe version.
*/
wint_t
fputwc_l(wchar_t wc, FILE *fp, locale_t locale)
{
wint_t r;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, 1);
r = __fputwc(wc, fp, locale);
FUNLOCKFILE_CANCELSAFE();
return (r);
}
wint_t
fputwc(wchar_t wc, FILE *fp)
{
return fputwc_l(wc, fp, __get_locale());
}
diff --git a/lib/libc/stdio/fputws.c b/lib/libc/stdio/fputws.c
index c77393886e72..105fc426cb9c 100644
--- a/lib/libc/stdio/fputws.c
+++ b/lib/libc/stdio/fputws.c
@@ -1,86 +1,85 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <wchar.h>
#include "un-namespace.h"
#include "fvwrite.h"
#include "libc_private.h"
#include "local.h"
#include "mblocal.h"
int
fputws_l(const wchar_t * __restrict ws, FILE * __restrict fp, locale_t locale)
{
size_t nbytes;
char buf[BUFSIZ];
struct __suio uio;
struct __siov iov;
const wchar_t *wsp;
FIX_LOCALE(locale);
struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
int ret;
ret = -1;
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, 1);
if (prepwrite(fp) != 0)
goto end;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
iov.iov_base = buf;
wsp = ws;
do {
nbytes = l->__wcsnrtombs(buf, &wsp, SIZE_T_MAX, sizeof(buf),
&fp->_mbstate);
if (nbytes == (size_t)-1)
goto end;
uio.uio_resid = iov.iov_len = nbytes;
if (__sfvwrite(fp, &uio) != 0)
goto end;
} while (wsp != NULL);
ret = 0;
end:
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
int
fputws(const wchar_t * __restrict ws, FILE * __restrict fp)
{
return fputws_l(ws, fp, __get_locale());
}
diff --git a/lib/libc/stdio/fread.c b/lib/libc/stdio/fread.c
index 13776382fbb7..9e1b0c5f42a3 100644
--- a/lib/libc/stdio/fread.c
+++ b/lib/libc/stdio/fread.c
@@ -1,148 +1,147 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fread.c 8.2 (Berkeley) 12/11/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
/*
* MT-safe version
*/
size_t
fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp)
{
size_t ret;
FLOCKFILE_CANCELSAFE(fp);
ret = __fread(buf, size, count, fp);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
size_t
__fread(void * __restrict buf, size_t size, size_t count, FILE * __restrict fp)
{
size_t resid;
char *p;
int r;
size_t total;
/*
* ANSI and SUSv2 require a return value of 0 if size or count are 0.
*/
if ((count == 0) || (size == 0))
return (0);
/*
* Check for integer overflow. As an optimization, first check that
* at least one of {count, size} is at least 2^16, since if both
* values are less than that, their product can't possible overflow
* (size_t is always at least 32 bits on FreeBSD).
*/
if (((count | size) > 0xFFFF) &&
(count > SIZE_MAX / size)) {
errno = EINVAL;
fp->_flags |= __SERR;
return (0);
}
/*
* Compute the (now required to not overflow) number of bytes to
* read and actually do the work.
*/
resid = count * size;
ORIENT(fp, -1);
if (fp->_r < 0)
fp->_r = 0;
total = resid;
p = buf;
/*
* If we're unbuffered we know that the buffer in fp is empty so
* we can read directly into buf. This is much faster than a
* series of one byte reads into fp->_nbuf.
*/
if ((fp->_flags & __SNBF) != 0 && buf != NULL) {
while (resid > 0) {
/* set up the buffer */
fp->_bf._base = fp->_p = p;
fp->_bf._size = resid;
if (__srefill(fp)) {
/* no more input: return partial result */
count = (total - resid) / size;
break;
}
p += fp->_r;
resid -= fp->_r;
}
/* restore the old buffer (see __smakebuf) */
fp->_bf._base = fp->_p = fp->_nbuf;
fp->_bf._size = 1;
fp->_r = 0;
return (count);
}
while (resid > (r = fp->_r)) {
if (r != 0) {
(void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
fp->_p += r;
/* fp->_r = 0 ... done in __srefill */
p += r;
resid -= r;
}
if (__srefill(fp)) {
/* no more input: return partial result */
return ((total - resid) / size);
}
}
(void)memcpy((void *)p, (void *)fp->_p, resid);
fp->_r -= resid;
fp->_p += resid;
return (count);
}
__weak_reference(__fread, fread_unlocked);
diff --git a/lib/libc/stdio/freopen.c b/lib/libc/stdio/freopen.c
index 2f3f96c1d92a..f987d273d116 100644
--- a/lib/libc/stdio/freopen.c
+++ b/lib/libc/stdio/freopen.c
@@ -1,251 +1,250 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)freopen.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <limits.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
/*
* Re-direct an existing, open (probably) file to some other file.
* ANSI is written such that the original file gets closed if at
* all possible, no matter what.
*/
FILE *
freopen(const char * __restrict file, const char * __restrict mode,
FILE * __restrict fp)
{
int f;
int dflags, flags, isopen, oflags, sverrno, wantfd;
if ((flags = __sflags(mode, &oflags)) == 0) {
sverrno = errno;
(void) fclose(fp);
errno = sverrno;
return (NULL);
}
FLOCKFILE_CANCELSAFE(fp);
if (!__sdidinit)
__sinit();
/*
* If the filename is a NULL pointer, the caller is asking us to
* re-open the same file with a different mode. We allow this only
* if the modes are compatible.
*/
if (file == NULL) {
/* See comment below regarding freopen() of closed files. */
if (fp->_flags == 0) {
errno = EINVAL;
fp = NULL;
goto end;
}
if ((dflags = _fcntl(fp->_file, F_GETFL)) < 0) {
sverrno = errno;
fclose(fp);
errno = sverrno;
fp = NULL;
goto end;
}
/* Work around incorrect O_ACCMODE. */
if ((dflags & O_ACCMODE) != O_RDWR &&
(dflags & (O_ACCMODE | O_EXEC)) != (oflags & O_ACCMODE)) {
fclose(fp);
errno = EBADF;
fp = NULL;
goto end;
}
if (fp->_flags & __SWR)
(void) __sflush(fp);
if ((oflags ^ dflags) & O_APPEND) {
dflags &= ~O_APPEND;
dflags |= oflags & O_APPEND;
if (_fcntl(fp->_file, F_SETFL, dflags) < 0) {
sverrno = errno;
fclose(fp);
errno = sverrno;
fp = NULL;
goto end;
}
}
if (oflags & O_TRUNC)
(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);
f = fp->_file;
isopen = 0;
wantfd = -1;
goto finish;
}
/*
* There are actually programs that depend on being able to "freopen"
* descriptors that weren't originally open. Keep this from breaking.
* Remember whether the stream was open to begin with, and which file
* descriptor (if any) was associated with it. If it was attached to
* a descriptor, defer closing it; freopen("/dev/stdin", "r", stdin)
* should work. This is unnecessary if it was not a Unix file.
*/
if (fp->_flags == 0) {
fp->_flags = __SEOF; /* hold on to it */
isopen = 0;
wantfd = -1;
} else {
/* flush the stream; ANSI doesn't require this. */
if (fp->_flags & __SWR)
(void) __sflush(fp);
/* if close is NULL, closing is a no-op, hence pointless */
isopen = fp->_close != NULL;
if ((wantfd = fp->_file) < 0 && isopen) {
(void) (*fp->_close)(fp->_cookie);
isopen = 0;
}
}
/* Get a new descriptor to refer to the new file. */
f = _open(file, oflags, DEFFILEMODE);
/* If out of fd's close the old one and try again. */
if (f < 0 && isopen && wantfd > STDERR_FILENO &&
(errno == ENFILE || errno == EMFILE)) {
(void) (*fp->_close)(fp->_cookie);
isopen = 0;
wantfd = -1;
f = _open(file, oflags, DEFFILEMODE);
}
sverrno = errno;
finish:
/*
* Finish closing fp. Even if the open succeeded above, we cannot
* keep fp->_base: it may be the wrong size. This loses the effect
* of any setbuffer calls, but stdio has always done this before.
*
* Leave the existing file descriptor open until dup2() is called
* below to avoid races where a concurrent open() in another thread
* could claim the existing descriptor.
*/
if (fp->_flags & __SMBF)
free((char *)fp->_bf._base);
fp->_w = 0;
fp->_r = 0;
fp->_p = NULL;
fp->_bf._base = NULL;
fp->_bf._size = 0;
fp->_lbfsize = 0;
if (HASUB(fp))
FREEUB(fp);
fp->_ub._size = 0;
if (HASLB(fp))
FREELB(fp);
fp->_lb._size = 0;
fp->_orientation = 0;
memset(&fp->_mbstate, 0, sizeof(mbstate_t));
fp->_flags2 = 0;
if (f < 0) { /* did not get it after all */
if (isopen)
(void) (*fp->_close)(fp->_cookie);
fp->_flags = 0; /* set it free */
errno = sverrno; /* restore in case _close clobbered */
fp = NULL;
goto end;
}
/*
* If reopening something that was open before on a real file, try
* to maintain the descriptor. Various C library routines (perror)
* assume stderr is always fd STDERR_FILENO, even if being freopen'd.
*/
if (wantfd >= 0) {
if ((oflags & O_CLOEXEC ? _fcntl(f, F_DUP2FD_CLOEXEC, wantfd) :
_dup2(f, wantfd)) >= 0) {
(void)_close(f);
f = wantfd;
} else
(void)_close(fp->_file);
}
/*
* File descriptors are a full int, but _file is only a short.
* If we get a valid file descriptor that is greater than
* SHRT_MAX, then the fd will get sign-extended into an
* invalid file descriptor. Handle this case by failing the
* open.
*/
if (f > SHRT_MAX) {
fp->_flags = 0; /* set it free */
errno = EMFILE;
fp = NULL;
goto end;
}
fp->_flags = flags;
fp->_file = f;
fp->_cookie = fp;
fp->_read = __sread;
fp->_write = __swrite;
fp->_seek = __sseek;
fp->_close = __sclose;
/*
* When opening in append mode, even though we use O_APPEND,
* we need to seek to the end so that ftell() gets the right
* answer. If the user then alters the seek pointer, or
* the file extends, this will fail, but there is not much
* we can do about this. (We could set __SAPP and check in
* fseek and ftell.)
*/
if (oflags & O_APPEND) {
fp->_flags2 |= __S2OAP;
(void) _sseek(fp, (fpos_t)0, SEEK_END);
}
end:
FUNLOCKFILE_CANCELSAFE();
return (fp);
}
diff --git a/lib/libc/stdio/fscanf.c b/lib/libc/stdio/fscanf.c
index f274cb98ef3c..3a15a279fa88 100644
--- a/lib/libc/stdio/fscanf.c
+++ b/lib/libc/stdio/fscanf.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fscanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <stdarg.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
int
fscanf(FILE * __restrict fp, char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
FLOCKFILE_CANCELSAFE(fp);
ret = __svfscanf(fp, __get_locale(), fmt, ap);
va_end(ap);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
int
fscanf_l(FILE * __restrict fp, locale_t locale, char const * __restrict fmt, ...)
{
int ret;
va_list ap;
FIX_LOCALE(locale);
va_start(ap, fmt);
FLOCKFILE_CANCELSAFE(fp);
ret = __svfscanf(fp, locale, fmt, ap);
va_end(ap);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
diff --git a/lib/libc/stdio/fseek.c b/lib/libc/stdio/fseek.c
index 21f1079b6458..7d0f4be1ff91 100644
--- a/lib/libc/stdio/fseek.c
+++ b/lib/libc/stdio/fseek.c
@@ -1,301 +1,300 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fseek.c 8.3 (Berkeley) 1/2/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
#define POS_ERR (-(fpos_t)1)
int
fseek(FILE *fp, long offset, int whence)
{
int ret;
int serrno = errno;
/* make sure stdio is set up */
if (!__sdidinit)
__sinit();
FLOCKFILE_CANCELSAFE(fp);
ret = _fseeko(fp, (off_t)offset, whence, 1);
FUNLOCKFILE_CANCELSAFE();
if (ret == 0)
errno = serrno;
return (ret);
}
int
fseeko(FILE *fp, off_t offset, int whence)
{
int ret;
int serrno = errno;
/* make sure stdio is set up */
if (!__sdidinit)
__sinit();
FLOCKFILE_CANCELSAFE(fp);
ret = _fseeko(fp, offset, whence, 0);
FUNLOCKFILE_CANCELSAFE();
if (ret == 0)
errno = serrno;
return (ret);
}
/*
* Seek the given file to the given offset.
* `Whence' must be one of the three SEEK_* macros.
*/
int
_fseeko(FILE *fp, off_t offset, int whence, int ltest)
{
fpos_t (*seekfn)(void *, fpos_t, int);
fpos_t target, curoff, ret;
size_t n;
struct stat st;
int havepos;
/*
* Have to be able to seek.
*/
if ((seekfn = fp->_seek) == NULL) {
errno = ESPIPE; /* historic practice */
return (-1);
}
/*
* Change any SEEK_CUR to SEEK_SET, and check `whence' argument.
* After this, whence is either SEEK_SET or SEEK_END.
*/
switch (whence) {
case SEEK_CUR:
/*
* In order to seek relative to the current stream offset,
* we have to first find the current stream offset via
* ftell (see ftell for details).
*/
if (_ftello(fp, &curoff))
return (-1);
if (curoff < 0) {
/* Unspecified position because of ungetc() at 0 */
errno = ESPIPE;
return (-1);
}
if (offset > 0 && curoff > OFF_MAX - offset) {
errno = EOVERFLOW;
return (-1);
}
offset += curoff;
if (offset < 0) {
errno = EINVAL;
return (-1);
}
if (ltest && offset > LONG_MAX) {
errno = EOVERFLOW;
return (-1);
}
whence = SEEK_SET;
havepos = 1;
break;
case SEEK_SET:
if (offset < 0) {
errno = EINVAL;
return (-1);
}
case SEEK_END:
curoff = 0; /* XXX just to keep gcc quiet */
havepos = 0;
break;
default:
errno = EINVAL;
return (-1);
}
/*
* Can only optimise if:
* reading (and not reading-and-writing);
* not unbuffered; and
* this is a `regular' Unix file (and hence seekfn==__sseek).
* We must check __NBF first, because it is possible to have __NBF
* and __SOPT both set.
*/
if (fp->_bf._base == NULL)
__smakebuf(fp);
if (fp->_flags & (__SWR | __SRW | __SNBF | __SNPT))
goto dumb;
if ((fp->_flags & __SOPT) == 0) {
if (seekfn != __sseek ||
fp->_file < 0 || _fstat(fp->_file, &st) ||
(st.st_mode & S_IFMT) != S_IFREG) {
fp->_flags |= __SNPT;
goto dumb;
}
fp->_blksize = st.st_blksize;
fp->_flags |= __SOPT;
}
/*
* We are reading; we can try to optimise.
* Figure out where we are going and where we are now.
*/
if (whence == SEEK_SET)
target = offset;
else {
if (_fstat(fp->_file, &st))
goto dumb;
if (offset > 0 && st.st_size > OFF_MAX - offset) {
errno = EOVERFLOW;
return (-1);
}
target = st.st_size + offset;
if ((off_t)target < 0) {
errno = EINVAL;
return (-1);
}
if (ltest && (off_t)target > LONG_MAX) {
errno = EOVERFLOW;
return (-1);
}
}
if (!havepos && _ftello(fp, &curoff))
goto dumb;
/*
* (If the buffer was modified, we have to
* skip this; see fgetln.c.)
*/
if (fp->_flags & __SMOD)
goto abspos;
/*
* Compute the number of bytes in the input buffer (pretending
* that any ungetc() input has been discarded). Adjust current
* offset backwards by this count so that it represents the
* file offset for the first byte in the current input buffer.
*/
if (HASUB(fp)) {
curoff += fp->_r; /* kill off ungetc */
n = fp->_up - fp->_bf._base;
curoff -= n;
n += fp->_ur;
} else {
n = fp->_p - fp->_bf._base;
curoff -= n;
n += fp->_r;
}
/*
* If the target offset is within the current buffer,
* simply adjust the pointers, clear EOF, undo ungetc(),
* and return.
*/
if (target >= curoff && target < curoff + n) {
size_t o = target - curoff;
fp->_p = fp->_bf._base + o;
fp->_r = n - o;
if (HASUB(fp))
FREEUB(fp);
fp->_flags &= ~__SEOF;
memset(&fp->_mbstate, 0, sizeof(mbstate_t));
return (0);
}
abspos:
/*
* The place we want to get to is not within the current buffer,
* but we can still be kind to the kernel copyout mechanism.
* By aligning the file offset to a block boundary, we can let
* the kernel use the VM hardware to map pages instead of
* copying bytes laboriously. Using a block boundary also
* ensures that we only read one block, rather than two.
*/
curoff = target & ~(fp->_blksize - 1);
if (_sseek(fp, curoff, SEEK_SET) == POS_ERR)
goto dumb;
fp->_r = 0;
fp->_p = fp->_bf._base;
if (HASUB(fp))
FREEUB(fp);
n = target - curoff;
if (n) {
if (__srefill(fp) || fp->_r < n)
goto dumb;
fp->_p += n;
fp->_r -= n;
}
fp->_flags &= ~__SEOF;
memset(&fp->_mbstate, 0, sizeof(mbstate_t));
return (0);
/*
* We get here if we cannot optimise the seek ... just
* do it. Allow the seek function to change fp->_bf._base.
*/
dumb:
if (__sflush(fp) ||
(ret = _sseek(fp, (fpos_t)offset, whence)) == POS_ERR)
return (-1);
if (ltest && ret > LONG_MAX) {
fp->_flags |= __SERR;
errno = EOVERFLOW;
return (-1);
}
/* success: clear EOF indicator and discard ungetc() data */
if (HASUB(fp))
FREEUB(fp);
fp->_p = fp->_bf._base;
fp->_r = 0;
/* fp->_w = 0; */ /* unnecessary (I think...) */
fp->_flags &= ~__SEOF;
memset(&fp->_mbstate, 0, sizeof(mbstate_t));
return (0);
}
diff --git a/lib/libc/stdio/fsetpos.c b/lib/libc/stdio/fsetpos.c
index 4f985e249a32..2a3fbb37c1a4 100644
--- a/lib/libc/stdio/fsetpos.c
+++ b/lib/libc/stdio/fsetpos.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fsetpos.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
/*
* fsetpos: like fseek.
*/
int
fsetpos(FILE *iop, const fpos_t *pos)
{
return (fseeko(iop, (off_t)*pos, SEEK_SET));
}
diff --git a/lib/libc/stdio/ftell.c b/lib/libc/stdio/ftell.c
index 4cb038df1d76..7f7813e9a986 100644
--- a/lib/libc/stdio/ftell.c
+++ b/lib/libc/stdio/ftell.c
@@ -1,141 +1,140 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ftell.c 8.2 (Berkeley) 5/4/95";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
/*
* standard ftell function.
*/
long
ftell(FILE *fp)
{
off_t rv;
rv = ftello(fp);
if (rv > LONG_MAX) {
errno = EOVERFLOW;
return (-1);
}
return (rv);
}
/*
* ftello: return current offset.
*/
off_t
ftello(FILE *fp)
{
fpos_t rv;
int ret;
FLOCKFILE(fp);
ret = _ftello(fp, &rv);
FUNLOCKFILE(fp);
if (ret)
return (-1);
if (rv < 0) { /* Unspecified value because of ungetc() at 0 */
errno = ESPIPE;
return (-1);
}
return (rv);
}
int
_ftello(FILE *fp, fpos_t *offset)
{
fpos_t pos;
size_t n;
if (fp->_seek == NULL) {
errno = ESPIPE; /* historic practice */
return (1);
}
/*
* Find offset of underlying I/O object, then
* adjust for buffered bytes.
*/
if (!(fp->_flags & __SRD) && (fp->_flags & __SWR) &&
fp->_p != NULL && fp->_p - fp->_bf._base > 0 &&
((fp->_flags & __SAPP) || (fp->_flags2 & __S2OAP))) {
pos = _sseek(fp, (fpos_t)0, SEEK_END);
if (pos == -1)
return (1);
} else if (fp->_flags & __SOFF)
pos = fp->_offset;
else {
pos = _sseek(fp, (fpos_t)0, SEEK_CUR);
if (pos == -1)
return (1);
}
if (fp->_flags & __SRD) {
/*
* Reading. Any unread characters (including
* those from ungetc) cause the position to be
* smaller than that in the underlying object.
*/
if ((pos -= (HASUB(fp) ? fp->_ur : fp->_r)) < 0) {
fp->_flags |= __SERR;
errno = EIO;
return (1);
}
if (HASUB(fp))
pos -= fp->_r; /* Can be negative at this point. */
} else if ((fp->_flags & __SWR) && fp->_p != NULL &&
(n = fp->_p - fp->_bf._base) > 0) {
/*
* Writing. Any buffered characters cause the
* position to be greater than that in the
* underlying object.
*/
if (pos > OFF_MAX - n) {
errno = EOVERFLOW;
return (1);
}
pos += n;
}
*offset = pos;
return (0);
}
diff --git a/lib/libc/stdio/funopen.c b/lib/libc/stdio/funopen.c
index 376721d33eb3..3b319c9df984 100644
--- a/lib/libc/stdio/funopen.c
+++ b/lib/libc/stdio/funopen.c
@@ -1,76 +1,75 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)funopen.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <errno.h>
#include "local.h"
FILE *
funopen(const void *cookie,
int (*readfn)(void *, char *, int),
int (*writefn)(void *, const char *, int),
fpos_t (*seekfn)(void *, fpos_t, int),
int (*closefn)(void *))
{
FILE *fp;
int flags;
if (readfn == NULL) {
if (writefn == NULL) { /* illegal */
errno = EINVAL;
return (NULL);
} else
flags = __SWR; /* write only */
} else {
if (writefn == NULL)
flags = __SRD; /* read only */
else
flags = __SRW; /* read-write */
}
if ((fp = __sfp()) == NULL)
return (NULL);
fp->_flags = flags;
fp->_file = -1;
fp->_cookie = (void *)cookie;
fp->_read = readfn;
fp->_write = writefn;
fp->_seek = seekfn;
fp->_close = closefn;
return (fp);
}
diff --git a/lib/libc/stdio/fvwrite.c b/lib/libc/stdio/fvwrite.c
index 81e7ba89a644..3bb2f3fb6d9c 100644
--- a/lib/libc/stdio/fvwrite.c
+++ b/lib/libc/stdio/fvwrite.c
@@ -1,215 +1,214 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fvwrite.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "local.h"
#include "fvwrite.h"
/*
* Write some memory regions. Return zero on success, EOF on error.
*
* This routine is large and unsightly, but most of the ugliness due
* to the three different kinds of output buffering is handled here.
*/
int
__sfvwrite(FILE *fp, struct __suio *uio)
{
size_t len;
unsigned char *old_p;
char *p;
struct __siov *iov;
int w, s;
char *nl;
int nlknown, nldist;
if (uio->uio_resid == 0)
return (0);
/* make sure we can write */
if (prepwrite(fp) != 0)
return (EOF);
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n))
iov = uio->uio_iov;
p = iov->iov_base;
len = iov->iov_len;
iov++;
#define GETIOV(extra_work) \
while (len == 0) { \
extra_work; \
p = iov->iov_base; \
len = iov->iov_len; \
iov++; \
}
if (fp->_flags & __SNBF) {
/*
* Unbuffered: write up to BUFSIZ bytes at a time.
*/
do {
GETIOV(;);
w = _swrite(fp, p, MIN(len, BUFSIZ));
if (w <= 0)
goto err;
p += w;
len -= w;
} while ((uio->uio_resid -= w) != 0);
} else if ((fp->_flags & __SLBF) == 0) {
/*
* Fully buffered: fill partially full buffer, if any,
* and then flush. If there is no partial buffer, write
* one _bf._size byte chunk directly (without copying).
*
* String output is a special case: write as many bytes
* as fit, but pretend we wrote everything. This makes
* snprintf() return the number of bytes needed, rather
* than the number used, and avoids its write function
* (so that the write function can be invalid).
*/
do {
GETIOV(;);
if ((fp->_flags & (__SALC | __SSTR)) ==
(__SALC | __SSTR) && fp->_w < len) {
size_t blen = fp->_p - fp->_bf._base;
/*
* Alloc an extra 128 bytes (+ 1 for NULL)
* so we don't call realloc(3) so often.
*/
fp->_w = len + 128;
fp->_bf._size = blen + len + 128;
fp->_bf._base =
reallocf(fp->_bf._base, fp->_bf._size + 1);
if (fp->_bf._base == NULL)
goto err;
fp->_p = fp->_bf._base + blen;
}
w = fp->_w;
if (fp->_flags & __SSTR) {
if (len < w)
w = len;
if (w > 0) {
COPY(w); /* copy MIN(fp->_w,len), */
fp->_w -= w;
fp->_p += w;
}
w = len; /* but pretend copied all */
} else if (fp->_p > fp->_bf._base && len > w) {
/* fill and flush */
COPY(w);
/* fp->_w -= w; */ /* unneeded */
fp->_p += w;
old_p = fp->_p;
if (__fflush(fp) == EOF) {
if (old_p == fp->_p && errno == EINTR)
fp->_p -= w;
goto err;
}
} else if (len >= (w = fp->_bf._size)) {
/* write directly */
w = _swrite(fp, p, w);
if (w <= 0)
goto err;
} else {
/* fill and done */
w = len;
COPY(w);
fp->_w -= w;
fp->_p += w;
}
p += w;
len -= w;
} while ((uio->uio_resid -= w) != 0);
} else {
/*
* Line buffered: like fully buffered, but we
* must check for newlines. Compute the distance
* to the first newline (including the newline),
* or `infinity' if there is none, then pretend
* that the amount to write is MIN(len,nldist).
*/
nlknown = 0;
nldist = 0; /* XXX just to keep gcc happy */
do {
GETIOV(nlknown = 0);
if (!nlknown) {
nl = memchr((void *)p, '\n', len);
nldist = nl ? nl + 1 - p : len + 1;
nlknown = 1;
}
s = MIN(len, nldist);
w = fp->_w + fp->_bf._size;
if (fp->_p > fp->_bf._base && s > w) {
COPY(w);
/* fp->_w -= w; */
fp->_p += w;
old_p = fp->_p;
if (__fflush(fp) == EOF) {
if (old_p == fp->_p && errno == EINTR)
fp->_p -= w;
goto err;
}
} else if (s >= (w = fp->_bf._size)) {
w = _swrite(fp, p, w);
if (w <= 0)
goto err;
} else {
w = s;
COPY(w);
fp->_w -= w;
fp->_p += w;
}
if ((nldist -= w) == 0) {
/* copied the newline: flush and forget */
if (__fflush(fp))
goto err;
nlknown = 0;
}
p += w;
len -= w;
} while ((uio->uio_resid -= w) != 0);
}
return (0);
err:
fp->_flags |= __SERR;
return (EOF);
}
diff --git a/lib/libc/stdio/fwalk.c b/lib/libc/stdio/fwalk.c
index 0e2c48234a75..b0b11777aef0 100644
--- a/lib/libc/stdio/fwalk.c
+++ b/lib/libc/stdio/fwalk.c
@@ -1,65 +1,64 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fwalk.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
#include "local.h"
#include "glue.h"
int
_fwalk(int (*function)(FILE *))
{
FILE *fp;
int n, ret;
struct glue *g;
ret = 0;
/*
* It should be safe to walk the list without locking it;
* new nodes are only added to the end and none are ever
* removed.
*
* Avoid locking this list while walking it or else you will
* introduce a potential deadlock in [at least] refill.c.
*/
for (g = &__sglue; g != NULL; g = g->next)
for (fp = g->iobs, n = g->niobs; --n >= 0; fp++)
if ((fp->_flags != 0) && ((fp->_flags & __SIGN) == 0))
ret |= (*function)(fp);
return (ret);
}
diff --git a/lib/libc/stdio/fwide.c b/lib/libc/stdio/fwide.c
index d413d4518d2a..86eb5b5299f8 100644
--- a/lib/libc/stdio/fwide.c
+++ b/lib/libc/stdio/fwide.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
int
fwide(FILE *fp, int mode)
{
int m;
FLOCKFILE(fp);
/* Only change the orientation if the stream is not oriented yet. */
if (mode != 0 && fp->_orientation == 0)
fp->_orientation = mode > 0 ? 1 : -1;
m = fp->_orientation;
FUNLOCKFILE(fp);
return (m);
}
diff --git a/lib/libc/stdio/fwprintf.c b/lib/libc/stdio/fwprintf.c
index 7550bb8eb69b..f2a28ad4b08a 100644
--- a/lib/libc/stdio/fwprintf.c
+++ b/lib/libc/stdio/fwprintf.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
fwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfwprintf(fp, fmt, ap);
va_end(ap);
return (ret);
}
int
fwprintf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfwprintf_l(fp, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/fwrite.c b/lib/libc/stdio/fwrite.c
index d0663c93a2a2..0004a5b9ffae 100644
--- a/lib/libc/stdio/fwrite.c
+++ b/lib/libc/stdio/fwrite.c
@@ -1,107 +1,106 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)fwrite.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include "un-namespace.h"
#include "local.h"
#include "fvwrite.h"
#include "libc_private.h"
/*
* Write `count' objects (each size `size') from memory to the given file.
* Return the number of whole objects written.
*/
size_t
fwrite_unlocked(const void * __restrict buf, size_t size, size_t count,
FILE * __restrict fp)
{
size_t n;
struct __suio uio;
struct __siov iov;
/*
* ANSI and SUSv2 require a return value of 0 if size or count are 0.
*/
if ((count == 0) || (size == 0))
return (0);
/*
* Check for integer overflow. As an optimization, first check that
* at least one of {count, size} is at least 2^16, since if both
* values are less than that, their product can't possibly overflow
* (size_t is always at least 32 bits on FreeBSD).
*/
if (((count | size) > 0xFFFF) &&
(count > SIZE_MAX / size)) {
errno = EINVAL;
fp->_flags |= __SERR;
return (0);
}
n = count * size;
iov.iov_base = (void *)buf;
uio.uio_resid = iov.iov_len = n;
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
ORIENT(fp, -1);
/*
* The usual case is success (__sfvwrite returns 0);
* skip the divide if this happens, since divides are
* generally slow and since this occurs whenever size==0.
*/
if (__sfvwrite(fp, &uio) != 0)
count = (n - uio.uio_resid) / size;
return (count);
}
size_t
fwrite(const void * __restrict buf, size_t size, size_t count,
FILE * __restrict fp)
{
size_t n;
FLOCKFILE_CANCELSAFE(fp);
n = fwrite_unlocked(buf, size, count, fp);
FUNLOCKFILE_CANCELSAFE();
return (n);
}
diff --git a/lib/libc/stdio/fwscanf.c b/lib/libc/stdio/fwscanf.c
index b0f2d02e748d..833a31a8f1b9 100644
--- a/lib/libc/stdio/fwscanf.c
+++ b/lib/libc/stdio/fwscanf.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
fwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vfwscanf(fp, fmt, ap);
va_end(ap);
return (r);
}
int
fwscanf_l(FILE * __restrict fp, locale_t locale, const wchar_t * __restrict fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vfwscanf_l(fp, locale, fmt, ap);
va_end(ap);
return (r);
}
diff --git a/lib/libc/stdio/getc.c b/lib/libc/stdio/getc.c
index 61fb4fe88c88..08cbbbcf15ed 100644
--- a/lib/libc/stdio/getc.c
+++ b/lib/libc/stdio/getc.c
@@ -1,65 +1,64 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getc.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#undef getc
#undef getc_unlocked
int
getc(FILE *fp)
{
int retval;
FLOCKFILE_CANCELSAFE(fp);
/* Orientation set by __sgetc() when buffer is empty. */
/* ORIENT(fp, -1); */
retval = __sgetc(fp);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
int
getc_unlocked(FILE *fp)
{
return (__sgetc(fp));
}
diff --git a/lib/libc/stdio/getchar.c b/lib/libc/stdio/getchar.c
index 197e135f8cbf..fef534812dbb 100644
--- a/lib/libc/stdio/getchar.c
+++ b/lib/libc/stdio/getchar.c
@@ -1,68 +1,67 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getchar.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* A subroutine version of the macro getchar.
*/
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
#undef getchar
#undef getchar_unlocked
int
getchar(void)
{
int retval;
FLOCKFILE_CANCELSAFE(stdin);
/* Orientation set by __sgetc() when buffer is empty. */
/* ORIENT(stdin, -1); */
retval = __sgetc(stdin);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
int
getchar_unlocked(void)
{
return (__sgetc(stdin));
}
diff --git a/lib/libc/stdio/getdelim.c b/lib/libc/stdio/getdelim.c
index 5a1a3cd3dfb8..7543fefc3a57 100644
--- a/lib/libc/stdio/getdelim.c
+++ b/lib/libc/stdio/getdelim.c
@@ -1,182 +1,181 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* Copyright (c) 2021 Dell EMC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
static inline size_t
p2roundup(size_t n)
{
if (!powerof2(n)) {
n--;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
#if SIZE_T_MAX > 0xffffffffU
n |= n >> 32;
#endif
n++;
}
return (n);
}
/*
* Expand *linep to hold len bytes (up to SSIZE_MAX + 1).
*/
static inline int
expandtofit(char ** __restrict linep, size_t len, size_t * __restrict capp)
{
char *newline;
size_t newcap;
if (len > (size_t)SSIZE_MAX + 1) {
errno = EOVERFLOW;
return (-1);
}
if (len > *capp) {
if (len == (size_t)SSIZE_MAX + 1) /* avoid overflow */
newcap = (size_t)SSIZE_MAX + 1;
else
newcap = p2roundup(len);
newline = realloc(*linep, newcap);
if (newline == NULL)
return (-1);
*capp = newcap;
*linep = newline;
}
return (0);
}
/*
* Append the src buffer to the *dstp buffer. The buffers are of
* length srclen and *dstlenp, respectively, and dst has space for
* *dstlenp bytes. After the call, *dstlenp and *dstcapp are updated
* appropriately, and *dstp is reallocated if needed. Returns 0 on
* success, -1 on allocation failure.
*/
static int
sappend(char ** __restrict dstp, size_t * __restrict dstlenp,
size_t * __restrict dstcapp, char * __restrict src, size_t srclen)
{
/* ensure room for srclen + dstlen + terminating NUL */
if (expandtofit(dstp, srclen + *dstlenp + 1, dstcapp))
return (-1);
memcpy(*dstp + *dstlenp, src, srclen);
*dstlenp += srclen;
return (0);
}
ssize_t
getdelim(char ** __restrict linep, size_t * __restrict linecapp, int delim,
FILE * __restrict fp)
{
u_char *endp;
size_t linelen;
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, -1);
if (linep == NULL || linecapp == NULL) {
errno = EINVAL;
goto error;
}
if (*linep == NULL)
*linecapp = 0;
if (fp->_r <= 0 && __srefill(fp)) {
/* If fp is at EOF already, we just need space for the NUL. */
if (!__sfeof(fp) || expandtofit(linep, 1, linecapp))
goto error;
(*linep)[0] = '\0';
linelen = -1;
goto end;
}
linelen = 0;
while ((endp = memchr(fp->_p, delim, fp->_r)) == NULL) {
if (sappend(linep, &linelen, linecapp, fp->_p, fp->_r))
goto error;
errno = 0;
if (__srefill(fp)) {
if (__sfeof(fp))
goto done;
if (errno == EAGAIN) {
/*
* We need to undo a partial read that has
* been placed into linep or we would otherwise
* lose it on the next read.
*/
while (linelen > 0) {
if (__ungetc((*linep)[--linelen],
fp) == EOF)
goto error;
}
/*
* This is not strictly needed but it is
* possible a consumer has worked around an
* older EAGAIN bug by buffering a partial
* return.
*/
(*linep)[0] = '\0';
}
goto error;
}
}
endp++; /* snarf the delimiter, too */
if (sappend(linep, &linelen, linecapp, fp->_p, endp - fp->_p))
goto error;
fp->_r -= endp - fp->_p;
fp->_p = endp;
done:
/* Invariant: *linep has space for at least linelen+1 bytes. */
(*linep)[linelen] = '\0';
end:
FUNLOCKFILE_CANCELSAFE();
return (linelen);
error:
fp->_flags |= __SERR;
linelen = -1;
goto end;
}
diff --git a/lib/libc/stdio/getline.c b/lib/libc/stdio/getline.c
index 7e62829ecf4c..371341d6ea8e 100644
--- a/lib/libc/stdio/getline.c
+++ b/lib/libc/stdio/getline.c
@@ -1,38 +1,37 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
ssize_t
getline(char ** __restrict linep, size_t * __restrict linecapp,
FILE * __restrict fp)
{
return (getdelim(linep, linecapp, '\n', fp));
}
diff --git a/lib/libc/stdio/gets.c b/lib/libc/stdio/gets.c
index 7f3e165f0bff..4babd64d0a00 100644
--- a/lib/libc/stdio/gets.c
+++ b/lib/libc/stdio/gets.c
@@ -1,77 +1,76 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)gets.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <unistd.h>
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
char *
__gets_unsafe(char *buf)
{
int c;
char *s, *ret;
static int warned;
static const char w[] =
"warning: this program uses gets(), which is unsafe.\n";
FLOCKFILE_CANCELSAFE(stdin);
ORIENT(stdin, -1);
if (!warned) {
(void) _write(STDERR_FILENO, w, sizeof(w) - 1);
warned = 1;
}
for (s = buf; (c = __sgetc(stdin)) != '\n'; ) {
if (c == EOF) {
if (s == buf) {
ret = NULL;
goto end;
} else
break;
} else
*s++ = c;
}
*s = 0;
ret = buf;
end:
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
__sym_compat(gets, __gets_unsafe, FBSD_1.0);
diff --git a/lib/libc/stdio/gets_s.c b/lib/libc/stdio/gets_s.c
index cf839f8abed9..9a8cf34916fb 100644
--- a/lib/libc/stdio/gets_s.c
+++ b/lib/libc/stdio/gets_s.c
@@ -1,100 +1,99 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2017, 2018
* Cyril S. E. Schubert
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <unistd.h>
#include <stdint.h>
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
static inline char *
_gets_s(char *buf, rsize_t n)
{
int c;
char *s;
ORIENT(stdin, -1);
for (s = buf, n--; (c = __sgetc(stdin)) != '\n' && n > 0 ; n--) {
if (c == EOF) {
if (s == buf) {
return (NULL);
} else
break;
} else
*s++ = c;
}
/*
* If end of buffer reached, discard until \n or eof.
* Then throw an error.
*/
if (n == 0) {
/* discard */
while ((c = __sgetc(stdin)) != '\n' && c != EOF);
/* throw the error after lock released prior to exit */
__throw_constraint_handler_s("gets_s : end of buffer", E2BIG);
return (NULL);
}
*s = 0;
return (buf);
}
/* ISO/IEC 9899:2011 K.3.7.4.1 */
char *
gets_s(char *buf, rsize_t n)
{
char *ret;
if (buf == NULL) {
__throw_constraint_handler_s("gets_s : str is NULL", EINVAL);
return(NULL);
} else if (n > RSIZE_MAX) {
__throw_constraint_handler_s("gets_s : n > RSIZE_MAX",
EINVAL);
return(NULL);
} else if (n == 0) {
__throw_constraint_handler_s("gets_s : n == 0", EINVAL);
return(NULL);
}
FLOCKFILE_CANCELSAFE(stdin);
ret = _gets_s(buf, n);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
diff --git a/lib/libc/stdio/getw.c b/lib/libc/stdio/getw.c
index f48395d7dc7c..634dbb3c74d0 100644
--- a/lib/libc/stdio/getw.c
+++ b/lib/libc/stdio/getw.c
@@ -1,47 +1,46 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getw.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
int
getw(FILE *fp)
{
int x;
return (fread((void *)&x, sizeof(x), 1, fp) == 1 ? x : EOF);
}
diff --git a/lib/libc/stdio/getwc.c b/lib/libc/stdio/getwc.c
index ccac10db228f..ae56ff7d6dd3 100644
--- a/lib/libc/stdio/getwc.c
+++ b/lib/libc/stdio/getwc.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#undef getwc
/*
* Synonym for fgetwc(). The only difference is that getwc(), if it is a
* macro, may evaluate `fp' more than once.
*/
wint_t
getwc(FILE *fp)
{
return (fgetwc(fp));
}
wint_t
getwc_l(FILE *fp, locale_t locale)
{
return (fgetwc_l(fp, locale));
}
diff --git a/lib/libc/stdio/getwchar.c b/lib/libc/stdio/getwchar.c
index 9294a952357e..335a975ba6e8 100644
--- a/lib/libc/stdio/getwchar.c
+++ b/lib/libc/stdio/getwchar.c
@@ -1,57 +1,56 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#undef getwchar
/*
* Synonym for fgetwc(stdin).
*/
wint_t
getwchar(void)
{
return (fgetwc(stdin));
}
wint_t
getwchar_l(locale_t locale)
{
return (fgetwc_l(stdin, locale));
}
diff --git a/lib/libc/stdio/makebuf.c b/lib/libc/stdio/makebuf.c
index f499651880ca..e1e85ab72a52 100644
--- a/lib/libc/stdio/makebuf.c
+++ b/lib/libc/stdio/makebuf.c
@@ -1,116 +1,115 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)makebuf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
/*
* Allocate a file buffer, or switch to unbuffered I/O.
* Per the ANSI C standard, ALL tty devices default to line buffered.
*
* As a side effect, we set __SOPT or __SNPT (en/dis-able fseek
* optimisation) right after the _fstat() that finds the buffer size.
*/
void
__smakebuf(FILE *fp)
{
void *p;
int flags;
size_t size;
int couldbetty;
if (fp->_flags & __SNBF) {
fp->_bf._base = fp->_p = fp->_nbuf;
fp->_bf._size = 1;
return;
}
flags = __swhatbuf(fp, &size, &couldbetty);
if ((p = malloc(size)) == NULL) {
fp->_flags |= __SNBF;
fp->_bf._base = fp->_p = fp->_nbuf;
fp->_bf._size = 1;
return;
}
__cleanup = _cleanup;
flags |= __SMBF;
fp->_bf._base = fp->_p = p;
fp->_bf._size = size;
if (couldbetty && isatty(fp->_file))
flags |= __SLBF;
fp->_flags |= flags;
}
/*
* Internal routine to determine `proper' buffering for a file.
*/
int
__swhatbuf(FILE *fp, size_t *bufsize, int *couldbetty)
{
struct stat st;
if (fp->_file < 0 || _fstat(fp->_file, &st) < 0) {
*couldbetty = 0;
*bufsize = BUFSIZ;
return (__SNPT);
}
/* could be a tty iff it is a character device */
*couldbetty = (st.st_mode & S_IFMT) == S_IFCHR;
if (st.st_blksize <= 0) {
*bufsize = BUFSIZ;
return (__SNPT);
}
/*
* Optimise fseek() only if it is a regular file. (The test for
* __sseek is mainly paranoia.) It is safe to set _blksize
* unconditionally; it will only be used if __SOPT is also set.
*/
*bufsize = st.st_blksize;
fp->_blksize = st.st_blksize;
return ((st.st_mode & S_IFMT) == S_IFREG && fp->_seek == __sseek ?
__SOPT : __SNPT);
}
diff --git a/lib/libc/stdio/mktemp.c b/lib/libc/stdio/mktemp.c
index bbefc2b28cfd..ca80e86fc60c 100644
--- a/lib/libc/stdio/mktemp.c
+++ b/lib/libc/stdio/mktemp.c
@@ -1,201 +1,200 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)mktemp.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <unistd.h>
#include "un-namespace.h"
char *_mktemp(char *);
static int _gettemp(int, char *, int *, int, int, int);
static const unsigned char padchar[] =
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
int
mkostempsat(int dfd, char *path, int slen, int oflags)
{
int fd;
return (_gettemp(dfd, path, &fd, 0, slen, oflags) ? fd : -1);
}
int
mkostemps(char *path, int slen, int oflags)
{
int fd;
return (_gettemp(AT_FDCWD, path, &fd, 0, slen, oflags) ? fd : -1);
}
int
mkstemps(char *path, int slen)
{
int fd;
return (_gettemp(AT_FDCWD, path, &fd, 0, slen, 0) ? fd : -1);
}
int
mkostemp(char *path, int oflags)
{
int fd;
return (_gettemp(AT_FDCWD, path, &fd, 0, 0, oflags) ? fd : -1);
}
int
mkstemp(char *path)
{
int fd;
return (_gettemp(AT_FDCWD, path, &fd, 0, 0, 0) ? fd : -1);
}
char *
mkdtemp(char *path)
{
return (_gettemp(AT_FDCWD, path, (int *)NULL, 1, 0, 0) ? path : (char *)NULL);
}
char *
_mktemp(char *path)
{
return (_gettemp(AT_FDCWD, path, (int *)NULL, 0, 0, 0) ? path : (char *)NULL);
}
__warn_references(mktemp,
"warning: mktemp() possibly used unsafely; consider using mkstemp()");
char *
mktemp(char *path)
{
return (_mktemp(path));
}
static int
_gettemp(int dfd, char *path, int *doopen, int domkdir, int slen, int oflags)
{
char *start, *trv, *suffp, *carryp;
char *pad;
struct stat sbuf;
uint32_t rand;
char carrybuf[MAXPATHLEN];
int saved;
if ((doopen != NULL && domkdir) || slen < 0 ||
(oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
O_CLOEXEC)) != 0) {
errno = EINVAL;
return (0);
}
trv = path + strlen(path);
if (trv - path >= MAXPATHLEN) {
errno = ENAMETOOLONG;
return (0);
}
trv -= slen;
suffp = trv;
--trv;
if (trv < path || NULL != strchr(suffp, '/')) {
errno = EINVAL;
return (0);
}
/* Fill space with random characters */
while (trv >= path && *trv == 'X') {
rand = arc4random_uniform(sizeof(padchar) - 1);
*trv-- = padchar[rand];
}
start = trv + 1;
saved = 0;
oflags |= O_CREAT | O_EXCL | O_RDWR;
for (;;) {
if (doopen) {
*doopen = _openat(dfd, path, oflags, 0600);
if (*doopen >= 0)
return (1);
if (errno != EEXIST)
return (0);
} else if (domkdir) {
if (mkdir(path, 0700) == 0)
return (1);
if (errno != EEXIST)
return (0);
} else if (lstat(path, &sbuf))
return (errno == ENOENT);
/* save first combination of random characters */
if (!saved) {
memcpy(carrybuf, start, suffp - start);
saved = 1;
}
/* If we have a collision, cycle through the space of filenames */
for (trv = start, carryp = carrybuf;;) {
/* have we tried all possible permutations? */
if (trv == suffp)
return (0); /* yes - exit with EEXIST */
pad = strchr(padchar, *trv);
if (pad == NULL) {
/* this should never happen */
errno = EIO;
return (0);
}
/* increment character */
*trv = (*++pad == '\0') ? padchar[0] : *pad;
/* carry to next position? */
if (*trv == *carryp) {
/* increment position and loop */
++trv;
++carryp;
} else {
/* try with new name */
break;
}
}
}
/*NOTREACHED*/
}
diff --git a/lib/libc/stdio/open_memstream.c b/lib/libc/stdio/open_memstream.c
index 7dabc737db8c..371022adf6b3 100644
--- a/lib/libc/stdio/open_memstream.c
+++ b/lib/libc/stdio/open_memstream.c
@@ -1,212 +1,211 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#ifdef DEBUG
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "un-namespace.h"
/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
#define FPOS_MAX OFF_MAX
struct memstream {
char **bufp;
size_t *sizep;
ssize_t len;
fpos_t offset;
};
static int
memstream_grow(struct memstream *ms, fpos_t newoff)
{
char *buf;
ssize_t newsize;
if (newoff < 0 || newoff >= SSIZE_MAX)
newsize = SSIZE_MAX - 1;
else
newsize = newoff;
if (newsize > ms->len) {
buf = realloc(*ms->bufp, newsize + 1);
if (buf != NULL) {
#ifdef DEBUG
fprintf(stderr, "MS: %p growing from %zd to %zd\n",
ms, ms->len, newsize);
#endif
memset(buf + ms->len + 1, 0, newsize - ms->len);
*ms->bufp = buf;
ms->len = newsize;
return (1);
}
return (0);
}
return (1);
}
static void
memstream_update(struct memstream *ms)
{
assert(ms->len >= 0 && ms->offset >= 0);
*ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
}
static int
memstream_write(void *cookie, const char *buf, int len)
{
struct memstream *ms;
ssize_t tocopy;
ms = cookie;
if (!memstream_grow(ms, ms->offset + len))
return (-1);
tocopy = ms->len - ms->offset;
if (len < tocopy)
tocopy = len;
memcpy(*ms->bufp + ms->offset, buf, tocopy);
ms->offset += tocopy;
memstream_update(ms);
#ifdef DEBUG
fprintf(stderr, "MS: write(%p, %d) = %zd\n", ms, len, tocopy);
#endif
return (tocopy);
}
static fpos_t
memstream_seek(void *cookie, fpos_t pos, int whence)
{
struct memstream *ms;
#ifdef DEBUG
fpos_t old;
#endif
ms = cookie;
#ifdef DEBUG
old = ms->offset;
#endif
switch (whence) {
case SEEK_SET:
/* _fseeko() checks for negative offsets. */
assert(pos >= 0);
ms->offset = pos;
break;
case SEEK_CUR:
/* This is only called by _ftello(). */
assert(pos == 0);
break;
case SEEK_END:
if (pos < 0) {
if (pos + ms->len < 0) {
#ifdef DEBUG
fprintf(stderr,
"MS: bad SEEK_END: pos %jd, len %zd\n",
(intmax_t)pos, ms->len);
#endif
errno = EINVAL;
return (-1);
}
} else {
if (FPOS_MAX - ms->len < pos) {
#ifdef DEBUG
fprintf(stderr,
"MS: bad SEEK_END: pos %jd, len %zd\n",
(intmax_t)pos, ms->len);
#endif
errno = EOVERFLOW;
return (-1);
}
}
ms->offset = ms->len + pos;
break;
}
memstream_update(ms);
#ifdef DEBUG
fprintf(stderr, "MS: seek(%p, %jd, %d) %jd -> %jd\n", ms, (intmax_t)pos,
whence, (intmax_t)old, (intmax_t)ms->offset);
#endif
return (ms->offset);
}
static int
memstream_close(void *cookie)
{
free(cookie);
return (0);
}
FILE *
open_memstream(char **bufp, size_t *sizep)
{
struct memstream *ms;
int save_errno;
FILE *fp;
if (bufp == NULL || sizep == NULL) {
errno = EINVAL;
return (NULL);
}
*bufp = calloc(1, 1);
if (*bufp == NULL)
return (NULL);
ms = malloc(sizeof(*ms));
if (ms == NULL) {
save_errno = errno;
free(*bufp);
*bufp = NULL;
errno = save_errno;
return (NULL);
}
ms->bufp = bufp;
ms->sizep = sizep;
ms->len = 0;
ms->offset = 0;
memstream_update(ms);
fp = funopen(ms, NULL, memstream_write, memstream_seek,
memstream_close);
if (fp == NULL) {
save_errno = errno;
free(ms);
free(*bufp);
*bufp = NULL;
errno = save_errno;
return (NULL);
}
fwide(fp, -1);
return (fp);
}
diff --git a/lib/libc/stdio/open_wmemstream.c b/lib/libc/stdio/open_wmemstream.c
index bc746ebf8073..213d61fcd4dd 100644
--- a/lib/libc/stdio/open_wmemstream.c
+++ b/lib/libc/stdio/open_wmemstream.c
@@ -1,274 +1,273 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#ifdef DEBUG
#include <stdint.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "un-namespace.h"
/* XXX: There is no FPOS_MAX. This assumes fpos_t is an off_t. */
#define FPOS_MAX OFF_MAX
struct wmemstream {
wchar_t **bufp;
size_t *sizep;
ssize_t len;
fpos_t offset;
mbstate_t mbstate;
};
static int
wmemstream_grow(struct wmemstream *ms, fpos_t newoff)
{
wchar_t *buf;
ssize_t newsize;
if (newoff < 0 || newoff >= SSIZE_MAX / sizeof(wchar_t))
newsize = SSIZE_MAX / sizeof(wchar_t) - 1;
else
newsize = newoff;
if (newsize > ms->len) {
buf = reallocarray(*ms->bufp, newsize + 1, sizeof(wchar_t));
if (buf != NULL) {
#ifdef DEBUG
fprintf(stderr, "WMS: %p growing from %zd to %zd\n",
ms, ms->len, newsize);
#endif
wmemset(buf + ms->len + 1, 0, newsize - ms->len);
*ms->bufp = buf;
ms->len = newsize;
return (1);
}
return (0);
}
return (1);
}
static void
wmemstream_update(struct wmemstream *ms)
{
assert(ms->len >= 0 && ms->offset >= 0);
*ms->sizep = ms->len < ms->offset ? ms->len : ms->offset;
}
/*
* Based on a starting multibyte state and an input buffer, determine
* how many wchar_t's would be output. This doesn't use mbsnrtowcs()
* so that it can handle embedded null characters.
*/
static size_t
wbuflen(const mbstate_t *state, const char *buf, int len)
{
mbstate_t lenstate;
size_t charlen, count;
count = 0;
lenstate = *state;
while (len > 0) {
charlen = mbrlen(buf, len, &lenstate);
if (charlen == (size_t)-1)
return (-1);
if (charlen == (size_t)-2)
break;
if (charlen == 0)
/* XXX: Not sure how else to handle this. */
charlen = 1;
len -= charlen;
buf += charlen;
count++;
}
return (count);
}
static int
wmemstream_write(void *cookie, const char *buf, int len)
{
struct wmemstream *ms;
ssize_t consumed, wlen;
size_t charlen;
ms = cookie;
wlen = wbuflen(&ms->mbstate, buf, len);
if (wlen < 0) {
errno = EILSEQ;
return (-1);
}
if (!wmemstream_grow(ms, ms->offset + wlen))
return (-1);
/*
* This copies characters one at a time rather than using
* mbsnrtowcs() so it can properly handle embedded null
* characters.
*/
consumed = 0;
while (len > 0 && ms->offset < ms->len) {
charlen = mbrtowc(*ms->bufp + ms->offset, buf, len,
&ms->mbstate);
if (charlen == (size_t)-1) {
if (consumed == 0) {
errno = EILSEQ;
return (-1);
}
/* Treat it as a successful short write. */
break;
}
if (charlen == 0)
/* XXX: Not sure how else to handle this. */
charlen = 1;
if (charlen == (size_t)-2) {
consumed += len;
len = 0;
} else {
consumed += charlen;
buf += charlen;
len -= charlen;
ms->offset++;
}
}
wmemstream_update(ms);
#ifdef DEBUG
fprintf(stderr, "WMS: write(%p, %d) = %zd\n", ms, len, consumed);
#endif
return (consumed);
}
static fpos_t
wmemstream_seek(void *cookie, fpos_t pos, int whence)
{
struct wmemstream *ms;
fpos_t old;
ms = cookie;
old = ms->offset;
switch (whence) {
case SEEK_SET:
/* _fseeko() checks for negative offsets. */
assert(pos >= 0);
ms->offset = pos;
break;
case SEEK_CUR:
/* This is only called by _ftello(). */
assert(pos == 0);
break;
case SEEK_END:
if (pos < 0) {
if (pos + ms->len < 0) {
#ifdef DEBUG
fprintf(stderr,
"WMS: bad SEEK_END: pos %jd, len %zd\n",
(intmax_t)pos, ms->len);
#endif
errno = EINVAL;
return (-1);
}
} else {
if (FPOS_MAX - ms->len < pos) {
#ifdef DEBUG
fprintf(stderr,
"WMS: bad SEEK_END: pos %jd, len %zd\n",
(intmax_t)pos, ms->len);
#endif
errno = EOVERFLOW;
return (-1);
}
}
ms->offset = ms->len + pos;
break;
}
/* Reset the multibyte state if a seek changes the position. */
if (ms->offset != old)
memset(&ms->mbstate, 0, sizeof(ms->mbstate));
wmemstream_update(ms);
#ifdef DEBUG
fprintf(stderr, "WMS: seek(%p, %jd, %d) %jd -> %jd\n", ms,
(intmax_t)pos, whence, (intmax_t)old, (intmax_t)ms->offset);
#endif
return (ms->offset);
}
static int
wmemstream_close(void *cookie)
{
free(cookie);
return (0);
}
FILE *
open_wmemstream(wchar_t **bufp, size_t *sizep)
{
struct wmemstream *ms;
int save_errno;
FILE *fp;
if (bufp == NULL || sizep == NULL) {
errno = EINVAL;
return (NULL);
}
*bufp = calloc(1, sizeof(wchar_t));
if (*bufp == NULL)
return (NULL);
ms = malloc(sizeof(*ms));
if (ms == NULL) {
save_errno = errno;
free(*bufp);
*bufp = NULL;
errno = save_errno;
return (NULL);
}
ms->bufp = bufp;
ms->sizep = sizep;
ms->len = 0;
ms->offset = 0;
memset(&ms->mbstate, 0, sizeof(mbstate_t));
wmemstream_update(ms);
fp = funopen(ms, NULL, wmemstream_write, wmemstream_seek,
wmemstream_close);
if (fp == NULL) {
save_errno = errno;
free(ms);
free(*bufp);
*bufp = NULL;
errno = save_errno;
return (NULL);
}
fwide(fp, 1);
return (fp);
}
diff --git a/lib/libc/stdio/perror.c b/lib/libc/stdio/perror.c
index a16820f83b26..7f154b52b73f 100644
--- a/lib/libc/stdio/perror.c
+++ b/lib/libc/stdio/perror.c
@@ -1,75 +1,74 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)perror.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
void
perror(const char *s)
{
char msgbuf[NL_TEXTMAX];
struct iovec *v;
struct iovec iov[4];
v = iov;
if (s != NULL && *s != '\0') {
v->iov_base = (char *)s;
v->iov_len = strlen(s);
v++;
v->iov_base = ": ";
v->iov_len = 2;
v++;
}
strerror_r(errno, msgbuf, sizeof(msgbuf));
v->iov_base = msgbuf;
v->iov_len = strlen(v->iov_base);
v++;
v->iov_base = "\n";
v->iov_len = 1;
FLOCKFILE_CANCELSAFE(stderr);
__sflush(stderr);
(void)_writev(stderr->_file, iov, (v - iov) + 1);
stderr->_flags &= ~__SOFF;
FUNLOCKFILE_CANCELSAFE();
}
diff --git a/lib/libc/stdio/printf-pos.c b/lib/libc/stdio/printf-pos.c
index 534ac9cd4b78..77a1218ccd91 100644
--- a/lib/libc/stdio/printf-pos.c
+++ b/lib/libc/stdio/printf-pos.c
@@ -1,774 +1,773 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* This is the code responsible for handling positional arguments
* (%m$ and %m$.n$) for vfprintf() and vfwprintf().
*/
#include "namespace.h"
#include <sys/types.h>
#include <limits.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "un-namespace.h"
#include "printflocal.h"
#ifdef NL_ARGMAX
#define MAX_POSARG NL_ARGMAX
#else
#define MAX_POSARG 65536
#endif
/*
* Type ids for argument type table.
*/
enum typeid {
T_UNUSED, TP_SHORT, T_INT, T_U_INT, TP_INT,
T_LONG, T_U_LONG, TP_LONG, T_LLONG, T_U_LLONG, TP_LLONG,
T_PTRDIFFT, TP_PTRDIFFT, T_SSIZET, T_SIZET, TP_SSIZET,
T_INTMAXT, T_UINTMAXT, TP_INTMAXT, TP_VOID, TP_CHAR, TP_SCHAR,
T_DOUBLE, T_LONG_DOUBLE, T_WINT, TP_WCHAR
};
/* An expandable array of types. */
struct typetable {
enum typeid *table; /* table of types */
enum typeid stattable[STATIC_ARG_TBL_SIZE];
u_int tablesize; /* current size of type table */
u_int tablemax; /* largest used index in table */
u_int nextarg; /* 1-based argument index */
};
static int __grow_type_table(struct typetable *);
static void build_arg_table (struct typetable *, va_list, union arg **);
/*
* Initialize a struct typetable.
*/
static inline void
inittypes(struct typetable *types)
{
u_int n;
types->table = types->stattable;
types->tablesize = STATIC_ARG_TBL_SIZE;
types->tablemax = 0;
types->nextarg = 1;
for (n = 0; n < STATIC_ARG_TBL_SIZE; n++)
types->table[n] = T_UNUSED;
}
/*
* struct typetable destructor.
*/
static inline void
freetypes(struct typetable *types)
{
if (types->table != types->stattable)
free (types->table);
}
/*
* Ensure that there is space to add a new argument type to the type table.
* Expand the table if necessary. Returns 0 on success.
*/
static inline int
_ensurespace(struct typetable *types)
{
if (types->nextarg >= types->tablesize) {
if (__grow_type_table(types))
return (-1);
}
if (types->nextarg > types->tablemax)
types->tablemax = types->nextarg;
return (0);
}
/*
* Add an argument type to the table, expanding if necessary.
* Returns 0 on success.
*/
static inline int
addtype(struct typetable *types, enum typeid type)
{
if (_ensurespace(types))
return (-1);
types->table[types->nextarg++] = type;
return (0);
}
static inline int
addsarg(struct typetable *types, int flags)
{
if (_ensurespace(types))
return (-1);
if (flags & INTMAXT)
types->table[types->nextarg++] = T_INTMAXT;
else if (flags & SIZET)
types->table[types->nextarg++] = T_SSIZET;
else if (flags & PTRDIFFT)
types->table[types->nextarg++] = T_PTRDIFFT;
else if (flags & LLONGINT)
types->table[types->nextarg++] = T_LLONG;
else if (flags & LONGINT)
types->table[types->nextarg++] = T_LONG;
else
types->table[types->nextarg++] = T_INT;
return (0);
}
static inline int
adduarg(struct typetable *types, int flags)
{
if (_ensurespace(types))
return (-1);
if (flags & INTMAXT)
types->table[types->nextarg++] = T_UINTMAXT;
else if (flags & SIZET)
types->table[types->nextarg++] = T_SIZET;
else if (flags & PTRDIFFT)
types->table[types->nextarg++] = T_SIZET;
else if (flags & LLONGINT)
types->table[types->nextarg++] = T_U_LLONG;
else if (flags & LONGINT)
types->table[types->nextarg++] = T_U_LONG;
else
types->table[types->nextarg++] = T_U_INT;
return (0);
}
/*
* Add * arguments to the type array.
*/
static inline int
addaster(struct typetable *types, char **fmtp)
{
char *cp;
u_int n2;
n2 = 0;
cp = *fmtp;
while (is_digit(*cp)) {
n2 = 10 * n2 + to_digit(*cp);
cp++;
}
if (*cp == '$') {
u_int hold = types->nextarg;
types->nextarg = n2;
if (addtype(types, T_INT))
return (-1);
types->nextarg = hold;
*fmtp = ++cp;
} else {
if (addtype(types, T_INT))
return (-1);
}
return (0);
}
static inline int
addwaster(struct typetable *types, wchar_t **fmtp)
{
wchar_t *cp;
u_int n2;
n2 = 0;
cp = *fmtp;
while (is_digit(*cp)) {
n2 = 10 * n2 + to_digit(*cp);
cp++;
}
if (*cp == '$') {
u_int hold = types->nextarg;
types->nextarg = n2;
if (addtype(types, T_INT))
return (-1);
types->nextarg = hold;
*fmtp = ++cp;
} else {
if (addtype(types, T_INT))
return (-1);
}
return (0);
}
/*
* Find all arguments when a positional parameter is encountered. Returns a
* table, indexed by argument number, of pointers to each arguments. The
* initial argument table should be an array of STATIC_ARG_TBL_SIZE entries.
* It will be replaces with a malloc-ed one if it overflows.
* Returns 0 on success. On failure, returns nonzero and sets errno.
*/
int
__find_arguments (const char *fmt0, va_list ap, union arg **argtable)
{
char *fmt; /* format string */
int ch; /* character from fmt */
u_int n; /* handy integer (short term usage) */
int error;
int flags; /* flags as above */
struct typetable types; /* table of types */
fmt = (char *)fmt0;
inittypes(&types);
error = 0;
/*
* Scan the format for conversions (`%' character).
*/
for (;;) {
while ((ch = *fmt) != '\0' && ch != '%')
fmt++;
if (ch == '\0')
goto done;
fmt++; /* skip over '%' */
flags = 0;
rflag: ch = *fmt++;
reswitch: switch (ch) {
case ' ':
case '#':
goto rflag;
case '*':
if ((error = addaster(&types, &fmt)))
goto error;
goto rflag;
case '-':
case '+':
case '\'':
goto rflag;
case '.':
if ((ch = *fmt++) == '*') {
if ((error = addaster(&types, &fmt)))
goto error;
goto rflag;
}
while (is_digit(ch)) {
ch = *fmt++;
}
goto reswitch;
case '0':
goto rflag;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do {
n = 10 * n + to_digit(ch);
/* Detect overflow */
if (n > MAX_POSARG) {
error = -1;
goto error;
}
ch = *fmt++;
} while (is_digit(ch));
if (ch == '$') {
types.nextarg = n;
goto rflag;
}
goto reswitch;
#ifndef NO_FLOATING_POINT
case 'L':
flags |= LONGDBL;
goto rflag;
#endif
case 'h':
if (flags & SHORTINT) {
flags &= ~SHORTINT;
flags |= CHARINT;
} else
flags |= SHORTINT;
goto rflag;
case 'j':
flags |= INTMAXT;
goto rflag;
case 'l':
if (flags & LONGINT) {
flags &= ~LONGINT;
flags |= LLONGINT;
} else
flags |= LONGINT;
goto rflag;
case 'q':
flags |= LLONGINT; /* not necessarily */
goto rflag;
case 't':
flags |= PTRDIFFT;
goto rflag;
case 'z':
flags |= SIZET;
goto rflag;
case 'C':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'c':
error = addtype(&types,
(flags & LONGINT) ? T_WINT : T_INT);
if (error)
goto error;
break;
case 'D':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'd':
case 'i':
if ((error = addsarg(&types, flags)))
goto error;
break;
#ifndef NO_FLOATING_POINT
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
error = addtype(&types,
(flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
if (error)
goto error;
break;
#endif /* !NO_FLOATING_POINT */
case 'n':
if (flags & INTMAXT)
error = addtype(&types, TP_INTMAXT);
else if (flags & PTRDIFFT)
error = addtype(&types, TP_PTRDIFFT);
else if (flags & SIZET)
error = addtype(&types, TP_SSIZET);
else if (flags & LLONGINT)
error = addtype(&types, TP_LLONG);
else if (flags & LONGINT)
error = addtype(&types, TP_LONG);
else if (flags & SHORTINT)
error = addtype(&types, TP_SHORT);
else if (flags & CHARINT)
error = addtype(&types, TP_SCHAR);
else
error = addtype(&types, TP_INT);
if (error)
goto error;
continue; /* no output */
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
if ((error = adduarg(&types, flags)))
goto error;
break;
case 'p':
if ((error = addtype(&types, TP_VOID)))
goto error;
break;
case 'S':
flags |= LONGINT;
/*FALLTHROUGH*/
case 's':
error = addtype(&types,
(flags & LONGINT) ? TP_WCHAR : TP_CHAR);
if (error)
goto error;
break;
case 'U':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'u':
case 'X':
case 'x':
if ((error = adduarg(&types, flags)))
goto error;
break;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
goto done;
break;
}
}
done:
build_arg_table(&types, ap, argtable);
error:
freetypes(&types);
return (error || *argtable == NULL);
}
/* wchar version of __find_arguments. */
int
__find_warguments (const wchar_t *fmt0, va_list ap, union arg **argtable)
{
wchar_t *fmt; /* format string */
wchar_t ch; /* character from fmt */
u_int n; /* handy integer (short term usage) */
int error;
int flags; /* flags as above */
struct typetable types; /* table of types */
fmt = (wchar_t *)fmt0;
inittypes(&types);
error = 0;
/*
* Scan the format for conversions (`%' character).
*/
for (;;) {
while ((ch = *fmt) != '\0' && ch != '%')
fmt++;
if (ch == '\0')
goto done;
fmt++; /* skip over '%' */
flags = 0;
rflag: ch = *fmt++;
reswitch: switch (ch) {
case ' ':
case '#':
goto rflag;
case '*':
if ((error = addwaster(&types, &fmt)))
goto error;
goto rflag;
case '-':
case '+':
case '\'':
goto rflag;
case '.':
if ((ch = *fmt++) == '*') {
if ((error = addwaster(&types, &fmt)))
goto error;
goto rflag;
}
while (is_digit(ch)) {
ch = *fmt++;
}
goto reswitch;
case '0':
goto rflag;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do {
n = 10 * n + to_digit(ch);
/* Detect overflow */
if (n > MAX_POSARG) {
error = -1;
goto error;
}
ch = *fmt++;
} while (is_digit(ch));
if (ch == '$') {
types.nextarg = n;
goto rflag;
}
goto reswitch;
#ifndef NO_FLOATING_POINT
case 'L':
flags |= LONGDBL;
goto rflag;
#endif
case 'h':
if (flags & SHORTINT) {
flags &= ~SHORTINT;
flags |= CHARINT;
} else
flags |= SHORTINT;
goto rflag;
case 'j':
flags |= INTMAXT;
goto rflag;
case 'l':
if (flags & LONGINT) {
flags &= ~LONGINT;
flags |= LLONGINT;
} else
flags |= LONGINT;
goto rflag;
case 'q':
flags |= LLONGINT; /* not necessarily */
goto rflag;
case 't':
flags |= PTRDIFFT;
goto rflag;
case 'z':
flags |= SIZET;
goto rflag;
case 'C':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'c':
error = addtype(&types,
(flags & LONGINT) ? T_WINT : T_INT);
if (error)
goto error;
break;
case 'D':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'd':
case 'i':
if ((error = addsarg(&types, flags)))
goto error;
break;
#ifndef NO_FLOATING_POINT
case 'a':
case 'A':
case 'e':
case 'E':
case 'f':
case 'g':
case 'G':
error = addtype(&types,
(flags & LONGDBL) ? T_LONG_DOUBLE : T_DOUBLE);
if (error)
goto error;
break;
#endif /* !NO_FLOATING_POINT */
case 'n':
if (flags & INTMAXT)
error = addtype(&types, TP_INTMAXT);
else if (flags & PTRDIFFT)
error = addtype(&types, TP_PTRDIFFT);
else if (flags & SIZET)
error = addtype(&types, TP_SSIZET);
else if (flags & LLONGINT)
error = addtype(&types, TP_LLONG);
else if (flags & LONGINT)
error = addtype(&types, TP_LONG);
else if (flags & SHORTINT)
error = addtype(&types, TP_SHORT);
else if (flags & CHARINT)
error = addtype(&types, TP_SCHAR);
else
error = addtype(&types, TP_INT);
if (error)
goto error;
continue; /* no output */
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
if ((error = adduarg(&types, flags)))
goto error;
break;
case 'p':
if ((error = addtype(&types, TP_VOID)))
goto error;
break;
case 'S':
flags |= LONGINT;
/*FALLTHROUGH*/
case 's':
error = addtype(&types,
(flags & LONGINT) ? TP_WCHAR : TP_CHAR);
if (error)
goto error;
break;
case 'U':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'u':
case 'X':
case 'x':
if ((error = adduarg(&types, flags)))
goto error;
break;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
goto done;
break;
}
}
done:
build_arg_table(&types, ap, argtable);
error:
freetypes(&types);
return (error || *argtable == NULL);
}
/*
* Increase the size of the type table. Returns 0 on success.
*/
static int
__grow_type_table(struct typetable *types)
{
enum typeid *const oldtable = types->table;
const int oldsize = types->tablesize;
enum typeid *newtable;
u_int n, newsize;
/* Detect overflow */
if (types->nextarg > NL_ARGMAX)
return (-1);
newsize = oldsize * 2;
if (newsize < types->nextarg + 1)
newsize = types->nextarg + 1;
if (oldsize == STATIC_ARG_TBL_SIZE) {
if ((newtable = malloc(newsize * sizeof(enum typeid))) == NULL)
return (-1);
bcopy(oldtable, newtable, oldsize * sizeof(enum typeid));
} else {
newtable = reallocarray(oldtable, newsize, sizeof(enum typeid));
if (newtable == NULL)
return (-1);
}
for (n = oldsize; n < newsize; n++)
newtable[n] = T_UNUSED;
types->table = newtable;
types->tablesize = newsize;
return (0);
}
/*
* Build the argument table from the completed type table.
* On malloc failure, *argtable is set to NULL.
*/
static void
build_arg_table(struct typetable *types, va_list ap, union arg **argtable)
{
u_int n;
if (types->tablemax >= STATIC_ARG_TBL_SIZE) {
*argtable = (union arg *)
malloc (sizeof (union arg) * (types->tablemax + 1));
if (*argtable == NULL)
return;
}
(*argtable) [0].intarg = 0;
for (n = 1; n <= types->tablemax; n++) {
switch (types->table[n]) {
case T_UNUSED: /* whoops! */
(*argtable) [n].intarg = va_arg (ap, int);
break;
case TP_SCHAR:
(*argtable) [n].pschararg = va_arg (ap, signed char *);
break;
case TP_SHORT:
(*argtable) [n].pshortarg = va_arg (ap, short *);
break;
case T_INT:
(*argtable) [n].intarg = va_arg (ap, int);
break;
case T_U_INT:
(*argtable) [n].uintarg = va_arg (ap, unsigned int);
break;
case TP_INT:
(*argtable) [n].pintarg = va_arg (ap, int *);
break;
case T_LONG:
(*argtable) [n].longarg = va_arg (ap, long);
break;
case T_U_LONG:
(*argtable) [n].ulongarg = va_arg (ap, unsigned long);
break;
case TP_LONG:
(*argtable) [n].plongarg = va_arg (ap, long *);
break;
case T_LLONG:
(*argtable) [n].longlongarg = va_arg (ap, long long);
break;
case T_U_LLONG:
(*argtable) [n].ulonglongarg = va_arg (ap, unsigned long long);
break;
case TP_LLONG:
(*argtable) [n].plonglongarg = va_arg (ap, long long *);
break;
case T_PTRDIFFT:
(*argtable) [n].ptrdiffarg = va_arg (ap, ptrdiff_t);
break;
case TP_PTRDIFFT:
(*argtable) [n].pptrdiffarg = va_arg (ap, ptrdiff_t *);
break;
case T_SIZET:
(*argtable) [n].sizearg = va_arg (ap, size_t);
break;
case T_SSIZET:
(*argtable) [n].sizearg = va_arg (ap, ssize_t);
break;
case TP_SSIZET:
(*argtable) [n].pssizearg = va_arg (ap, ssize_t *);
break;
case T_INTMAXT:
(*argtable) [n].intmaxarg = va_arg (ap, intmax_t);
break;
case T_UINTMAXT:
(*argtable) [n].uintmaxarg = va_arg (ap, uintmax_t);
break;
case TP_INTMAXT:
(*argtable) [n].pintmaxarg = va_arg (ap, intmax_t *);
break;
case T_DOUBLE:
#ifndef NO_FLOATING_POINT
(*argtable) [n].doublearg = va_arg (ap, double);
#endif
break;
case T_LONG_DOUBLE:
#ifndef NO_FLOATING_POINT
(*argtable) [n].longdoublearg = va_arg (ap, long double);
#endif
break;
case TP_CHAR:
(*argtable) [n].pchararg = va_arg (ap, char *);
break;
case TP_VOID:
(*argtable) [n].pvoidarg = va_arg (ap, void *);
break;
case T_WINT:
(*argtable) [n].wintarg = va_arg (ap, wint_t);
break;
case TP_WCHAR:
(*argtable) [n].pwchararg = va_arg (ap, wchar_t *);
break;
}
}
}
diff --git a/lib/libc/stdio/printf.c b/lib/libc/stdio/printf.c
index 20e5b7b0e3cd..ce6c1b147efd 100644
--- a/lib/libc/stdio/printf.c
+++ b/lib/libc/stdio/printf.c
@@ -1,69 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)printf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdarg.h>
#include <xlocale.h>
int
printf(char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf(stdout, fmt, ap);
va_end(ap);
return (ret);
}
int
printf_l(locale_t locale, char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfprintf_l(stdout, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/putc.c b/lib/libc/stdio/putc.c
index 54735da59527..9e708e733ac2 100644
--- a/lib/libc/stdio/putc.c
+++ b/lib/libc/stdio/putc.c
@@ -1,65 +1,64 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)putc.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
#undef putc
#undef putc_unlocked
int
putc(int c, FILE *fp)
{
int retval;
FLOCKFILE_CANCELSAFE(fp);
/* Orientation set by __sputc() when buffer is full. */
/* ORIENT(fp, -1); */
retval = __sputc(c, fp);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
int
putc_unlocked(int ch, FILE *fp)
{
return (__sputc(ch, fp));
}
diff --git a/lib/libc/stdio/putchar.c b/lib/libc/stdio/putchar.c
index dd8ea0271b94..44e2907993e0 100644
--- a/lib/libc/stdio/putchar.c
+++ b/lib/libc/stdio/putchar.c
@@ -1,70 +1,69 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)putchar.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
#undef putchar
#undef putchar_unlocked
/*
* A subroutine version of the macro putchar
*/
int
putchar(int c)
{
int retval;
FILE *so = stdout;
FLOCKFILE_CANCELSAFE(so);
/* Orientation set by __sputc() when buffer is full. */
/* ORIENT(so, -1); */
retval = __sputc(c, so);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
int
putchar_unlocked(int ch)
{
return (__sputc(ch, stdout));
}
diff --git a/lib/libc/stdio/puts.c b/lib/libc/stdio/puts.c
index b97807fe1255..61138b85755b 100644
--- a/lib/libc/stdio/puts.c
+++ b/lib/libc/stdio/puts.c
@@ -1,70 +1,69 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)puts.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <string.h>
#include "un-namespace.h"
#include "fvwrite.h"
#include "libc_private.h"
#include "local.h"
/*
* Write the given string to stdout, appending a newline.
*/
int
puts(char const *s)
{
int retval;
size_t c;
struct __suio uio;
struct __siov iov[2];
iov[0].iov_base = (void *)s;
iov[0].iov_len = c = strlen(s);
iov[1].iov_base = "\n";
iov[1].iov_len = 1;
uio.uio_resid = c + 1;
uio.uio_iov = &iov[0];
uio.uio_iovcnt = 2;
FLOCKFILE_CANCELSAFE(stdout);
ORIENT(stdout, -1);
retval = __sfvwrite(stdout, &uio) ? EOF : '\n';
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
diff --git a/lib/libc/stdio/putw.c b/lib/libc/stdio/putw.c
index 7e7c87c99ba2..9f77829bb18b 100644
--- a/lib/libc/stdio/putw.c
+++ b/lib/libc/stdio/putw.c
@@ -1,61 +1,60 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)putw.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "fvwrite.h"
#include "libc_private.h"
#include "local.h"
int
putw(int w, FILE *fp)
{
int retval;
struct __suio uio;
struct __siov iov;
iov.iov_base = &w;
uio.uio_resid = iov.iov_len = sizeof(w);
uio.uio_iov = &iov;
uio.uio_iovcnt = 1;
FLOCKFILE_CANCELSAFE(fp);
retval = __sfvwrite(fp, &uio);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
diff --git a/lib/libc/stdio/putwc.c b/lib/libc/stdio/putwc.c
index 386023924440..435da69dec6a 100644
--- a/lib/libc/stdio/putwc.c
+++ b/lib/libc/stdio/putwc.c
@@ -1,59 +1,58 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
#undef putwc
/*
* Synonym for fputwc(). The only difference is that putwc(), if it is a
* macro, may evaluate `fp' more than once.
*/
wint_t
putwc_l(wchar_t wc, FILE *fp, locale_t locale)
{
FIX_LOCALE(locale);
return (fputwc_l(wc, fp, locale));
}
wint_t
putwc(wchar_t wc, FILE *fp)
{
return putwc_l(wc, fp, __get_locale());
}
diff --git a/lib/libc/stdio/putwchar.c b/lib/libc/stdio/putwchar.c
index 1c5ab256125a..f109a5f6b1dd 100644
--- a/lib/libc/stdio/putwchar.c
+++ b/lib/libc/stdio/putwchar.c
@@ -1,58 +1,57 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
#undef putwchar
/*
* Synonym for fputwc(wc, stdout).
*/
wint_t
putwchar_l(wchar_t wc, locale_t locale)
{
FIX_LOCALE(locale);
return (fputwc_l(wc, stdout, locale));
}
wint_t
putwchar(wchar_t wc)
{
return putwchar_l(wc, __get_locale());
}
diff --git a/lib/libc/stdio/refill.c b/lib/libc/stdio/refill.c
index afc0526441aa..5d1db43d7681 100644
--- a/lib/libc/stdio/refill.c
+++ b/lib/libc/stdio/refill.c
@@ -1,146 +1,145 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)refill.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
static int lflush(FILE *);
static int
lflush(FILE *fp)
{
int ret = 0;
if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR)) {
FLOCKFILE_CANCELSAFE(fp);
ret = __sflush(fp);
FUNLOCKFILE_CANCELSAFE();
}
return (ret);
}
/*
* Refill a stdio buffer.
* Return EOF on eof or error, 0 otherwise.
*/
int
__srefill(FILE *fp)
{
/* make sure stdio is set up */
if (!__sdidinit)
__sinit();
ORIENT(fp, -1);
fp->_r = 0; /* largely a convenience for callers */
/* SysV does not make this test; take it out for compatibility */
if (fp->_flags & __SEOF)
return (EOF);
/* if not already reading, have to be reading and writing */
if ((fp->_flags & __SRD) == 0) {
if ((fp->_flags & __SRW) == 0) {
errno = EBADF;
fp->_flags |= __SERR;
return (EOF);
}
/* switch to reading */
if (fp->_flags & __SWR) {
if (__sflush(fp))
return (EOF);
fp->_flags &= ~__SWR;
fp->_w = 0;
fp->_lbfsize = 0;
}
fp->_flags |= __SRD;
} else {
/*
* We were reading. If there is an ungetc buffer,
* we must have been reading from that. Drop it,
* restoring the previous buffer (if any). If there
* is anything in that buffer, return.
*/
if (HASUB(fp)) {
FREEUB(fp);
if ((fp->_r = fp->_ur) != 0) {
fp->_p = fp->_up;
return (0);
}
}
}
if (fp->_bf._base == NULL)
__smakebuf(fp);
/*
* Before reading from a line buffered or unbuffered file,
* flush all line buffered output files, per the ANSI C
* standard.
*/
if (fp->_flags & (__SLBF|__SNBF)) {
/* Ignore this file in _fwalk to avoid potential deadlock. */
fp->_flags |= __SIGN;
(void) _fwalk(lflush);
fp->_flags &= ~__SIGN;
/* Now flush this file without locking it. */
if ((fp->_flags & (__SLBF|__SWR)) == (__SLBF|__SWR))
__sflush(fp);
}
fp->_p = fp->_bf._base;
fp->_r = _sread(fp, (char *)fp->_p, fp->_bf._size);
fp->_flags &= ~__SMOD; /* buffer contents are again pristine */
if (fp->_r <= 0) {
if (fp->_r == 0)
fp->_flags |= __SEOF;
else {
fp->_r = 0;
fp->_flags |= __SERR;
}
return (EOF);
}
return (0);
}
diff --git a/lib/libc/stdio/remove.c b/lib/libc/stdio/remove.c
index 1e9dd98e1841..ac73c4d071ee 100644
--- a/lib/libc/stdio/remove.c
+++ b/lib/libc/stdio/remove.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)remove.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
int
remove(const char *file)
{
struct stat sb;
if (lstat(file, &sb) < 0)
return (-1);
if (S_ISDIR(sb.st_mode))
return (rmdir(file));
return (unlink(file));
}
diff --git a/lib/libc/stdio/rewind.c b/lib/libc/stdio/rewind.c
index 8e6fc877c401..e66888d8c59a 100644
--- a/lib/libc/stdio/rewind.c
+++ b/lib/libc/stdio/rewind.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rewind.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
void
rewind(FILE *fp)
{
int serrno = errno;
/* make sure stdio is set up */
if (!__sdidinit)
__sinit();
FLOCKFILE(fp);
if (_fseeko(fp, (off_t)0, SEEK_SET, 1) == 0)
errno = serrno;
clearerr_unlocked(fp); /* POSIX: clear stdio error regardless */
FUNLOCKFILE(fp);
}
diff --git a/lib/libc/stdio/rget.c b/lib/libc/stdio/rget.c
index a25ae3bdcea1..a3fb493cc4b9 100644
--- a/lib/libc/stdio/rget.c
+++ b/lib/libc/stdio/rget.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rget.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include "local.h"
/*
* Handle getc() when the buffer ran out:
* Refill, then return the first character
* in the newly-filled buffer.
*/
int
__srget(FILE *fp)
{
if (__srefill(fp) == 0) {
fp->_r--;
return (*fp->_p++);
}
return (EOF);
}
diff --git a/lib/libc/stdio/scanf.c b/lib/libc/stdio/scanf.c
index 1f84f9ab6542..49ff6ac4973d 100644
--- a/lib/libc/stdio/scanf.c
+++ b/lib/libc/stdio/scanf.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)scanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <stdarg.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
int
scanf(char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
FLOCKFILE_CANCELSAFE(stdin);
ret = __svfscanf(stdin, __get_locale(), fmt, ap);
FUNLOCKFILE_CANCELSAFE();
va_end(ap);
return (ret);
}
int
scanf_l(locale_t locale, char const * __restrict fmt, ...)
{
int ret;
va_list ap;
FIX_LOCALE(locale);
va_start(ap, fmt);
FLOCKFILE_CANCELSAFE(stdin);
ret = __svfscanf(stdin, locale, fmt, ap);
FUNLOCKFILE_CANCELSAFE();
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/setbuf.c b/lib/libc/stdio/setbuf.c
index 71f0ee4ae7dc..a304909b15aa 100644
--- a/lib/libc/stdio/setbuf.c
+++ b/lib/libc/stdio/setbuf.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setbuf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include "local.h"
void
setbuf(FILE * __restrict fp, char * __restrict buf)
{
(void) setvbuf(fp, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
}
diff --git a/lib/libc/stdio/setbuffer.c b/lib/libc/stdio/setbuffer.c
index 96c498f95e73..cc6fb7992c5d 100644
--- a/lib/libc/stdio/setbuffer.c
+++ b/lib/libc/stdio/setbuffer.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setbuffer.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
void
setbuffer(FILE *fp, char *buf, int size)
{
(void)setvbuf(fp, buf, buf ? _IOFBF : _IONBF, (size_t)size);
}
/*
* set line buffering
*/
int
setlinebuf(FILE *fp)
{
return (setvbuf(fp, (char *)NULL, _IOLBF, (size_t)0));
}
diff --git a/lib/libc/stdio/setvbuf.c b/lib/libc/stdio/setvbuf.c
index 9714818bc57f..4964d19f32f8 100644
--- a/lib/libc/stdio/setvbuf.c
+++ b/lib/libc/stdio/setvbuf.c
@@ -1,162 +1,161 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)setvbuf.c 8.2 (Berkeley) 11/16/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
/*
* Set one of the three kinds of buffering, optionally including
* a buffer.
*/
int
setvbuf(FILE * __restrict fp, char * __restrict buf, int mode, size_t size)
{
int ret, flags;
size_t iosize;
int ttyflag;
/*
* Verify arguments. The `int' limit on `size' is due to this
* particular implementation. Note, buf and size are ignored
* when setting _IONBF.
*/
if (mode != _IONBF)
if ((mode != _IOFBF && mode != _IOLBF) || size > INT_MAX)
return (EOF);
FLOCKFILE_CANCELSAFE(fp);
/*
* Write current buffer, if any. Discard unread input (including
* ungetc data), cancel line buffering, and free old buffer if
* malloc()ed. We also clear any eof condition, as if this were
* a seek.
*/
ret = 0;
(void)__sflush(fp);
if (HASUB(fp))
FREEUB(fp);
fp->_r = fp->_lbfsize = 0;
flags = fp->_flags;
if (flags & __SMBF)
free((void *)fp->_bf._base);
flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SOFF | __SNPT | __SEOF);
/* If setting unbuffered mode, skip all the hard work. */
if (mode == _IONBF)
goto nbf;
/*
* Find optimal I/O size for seek optimization. This also returns
* a `tty flag' to suggest that we check isatty(fd), but we do not
* care since our caller told us how to buffer.
*/
flags |= __swhatbuf(fp, &iosize, &ttyflag);
if (size == 0) {
buf = NULL; /* force local allocation */
size = iosize;
}
/* Allocate buffer if needed. */
if (buf == NULL) {
if ((buf = malloc(size)) == NULL) {
/*
* Unable to honor user's request. We will return
* failure, but try again with file system size.
*/
ret = EOF;
if (size != iosize) {
size = iosize;
buf = malloc(size);
}
}
if (buf == NULL) {
/* No luck; switch to unbuffered I/O. */
nbf:
fp->_flags = flags | __SNBF;
fp->_w = 0;
fp->_bf._base = fp->_p = fp->_nbuf;
fp->_bf._size = 1;
goto end;
}
flags |= __SMBF;
}
/*
* Kill any seek optimization if the buffer is not the
* right size.
*
* SHOULD WE ALLOW MULTIPLES HERE (i.e., ok iff (size % iosize) == 0)?
*/
if (size != iosize)
flags |= __SNPT;
/*
* Fix up the FILE fields, and set __cleanup for output flush on
* exit (since we are buffered in some way).
*/
if (mode == _IOLBF)
flags |= __SLBF;
fp->_flags = flags;
fp->_bf._base = fp->_p = (unsigned char *)buf;
fp->_bf._size = size;
/* fp->_lbfsize is still 0 */
if (flags & __SWR) {
/*
* Begin or continue writing: see __swsetup(). Note
* that __SNBF is impossible (it was handled earlier).
*/
if (flags & __SLBF) {
fp->_w = 0;
fp->_lbfsize = -fp->_bf._size;
} else
fp->_w = size;
} else {
/* begin/continue reading, or stay in intermediate state */
fp->_w = 0;
}
__cleanup = _cleanup;
end:
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
diff --git a/lib/libc/stdio/snprintf.c b/lib/libc/stdio/snprintf.c
index 45a9e3d7d622..270219ac61f9 100644
--- a/lib/libc/stdio/snprintf.c
+++ b/lib/libc/stdio/snprintf.c
@@ -1,105 +1,104 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)snprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdarg.h>
#include "xlocale_private.h"
#include "local.h"
int
snprintf(char * __restrict str, size_t n, char const * __restrict fmt, ...)
{
size_t on;
int ret;
va_list ap;
FILE f = FAKE_FILE;
on = n;
if (n != 0)
n--;
if (n > INT_MAX) {
errno = EOVERFLOW;
*str = '\0';
return (EOF);
}
va_start(ap, fmt);
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = n;
ret = __vfprintf(&f, __get_locale(), fmt, ap);
if (on > 0)
*f._p = '\0';
va_end(ap);
return (ret);
}
int
snprintf_l(char * __restrict str, size_t n, locale_t locale,
char const * __restrict fmt, ...)
{
size_t on;
int ret;
va_list ap;
FILE f = FAKE_FILE;
FIX_LOCALE(locale);
on = n;
if (n != 0)
n--;
if (n > INT_MAX) {
errno = EOVERFLOW;
*str = '\0';
return (EOF);
}
va_start(ap, fmt);
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = n;
ret = __vfprintf(&f, locale, fmt, ap);
if (on > 0)
*f._p = '\0';
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/sprintf.c b/lib/libc/stdio/sprintf.c
index c83efdb3f357..b9abfee46ed4 100644
--- a/lib/libc/stdio/sprintf.c
+++ b/lib/libc/stdio/sprintf.c
@@ -1,73 +1,72 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)sprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
#include "local.h"
#include "xlocale_private.h"
int
sprintf(char * __restrict str, char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vsprintf(str, fmt, ap);
va_end(ap);
return (ret);
}
int
sprintf_l(char * __restrict str, locale_t locale, char const * __restrict fmt,
...)
{
int ret;
va_list ap;
FIX_LOCALE(locale);
va_start(ap, fmt);
ret = vsprintf_l(str, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/sscanf.c b/lib/libc/stdio/sscanf.c
index a06aac85a676..2a2bae35ffd3 100644
--- a/lib/libc/stdio/sscanf.c
+++ b/lib/libc/stdio/sscanf.c
@@ -1,72 +1,71 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)sscanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <xlocale.h>
#include "local.h"
int
sscanf(const char * __restrict str, char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vsscanf(str, fmt, ap);
va_end(ap);
return (ret);
}
int
sscanf_l(const char * __restrict str, locale_t locale,
char const * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vsscanf_l(str, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/stdio.c b/lib/libc/stdio/stdio.c
index 40677118bea2..ebe9b33718e0 100644
--- a/lib/libc/stdio/stdio.c
+++ b/lib/libc/stdio/stdio.c
@@ -1,176 +1,175 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)stdio.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "un-namespace.h"
#include "local.h"
/*
* Small standard I/O/seek/close functions.
*/
int
__sread(void *cookie, char *buf, int n)
{
FILE *fp = cookie;
return(_read(fp->_file, buf, (size_t)n));
}
int
__swrite(void *cookie, char const *buf, int n)
{
FILE *fp = cookie;
return (_write(fp->_file, buf, (size_t)n));
}
fpos_t
__sseek(void *cookie, fpos_t offset, int whence)
{
FILE *fp = cookie;
return (lseek(fp->_file, (off_t)offset, whence));
}
int
__sclose(void *cookie)
{
return (_close(((FILE *)cookie)->_file));
}
/*
* Higher level wrappers.
*/
int
_sread(FILE *fp, char *buf, int n)
{
int ret;
ret = (*fp->_read)(fp->_cookie, buf, n);
if (ret > 0) {
if (fp->_flags & __SOFF) {
if (fp->_offset <= OFF_MAX - ret)
fp->_offset += ret;
else
fp->_flags &= ~__SOFF;
}
} else if (ret < 0)
fp->_flags &= ~__SOFF;
return (ret);
}
int
_swrite(FILE *fp, char const *buf, int n)
{
int ret;
int serrno;
if (fp->_flags & __SAPP) {
serrno = errno;
if (_sseek(fp, (fpos_t)0, SEEK_END) == -1 &&
(fp->_flags & __SOPT))
return (-1);
errno = serrno;
}
ret = (*fp->_write)(fp->_cookie, buf, n);
/* __SOFF removed even on success in case O_APPEND mode is set. */
if (ret >= 0) {
if ((fp->_flags & __SOFF) && !(fp->_flags2 & __S2OAP) &&
fp->_offset <= OFF_MAX - ret)
fp->_offset += ret;
else
fp->_flags &= ~__SOFF;
} else if (ret < 0)
fp->_flags &= ~__SOFF;
return (ret);
}
fpos_t
_sseek(FILE *fp, fpos_t offset, int whence)
{
fpos_t ret;
int serrno, errret;
serrno = errno;
errno = 0;
ret = (*fp->_seek)(fp->_cookie, offset, whence);
errret = errno;
if (errno == 0)
errno = serrno;
/*
* Disallow negative seeks per POSIX.
* It is needed here to help upper level caller
* in the cases it can't detect.
*/
if (ret < 0) {
if (errret == 0) {
if (offset != 0 || whence != SEEK_CUR) {
if (HASUB(fp))
FREEUB(fp);
fp->_p = fp->_bf._base;
fp->_r = 0;
fp->_flags &= ~__SEOF;
}
fp->_flags |= __SERR;
errno = EINVAL;
} else if (errret == ESPIPE)
fp->_flags &= ~__SAPP;
fp->_flags &= ~__SOFF;
ret = -1;
} else if (fp->_flags & __SOPT) {
fp->_flags |= __SOFF;
fp->_offset = ret;
}
return (ret);
}
void
__stdio_cancel_cleanup(void * arg)
{
if (arg != NULL)
_funlockfile((FILE *)arg);
}
diff --git a/lib/libc/stdio/swprintf.c b/lib/libc/stdio/swprintf.c
index 4c4db2accb76..278f0e37d117 100644
--- a/lib/libc/stdio/swprintf.c
+++ b/lib/libc/stdio/swprintf.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
swprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vswprintf(s, n, fmt, ap);
va_end(ap);
return (ret);
}
int
swprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
const wchar_t * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vswprintf_l(s, n, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/swscanf.c b/lib/libc/stdio/swscanf.c
index 20bf266dc772..9b91acf56685 100644
--- a/lib/libc/stdio/swscanf.c
+++ b/lib/libc/stdio/swscanf.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
swscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vswscanf(str, fmt, ap);
va_end(ap);
return (r);
}
int
swscanf_l(const wchar_t * __restrict str, locale_t locale,
const wchar_t * __restrict fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vswscanf_l(str, locale, fmt, ap);
va_end(ap);
return (r);
}
diff --git a/lib/libc/stdio/tempnam.c b/lib/libc/stdio/tempnam.c
index 06dceec153bf..0badf9093bf1 100644
--- a/lib/libc/stdio/tempnam.c
+++ b/lib/libc/stdio/tempnam.c
@@ -1,89 +1,88 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tempnam.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <paths.h>
__warn_references(tempnam,
"warning: tempnam() possibly used unsafely; consider using mkstemp()");
extern char *_mktemp(char *);
char *
tempnam(const char *dir, const char *pfx)
{
int sverrno;
char *f, *name;
if (!(name = malloc(MAXPATHLEN)))
return(NULL);
if (!pfx)
pfx = "tmp.";
if ((f = secure_getenv("TMPDIR")) != NULL) {
(void)snprintf(name, MAXPATHLEN, "%s%s%sXXXXXX", f,
*(f + strlen(f) - 1) == '/'? "": "/", pfx);
if ((f = _mktemp(name)))
return(f);
}
if ((f = (char *)dir)) {
(void)snprintf(name, MAXPATHLEN, "%s%s%sXXXXXX", f,
*(f + strlen(f) - 1) == '/'? "": "/", pfx);
if ((f = _mktemp(name)))
return(f);
}
f = P_tmpdir;
(void)snprintf(name, MAXPATHLEN, "%s%sXXXXXX", f, pfx);
if ((f = _mktemp(name)))
return(f);
f = _PATH_TMP;
(void)snprintf(name, MAXPATHLEN, "%s%sXXXXXX", f, pfx);
if ((f = _mktemp(name)))
return(f);
sverrno = errno;
free(name);
errno = sverrno;
return(NULL);
}
diff --git a/lib/libc/stdio/tmpfile.c b/lib/libc/stdio/tmpfile.c
index afe45595eac8..89a03b562002 100644
--- a/lib/libc/stdio/tmpfile.c
+++ b/lib/libc/stdio/tmpfile.c
@@ -1,91 +1,90 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tmpfile.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <paths.h>
#include "un-namespace.h"
#include "libc_private.h"
FILE *
tmpfile(void)
{
sigset_t set, oset;
FILE *fp;
int fd, sverrno;
#define TRAILER "tmp.XXXXXX"
char *buf;
const char *tmpdir;
tmpdir = secure_getenv("TMPDIR");
if (tmpdir == NULL)
tmpdir = _PATH_TMP;
(void)asprintf(&buf, "%s%s%s", tmpdir,
(tmpdir[strlen(tmpdir) - 1] == '/') ? "" : "/", TRAILER);
if (buf == NULL)
return (NULL);
sigfillset(&set);
(void)__libc_sigprocmask(SIG_BLOCK, &set, &oset);
fd = mkstemp(buf);
if (fd != -1)
(void)unlink(buf);
free(buf);
(void)__libc_sigprocmask(SIG_SETMASK, &oset, NULL);
if (fd == -1)
return (NULL);
if ((fp = fdopen(fd, "w+")) == NULL) {
sverrno = errno;
(void)_close(fd);
errno = sverrno;
return (NULL);
}
return (fp);
}
diff --git a/lib/libc/stdio/tmpnam.c b/lib/libc/stdio/tmpnam.c
index 8fc057dea868..22d6b2fe735d 100644
--- a/lib/libc/stdio/tmpnam.c
+++ b/lib/libc/stdio/tmpnam.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)tmpnam.c 8.3 (Berkeley) 3/28/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
__warn_references(tmpnam,
"warning: tmpnam() possibly used unsafely; consider using mkstemp()");
extern char *_mktemp(char *);
char *
tmpnam(char *s)
{
static u_long tmpcount;
static char buf[L_tmpnam];
if (s == NULL)
s = buf;
(void)snprintf(s, L_tmpnam, "%stmp.%lu.XXXXXX", P_tmpdir, tmpcount);
++tmpcount;
return (_mktemp(s));
}
diff --git a/lib/libc/stdio/ungetc.c b/lib/libc/stdio/ungetc.c
index d5c91626dfa1..1fd60daa66fc 100644
--- a/lib/libc/stdio/ungetc.c
+++ b/lib/libc/stdio/ungetc.c
@@ -1,168 +1,167 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ungetc.c 8.2 (Berkeley) 11/3/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
#include "local.h"
#include "libc_private.h"
static int __submore(FILE *);
/*
* Expand the ungetc buffer `in place'. That is, adjust fp->_p when
* the buffer moves, so that it points the same distance from the end,
* and move the bytes in the buffer around as necessary so that they
* are all at the end (stack-style).
*/
static int
__submore(FILE *fp)
{
int i;
unsigned char *p;
if (fp->_ub._base == fp->_ubuf) {
/*
* Get a new buffer (rather than expanding the old one).
*/
if ((p = malloc((size_t)BUFSIZ)) == NULL)
return (EOF);
fp->_ub._base = p;
fp->_ub._size = BUFSIZ;
p += BUFSIZ - sizeof(fp->_ubuf);
for (i = sizeof(fp->_ubuf); --i >= 0;)
p[i] = fp->_ubuf[i];
fp->_p = p;
return (0);
}
i = fp->_ub._size;
p = reallocarray(fp->_ub._base, i, 2);
if (p == NULL)
return (EOF);
/* no overlap (hence can use memcpy) because we doubled the size */
(void)memcpy((void *)(p + i), (void *)p, (size_t)i);
fp->_p = p + i;
fp->_ub._base = p;
fp->_ub._size = i * 2;
return (0);
}
/*
* MT-safe version
*/
int
ungetc(int c, FILE *fp)
{
int ret;
if (!__sdidinit)
__sinit();
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, -1);
ret = __ungetc(c, fp);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
/*
* Non-MT-safe version
*/
int
__ungetc(int c, FILE *fp)
{
if (c == EOF)
return (EOF);
if ((fp->_flags & __SRD) == 0) {
/*
* Not already reading: no good unless reading-and-writing.
* Otherwise, flush any current write stuff.
*/
if ((fp->_flags & __SRW) == 0)
return (EOF);
if (fp->_flags & __SWR) {
if (__sflush(fp))
return (EOF);
fp->_flags &= ~__SWR;
fp->_w = 0;
fp->_lbfsize = 0;
}
fp->_flags |= __SRD;
}
c = (unsigned char)c;
/*
* If we are in the middle of ungetc'ing, just continue.
* This may require expanding the current ungetc buffer.
*/
if (HASUB(fp)) {
if (fp->_r >= fp->_ub._size && __submore(fp))
return (EOF);
*--fp->_p = c;
fp->_r++;
return (c);
}
fp->_flags &= ~__SEOF;
/*
* If we can handle this by simply backing up, do so,
* but never replace the original character.
* (This makes sscanf() work when scanning `const' data.)
*/
if (fp->_bf._base != NULL && fp->_p > fp->_bf._base &&
fp->_p[-1] == c) {
fp->_p--;
fp->_r++;
return (c);
}
/*
* Create an ungetc buffer.
* Initially, we will use the `reserve' buffer.
*/
fp->_ur = fp->_r;
fp->_up = fp->_p;
fp->_ub._base = fp->_ubuf;
fp->_ub._size = sizeof(fp->_ubuf);
fp->_ubuf[sizeof(fp->_ubuf) - 1] = c;
fp->_p = &fp->_ubuf[sizeof(fp->_ubuf) - 1];
fp->_r = 1;
return (c);
}
diff --git a/lib/libc/stdio/ungetwc.c b/lib/libc/stdio/ungetwc.c
index a4c71d012be0..0a72b6ea1705 100644
--- a/lib/libc/stdio/ungetwc.c
+++ b/lib/libc/stdio/ungetwc.c
@@ -1,90 +1,89 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002-2004 Tim J. Robbins.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "mblocal.h"
#include "xlocale_private.h"
/*
* Non-MT-safe version.
*/
wint_t
__ungetwc(wint_t wc, FILE *fp, locale_t locale)
{
char buf[MB_LEN_MAX];
size_t len;
struct xlocale_ctype *l = XLOCALE_CTYPE(locale);
if (wc == WEOF)
return (WEOF);
if ((len = l->__wcrtomb(buf, wc, &fp->_mbstate)) == (size_t)-1) {
fp->_flags |= __SERR;
return (WEOF);
}
while (len-- != 0)
if (__ungetc((unsigned char)buf[len], fp) == EOF)
return (WEOF);
return (wc);
}
/*
* MT-safe version.
*/
wint_t
ungetwc_l(wint_t wc, FILE *fp, locale_t locale)
{
wint_t r;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, 1);
r = __ungetwc(wc, fp, locale);
FUNLOCKFILE_CANCELSAFE();
return (r);
}
wint_t
ungetwc(wint_t wc, FILE *fp)
{
return ungetwc_l(wc, fp, __get_locale());
}
diff --git a/lib/libc/stdio/vasprintf.c b/lib/libc/stdio/vasprintf.c
index 2e5f8dd4107a..c2c6170a2382 100644
--- a/lib/libc/stdio/vasprintf.c
+++ b/lib/libc/stdio/vasprintf.c
@@ -1,74 +1,73 @@
/* $OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "xlocale_private.h"
#include "local.h"
int
vasprintf_l(char **str, locale_t locale, const char *fmt, __va_list ap)
{
FILE f = FAKE_FILE;
int ret;
FIX_LOCALE(locale);
f._flags = __SWR | __SSTR | __SALC;
f._bf._base = f._p = malloc(128);
if (f._bf._base == NULL) {
*str = NULL;
errno = ENOMEM;
return (-1);
}
f._bf._size = f._w = 127; /* Leave room for the NUL */
ret = __vfprintf(&f, locale, fmt, ap);
if (ret < 0) {
free(f._bf._base);
*str = NULL;
errno = ENOMEM;
return (-1);
}
*f._p = '\0';
*str = (char *)f._bf._base;
return (ret);
}
int
vasprintf(char **str, const char *fmt, __va_list ap)
{
return vasprintf_l(str, __get_locale(), fmt, ap);
}
diff --git a/lib/libc/stdio/vdprintf.c b/lib/libc/stdio/vdprintf.c
index a84efaa14b4d..3cff85aa9dc5 100644
--- a/lib/libc/stdio/vdprintf.c
+++ b/lib/libc/stdio/vdprintf.c
@@ -1,70 +1,69 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include "un-namespace.h"
#include "local.h"
#include "xlocale_private.h"
int
vdprintf(int fd, const char * __restrict fmt, va_list ap)
{
FILE f = FAKE_FILE;
unsigned char buf[BUFSIZ];
int ret;
if (fd > SHRT_MAX) {
errno = EMFILE;
return (EOF);
}
f._p = buf;
f._w = sizeof(buf);
f._flags = __SWR;
f._file = fd;
f._cookie = &f;
f._write = __swrite;
f._bf._base = buf;
f._bf._size = sizeof(buf);
if ((ret = __vfprintf(&f, __get_locale(), fmt, ap)) < 0)
return (ret);
return (__fflush(&f) ? EOF : ret);
}
diff --git a/lib/libc/stdio/vfprintf.c b/lib/libc/stdio/vfprintf.c
index 8ce77626fb6f..38c77aebf316 100644
--- a/lib/libc/stdio/vfprintf.c
+++ b/lib/libc/stdio/vfprintf.c
@@ -1,1109 +1,1108 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* Actual printf innards.
*
* This code is large and complicated...
*/
#include "namespace.h"
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <printf.h>
#include <stdarg.h>
#include "xlocale_private.h"
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "fvwrite.h"
#include "printflocal.h"
static int __sprint(FILE *, struct __suio *, locale_t);
static int __sbprintf(FILE *, locale_t, const char *, va_list) __printflike(3, 0)
__noinline;
static char *__wcsconv(wchar_t *, int);
#define CHAR char
#include "printfcommon.h"
struct grouping_state {
char *thousands_sep; /* locale-specific thousands separator */
int thousep_len; /* length of thousands_sep */
const char *grouping; /* locale-specific numeric grouping rules */
int lead; /* sig figs before decimal or group sep */
int nseps; /* number of group separators with ' */
int nrepeats; /* number of repeats of the last group */
};
/*
* Initialize the thousands' grouping state in preparation to print a
* number with ndigits digits. This routine returns the total number
* of bytes that will be needed.
*/
static int
grouping_init(struct grouping_state *gs, int ndigits, locale_t loc)
{
struct lconv *locale;
locale = localeconv_l(loc);
gs->grouping = locale->grouping;
gs->thousands_sep = locale->thousands_sep;
gs->thousep_len = strlen(gs->thousands_sep);
gs->nseps = gs->nrepeats = 0;
gs->lead = ndigits;
while (*gs->grouping != CHAR_MAX) {
if (gs->lead <= *gs->grouping)
break;
gs->lead -= *gs->grouping;
if (*(gs->grouping+1)) {
gs->nseps++;
gs->grouping++;
} else
gs->nrepeats++;
}
return ((gs->nseps + gs->nrepeats) * gs->thousep_len);
}
/*
* Print a number with thousands' separators.
*/
static int
grouping_print(struct grouping_state *gs, struct io_state *iop,
const CHAR *cp, const CHAR *ep, locale_t locale)
{
const CHAR *cp0 = cp;
if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
return (-1);
cp += gs->lead;
while (gs->nseps > 0 || gs->nrepeats > 0) {
if (gs->nrepeats > 0)
gs->nrepeats--;
else {
gs->grouping--;
gs->nseps--;
}
if (io_print(iop, gs->thousands_sep, gs->thousep_len, locale))
return (-1);
if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
return (-1);
cp += *gs->grouping;
}
if (cp > ep)
cp = ep;
return (cp - cp0);
}
/*
* Flush out all the vectors defined by the given uio,
* then reset it so that it can be reused.
*/
static int
__sprint(FILE *fp, struct __suio *uio, locale_t locale)
{
int err;
if (uio->uio_resid == 0) {
uio->uio_iovcnt = 0;
return (0);
}
err = __sfvwrite(fp, uio);
uio->uio_resid = 0;
uio->uio_iovcnt = 0;
return (err);
}
/*
* Helper function for `fprintf to unbuffered unix file': creates a
* temporary buffer. We only work on write-only files; this avoids
* worries about ungetc buffers and so forth.
*/
static int
__sbprintf(FILE *fp, locale_t locale, const char *fmt, va_list ap)
{
int ret;
FILE fake = FAKE_FILE;
unsigned char buf[BUFSIZ];
/* XXX This is probably not needed. */
if (prepwrite(fp) != 0)
return (EOF);
/* copy the important variables */
fake._flags = fp->_flags & ~__SNBF;
fake._file = fp->_file;
fake._cookie = fp->_cookie;
fake._write = fp->_write;
fake._orientation = fp->_orientation;
fake._mbstate = fp->_mbstate;
/* set up the buffer */
fake._bf._base = fake._p = buf;
fake._bf._size = fake._w = sizeof(buf);
fake._lbfsize = 0; /* not actually used, but Just In Case */
/* do the work, then copy any error status */
ret = __vfprintf(&fake, locale, fmt, ap);
if (ret >= 0 && __fflush(&fake))
ret = EOF;
if (fake._flags & __SERR)
fp->_flags |= __SERR;
return (ret);
}
/*
* Convert a wide character string argument for the %ls format to a multibyte
* string representation. If not -1, prec specifies the maximum number of
* bytes to output, and also means that we can't assume that the wide char.
* string ends is null-terminated.
*/
static char *
__wcsconv(wchar_t *wcsarg, int prec)
{
static const mbstate_t initial;
mbstate_t mbs;
char buf[MB_LEN_MAX];
wchar_t *p;
char *convbuf;
size_t clen, nbytes;
/* Allocate space for the maximum number of bytes we could output. */
if (prec < 0) {
p = wcsarg;
mbs = initial;
nbytes = wcsrtombs(NULL, (const wchar_t **)&p, 0, &mbs);
if (nbytes == (size_t)-1)
return (NULL);
} else {
/*
* Optimisation: if the output precision is small enough,
* just allocate enough memory for the maximum instead of
* scanning the string.
*/
if (prec < 128)
nbytes = prec;
else {
nbytes = 0;
p = wcsarg;
mbs = initial;
for (;;) {
clen = wcrtomb(buf, *p++, &mbs);
if (clen == 0 || clen == (size_t)-1 ||
nbytes + clen > prec)
break;
nbytes += clen;
}
}
}
if ((convbuf = malloc(nbytes + 1)) == NULL)
return (NULL);
/* Fill the output buffer. */
p = wcsarg;
mbs = initial;
if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p,
nbytes, &mbs)) == (size_t)-1) {
free(convbuf);
return (NULL);
}
convbuf[nbytes] = '\0';
return (convbuf);
}
/*
* MT-safe version
*/
int
vfprintf_l(FILE * __restrict fp, locale_t locale, const char * __restrict fmt0,
va_list ap)
{
int ret;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
/* optimise fprintf(stderr) (and other unbuffered Unix files) */
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
fp->_file >= 0)
ret = __sbprintf(fp, locale, fmt0, ap);
else
ret = __vfprintf(fp, locale, fmt0, ap);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
int
vfprintf(FILE * __restrict fp, const char * __restrict fmt0, va_list ap)
{
return vfprintf_l(fp, __get_locale(), fmt0, ap);
}
/*
* The size of the buffer we use as scratch space for integer
* conversions, among other things. We need enough space to
* write a uintmax_t in octal (plus one byte).
*/
#if UINTMAX_MAX <= UINT64_MAX
#define BUF 32
#else
#error "BUF must be large enough to format a uintmax_t"
#endif
/*
* Non-MT-safe version
*/
int
__vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
{
char *fmt; /* format string */
int ch; /* character from fmt */
int n, n2; /* handy integer (short term usage) */
char *cp; /* handy char pointer (short term usage) */
int flags; /* flags as above */
int ret; /* return value accumulator */
int width; /* width from format (%8d), or 0 */
int prec; /* precision from format; <0 for N/A */
int saved_errno;
char sign; /* sign prefix (' ', '+', '-', or \0) */
struct grouping_state gs; /* thousands' grouping info */
#ifndef NO_FLOATING_POINT
/*
* We can decompose the printed representation of floating
* point numbers into several parts, some of which may be empty:
*
* [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
* A B ---C--- D E F
*
* A: 'sign' holds this value if present; '\0' otherwise
* B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
* C: cp points to the string MMMNNN. Leading and trailing
* zeros are not in the string and must be added.
* D: expchar holds this character; '\0' if no exponent, e.g. %f
* F: at least two digits for decimal, at least one digit for hex
*/
char *decimal_point; /* locale specific decimal point */
int decpt_len; /* length of decimal_point */
int signflag; /* true if float is negative */
union { /* floating point arguments %[aAeEfFgG] */
double dbl;
long double ldbl;
} fparg;
int expt; /* integer value of exponent */
char expchar; /* exponent character: [eEpP\0] */
char *dtoaend; /* pointer to end of converted digits */
int expsize; /* character count for expstr */
int ndig; /* actual number of digits returned by dtoa */
char expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
char *dtoaresult; /* buffer allocated by dtoa */
#endif
u_long ulval; /* integer arguments %[diouxX] */
uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
int base; /* base for [diouxX] conversion */
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
int realsz; /* field size expanded by dprec, sign, etc */
int size; /* size of converted field or string */
int prsize; /* max size of printed field */
const char *xdigs; /* digits for %[xX] conversion */
struct io_state io; /* I/O buffering state */
char buf[BUF]; /* buffer with space for digits of uintmax_t */
char ox[2]; /* space for 0x; ox[1] is either x, X, or \0 */
union arg *argtable; /* args, built due to positional arg */
union arg statargtable [STATIC_ARG_TBL_SIZE];
int nextarg; /* 1-based argument index */
va_list orgap; /* original argument pointer */
char *convbuf; /* wide to multibyte conversion result */
int savserr;
static const char xdigs_lower[16] = "0123456789abcdef";
static const char xdigs_upper[16] = "0123456789ABCDEF";
/* BEWARE, these `goto error' on error. */
#define PRINT(ptr, len) { \
if (io_print(&io, (ptr), (len), locale)) \
goto error; \
}
#define PAD(howmany, with) { \
if (io_pad(&io, (howmany), (with), locale)) \
goto error; \
}
#define PRINTANDPAD(p, ep, len, with) { \
if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
goto error; \
}
#define FLUSH() { \
if (io_flush(&io, locale)) \
goto error; \
}
/*
* Get the argument indexed by nextarg. If the argument table is
* built, use it to get the argument. If its not, get the next
* argument (and arguments must be gotten sequentially).
*/
#define GETARG(type) \
((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
(nextarg++, va_arg(ap, type)))
/*
* To extend shorts properly, we need both signed and unsigned
* argument extraction methods.
*/
#define SARG() \
(flags&LONGINT ? GETARG(long) : \
flags&SHORTINT ? (long)(short)GETARG(int) : \
flags&CHARINT ? (long)(signed char)GETARG(int) : \
(long)GETARG(int))
#define UARG() \
(flags&LONGINT ? GETARG(u_long) : \
flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
(u_long)GETARG(u_int))
#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
#define SJARG() \
(flags&INTMAXT ? GETARG(intmax_t) : \
flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
(intmax_t)GETARG(long long))
#define UJARG() \
(flags&INTMAXT ? GETARG(uintmax_t) : \
flags&SIZET ? (uintmax_t)GETARG(size_t) : \
flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
(uintmax_t)GETARG(unsigned long long))
/*
* Get * arguments, including the form *nn$. Preserve the nextarg
* that the argument can be gotten once the type is determined.
*/
#define GETASTER(val) \
n2 = 0; \
cp = fmt; \
while (is_digit(*cp)) { \
n2 = 10 * n2 + to_digit(*cp); \
cp++; \
} \
if (*cp == '$') { \
int hold = nextarg; \
if (argtable == NULL) { \
argtable = statargtable; \
if (__find_arguments (fmt0, orgap, &argtable)) { \
ret = EOF; \
goto error; \
} \
} \
nextarg = n2; \
val = GETARG (int); \
nextarg = hold; \
fmt = ++cp; \
} else { \
val = GETARG (int); \
}
if (__use_xprintf == 0 && getenv("USE_XPRINTF"))
__use_xprintf = 1;
if (__use_xprintf > 0)
return (__xvprintf(fp, fmt0, ap));
/* sorry, fprintf(read_only_file, "") returns EOF, not 0 */
if (prepwrite(fp) != 0) {
errno = EBADF;
return (EOF);
}
savserr = fp->_flags & __SERR;
fp->_flags &= ~__SERR;
saved_errno = errno;
convbuf = NULL;
fmt = (char *)fmt0;
argtable = NULL;
nextarg = 1;
va_copy(orgap, ap);
io_init(&io, fp);
ret = 0;
#ifndef NO_FLOATING_POINT
dtoaresult = NULL;
decimal_point = localeconv_l(locale)->decimal_point;
/* The overwhelmingly common case is decpt_len == 1. */
decpt_len = (decimal_point[1] == '\0' ? 1 : strlen(decimal_point));
#endif
/*
* Scan the format for conversions (`%' character).
*/
for (;;) {
for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
/* void */;
if ((n = fmt - cp) != 0) {
if ((unsigned)ret + n > INT_MAX) {
ret = EOF;
errno = EOVERFLOW;
goto error;
}
PRINT(cp, n);
ret += n;
}
if (ch == '\0')
goto done;
fmt++; /* skip over '%' */
flags = 0;
dprec = 0;
width = 0;
prec = -1;
gs.grouping = NULL;
sign = '\0';
ox[1] = '\0';
rflag: ch = *fmt++;
reswitch: switch (ch) {
case ' ':
/*-
* ``If the space and + flags both appear, the space
* flag will be ignored.''
* -- ANSI X3J11
*/
if (!sign)
sign = ' ';
goto rflag;
case '#':
flags |= ALT;
goto rflag;
case '*':
/*-
* ``A negative field width argument is taken as a
* - flag followed by a positive field width.''
* -- ANSI X3J11
* They don't exclude field widths read from args.
*/
GETASTER (width);
if (width >= 0)
goto rflag;
width = -width;
/* FALLTHROUGH */
case '-':
flags |= LADJUST;
goto rflag;
case '+':
sign = '+';
goto rflag;
case '\'':
flags |= GROUPING;
goto rflag;
case '.':
if ((ch = *fmt++) == '*') {
GETASTER (prec);
goto rflag;
}
prec = 0;
while (is_digit(ch)) {
prec = 10 * prec + to_digit(ch);
ch = *fmt++;
}
goto reswitch;
case '0':
/*-
* ``Note that 0 is taken as a flag, not as the
* beginning of a field width.''
* -- ANSI X3J11
*/
flags |= ZEROPAD;
goto rflag;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do {
n = 10 * n + to_digit(ch);
ch = *fmt++;
} while (is_digit(ch));
if (ch == '$') {
nextarg = n;
if (argtable == NULL) {
argtable = statargtable;
if (__find_arguments (fmt0, orgap,
&argtable)) {
ret = EOF;
goto error;
}
}
goto rflag;
}
width = n;
goto reswitch;
#ifndef NO_FLOATING_POINT
case 'L':
flags |= LONGDBL;
goto rflag;
#endif
case 'h':
if (flags & SHORTINT) {
flags &= ~SHORTINT;
flags |= CHARINT;
} else
flags |= SHORTINT;
goto rflag;
case 'j':
flags |= INTMAXT;
goto rflag;
case 'l':
if (flags & LONGINT) {
flags &= ~LONGINT;
flags |= LLONGINT;
} else
flags |= LONGINT;
goto rflag;
case 'q':
flags |= LLONGINT; /* not necessarily */
goto rflag;
case 't':
flags |= PTRDIFFT;
goto rflag;
case 'w':
/*
* Fixed-width integer types. On all platforms we
* support, int8_t is equivalent to char, int16_t
* is equivalent to short, int32_t is equivalent
* to int, int64_t is equivalent to long long int.
* Furthermore, int_fast8_t, int_fast16_t and
* int_fast32_t are equivalent to int, and
* int_fast64_t is equivalent to long long int.
*/
flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT);
if (fmt[0] == 'f') {
flags |= FASTINT;
fmt++;
} else {
flags &= ~FASTINT;
}
if (fmt[0] == '8') {
if (!(flags & FASTINT))
flags |= CHARINT;
else
/* no flag set = 32 */ ;
fmt += 1;
} else if (fmt[0] == '1' && fmt[1] == '6') {
if (!(flags & FASTINT))
flags |= SHORTINT;
else
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '3' && fmt[1] == '2') {
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '6' && fmt[1] == '4') {
flags |= LLONGINT;
fmt += 2;
} else {
if (flags & FASTINT) {
flags &= ~FASTINT;
fmt--;
}
goto invalid;
}
goto rflag;
case 'z':
flags |= SIZET;
goto rflag;
case 'B':
case 'b':
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 2;
/* leading 0b/B only if non-zero */
if (flags & ALT &&
(flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
ox[1] = ch;
goto nosign;
break;
case 'C':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'c':
if (flags & LONGINT) {
static const mbstate_t initial;
mbstate_t mbs;
size_t mbseqlen;
mbs = initial;
mbseqlen = wcrtomb(cp = buf,
(wchar_t)GETARG(wint_t), &mbs);
if (mbseqlen == (size_t)-1) {
fp->_flags |= __SERR;
goto error;
}
size = (int)mbseqlen;
} else {
*(cp = buf) = GETARG(int);
size = 1;
}
sign = '\0';
break;
case 'D':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'd':
case 'i':
if (flags & INTMAX_SIZE) {
ujval = SJARG();
if ((intmax_t)ujval < 0) {
ujval = -ujval;
sign = '-';
}
} else {
ulval = SARG();
if ((long)ulval < 0) {
ulval = -ulval;
sign = '-';
}
}
base = 10;
goto number;
#ifndef NO_FLOATING_POINT
case 'a':
case 'A':
if (ch == 'a') {
ox[1] = 'x';
xdigs = xdigs_lower;
expchar = 'p';
} else {
ox[1] = 'X';
xdigs = xdigs_upper;
expchar = 'P';
}
if (prec >= 0)
prec++;
if (dtoaresult != NULL)
freedtoa(dtoaresult);
if (flags & LONGDBL) {
fparg.ldbl = GETARG(long double);
dtoaresult = cp =
__hldtoa(fparg.ldbl, xdigs, prec,
&expt, &signflag, &dtoaend);
} else {
fparg.dbl = GETARG(double);
dtoaresult = cp =
__hdtoa(fparg.dbl, xdigs, prec,
&expt, &signflag, &dtoaend);
}
if (prec < 0)
prec = dtoaend - cp;
if (expt == INT_MAX)
ox[1] = '\0';
goto fp_common;
case 'e':
case 'E':
expchar = ch;
if (prec < 0) /* account for digit before decpt */
prec = DEFPREC + 1;
else
prec++;
goto fp_begin;
case 'f':
case 'F':
expchar = '\0';
goto fp_begin;
case 'g':
case 'G':
expchar = ch - ('g' - 'e');
if (prec == 0)
prec = 1;
fp_begin:
if (prec < 0)
prec = DEFPREC;
if (dtoaresult != NULL)
freedtoa(dtoaresult);
if (flags & LONGDBL) {
fparg.ldbl = GETARG(long double);
dtoaresult = cp =
__ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
&expt, &signflag, &dtoaend);
} else {
fparg.dbl = GETARG(double);
dtoaresult = cp =
dtoa(fparg.dbl, expchar ? 2 : 3, prec,
&expt, &signflag, &dtoaend);
if (expt == 9999)
expt = INT_MAX;
}
fp_common:
if (signflag)
sign = '-';
if (expt == INT_MAX) { /* inf or nan */
if (*cp == 'N') {
cp = (ch >= 'a') ? "nan" : "NAN";
sign = '\0';
} else
cp = (ch >= 'a') ? "inf" : "INF";
size = 3;
flags &= ~ZEROPAD;
break;
}
flags |= FPT;
ndig = dtoaend - cp;
if (ch == 'g' || ch == 'G') {
if (expt > -4 && expt <= prec) {
/* Make %[gG] smell like %[fF] */
expchar = '\0';
if (flags & ALT)
prec -= expt;
else
prec = ndig - expt;
if (prec < 0)
prec = 0;
} else {
/*
* Make %[gG] smell like %[eE], but
* trim trailing zeroes if no # flag.
*/
if (!(flags & ALT))
prec = ndig;
}
}
if (expchar) {
expsize = exponent(expstr, expt - 1, expchar);
size = expsize + prec;
if (prec > 1 || flags & ALT)
size += decpt_len;
} else {
/* space for digits before decimal point */
if (expt > 0)
size = expt;
else /* "0" */
size = 1;
/* space for decimal pt and following digits */
if (prec || flags & ALT)
size += prec + decpt_len;
if ((flags & GROUPING) && expt > 0)
size += grouping_init(&gs, expt, locale);
}
break;
#endif /* !NO_FLOATING_POINT */
case 'm':
cp = strerror(saved_errno);
size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
sign = '\0';
break;
case 'n':
/*
* Assignment-like behavior is specified if the
* value overflows or is otherwise unrepresentable.
* C99 says to use `signed char' for %hhn conversions.
*/
if (flags & LLONGINT)
*GETARG(long long *) = ret;
else if (flags & SIZET)
*GETARG(ssize_t *) = (ssize_t)ret;
else if (flags & PTRDIFFT)
*GETARG(ptrdiff_t *) = ret;
else if (flags & INTMAXT)
*GETARG(intmax_t *) = ret;
else if (flags & LONGINT)
*GETARG(long *) = ret;
else if (flags & SHORTINT)
*GETARG(short *) = ret;
else if (flags & CHARINT)
*GETARG(signed char *) = ret;
else
*GETARG(int *) = ret;
continue; /* no output */
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 8;
goto nosign;
case 'p':
/*-
* ``The argument shall be a pointer to void. The
* value of the pointer is converted to a sequence
* of printable characters, in an implementation-
* defined manner.''
* -- ANSI X3J11
*/
ujval = (uintmax_t)(uintptr_t)GETARG(void *);
base = 16;
xdigs = xdigs_lower;
flags = flags | INTMAXT;
ox[1] = 'x';
goto nosign;
case 'S':
flags |= LONGINT;
/*FALLTHROUGH*/
case 's':
if (flags & LONGINT) {
wchar_t *wcp;
if (convbuf != NULL)
free(convbuf);
if ((wcp = GETARG(wchar_t *)) == NULL)
cp = "(null)";
else {
convbuf = __wcsconv(wcp, prec);
if (convbuf == NULL) {
fp->_flags |= __SERR;
goto error;
}
cp = convbuf;
}
} else if ((cp = GETARG(char *)) == NULL)
cp = "(null)";
size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
sign = '\0';
break;
case 'U':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'u':
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 10;
goto nosign;
case 'X':
xdigs = xdigs_upper;
goto hex;
case 'x':
xdigs = xdigs_lower;
hex:
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 16;
/* leading 0x/X only if non-zero */
if (flags & ALT &&
(flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
ox[1] = ch;
flags &= ~GROUPING;
/* unsigned conversions */
nosign: sign = '\0';
/*-
* ``... diouXx conversions ... if a precision is
* specified, the 0 flag will be ignored.''
* -- ANSI X3J11
*/
number: if ((dprec = prec) >= 0)
flags &= ~ZEROPAD;
/*-
* ``The result of converting a zero value with an
* explicit precision of zero is no characters.''
* -- ANSI X3J11
*
* ``The C Standard is clear enough as is. The call
* printf("%#.0o", 0) should print 0.''
* -- Defect Report #151
*/
cp = buf + BUF;
if (flags & INTMAX_SIZE) {
if (ujval != 0 || prec != 0 ||
(flags & ALT && base == 8))
cp = __ujtoa(ujval, cp, base,
flags & ALT, xdigs);
} else {
if (ulval != 0 || prec != 0 ||
(flags & ALT && base == 8))
cp = __ultoa(ulval, cp, base,
flags & ALT, xdigs);
}
size = buf + BUF - cp;
if (size > BUF) /* should never happen */
abort();
if ((flags & GROUPING) && size != 0)
size += grouping_init(&gs, size, locale);
break;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
goto done;
invalid:
/* pretend it was %c with argument ch */
cp = buf;
*cp = ch;
size = 1;
sign = '\0';
break;
}
/*
* All reasonable formats wind up here. At this point, `cp'
* points to a string which (if not flags&LADJUST) should be
* padded out to `width' places. If flags&ZEROPAD, it should
* first be prefixed by any sign or other prefix; otherwise,
* it should be blank padded before the prefix is emitted.
* After any left-hand padding and prefixing, emit zeroes
* required by a decimal [diouxX] precision, then print the
* string proper, then emit zeroes required by any leftover
* floating precision; finally, if LADJUST, pad with blanks.
*
* Compute actual size, so we know how much to pad.
* size excludes decimal prec; realsz includes it.
*/
realsz = dprec > size ? dprec : size;
if (sign)
realsz++;
if (ox[1])
realsz += 2;
prsize = width > realsz ? width : realsz;
if ((unsigned)ret + prsize > INT_MAX) {
ret = EOF;
errno = EOVERFLOW;
goto error;
}
/* right-adjusting blank padding */
if ((flags & (LADJUST|ZEROPAD)) == 0)
PAD(width - realsz, blanks);
/* prefix */
if (sign)
PRINT(&sign, 1);
if (ox[1]) { /* ox[1] is either x, X, or \0 */
ox[0] = '0';
PRINT(ox, 2);
}
/* right-adjusting zero padding */
if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
PAD(width - realsz, zeroes);
/* the string or number proper */
#ifndef NO_FLOATING_POINT
if ((flags & FPT) == 0) {
#endif
/* leading zeroes from decimal precision */
PAD(dprec - size, zeroes);
if (gs.grouping) {
if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
goto error;
} else {
PRINT(cp, size);
}
#ifndef NO_FLOATING_POINT
} else { /* glue together f_p fragments */
if (!expchar) { /* %[fF] or sufficiently short %[gG] */
if (expt <= 0) {
PRINT(zeroes, 1);
if (prec || flags & ALT)
PRINT(decimal_point,decpt_len);
PAD(-expt, zeroes);
/* already handled initial 0's */
prec += expt;
} else {
if (gs.grouping) {
n = grouping_print(&gs, &io,
cp, dtoaend, locale);
if (n < 0)
goto error;
cp += n;
} else {
PRINTANDPAD(cp, dtoaend,
expt, zeroes);
cp += expt;
}
if (prec || flags & ALT)
PRINT(decimal_point,decpt_len);
}
PRINTANDPAD(cp, dtoaend, prec, zeroes);
} else { /* %[eE] or sufficiently long %[gG] */
if (prec > 1 || flags & ALT) {
PRINT(cp++, 1);
PRINT(decimal_point, decpt_len);
PRINT(cp, ndig-1);
PAD(prec - ndig, zeroes);
} else /* XeYYY */
PRINT(cp, 1);
PRINT(expstr, expsize);
}
}
#endif
/* left-adjusting padding (always blank) */
if (flags & LADJUST)
PAD(width - realsz, blanks);
/* finally, adjust ret */
ret += prsize;
FLUSH(); /* copy out the I/O vectors */
}
done:
FLUSH();
error:
va_end(orgap);
#ifndef NO_FLOATING_POINT
if (dtoaresult != NULL)
freedtoa(dtoaresult);
#endif
if (convbuf != NULL)
free(convbuf);
if (__sferror(fp))
ret = EOF;
else
fp->_flags |= savserr;
if ((argtable != NULL) && (argtable != statargtable))
free (argtable);
return (ret);
/* NOTREACHED */
}
diff --git a/lib/libc/stdio/vfscanf.c b/lib/libc/stdio/vfscanf.c
index fa2e865f33f9..37616e64570c 100644
--- a/lib/libc/stdio/vfscanf.c
+++ b/lib/libc/stdio/vfscanf.c
@@ -1,1161 +1,1160 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Copyright (c) 2023 Dag-Erling Smørgrav
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ctype.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "un-namespace.h"
#include "collate.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
#ifndef NO_FLOATING_POINT
#include <locale.h>
#endif
#define BUF 513 /* Maximum length of numeric string. */
/*
* Flags used during conversion.
*/
#define LONG 0x01 /* l: long or double */
#define LONGDBL 0x02 /* L: long double */
#define SHORT 0x04 /* h: short */
#define SUPPRESS 0x08 /* *: suppress assignment */
#define POINTER 0x10 /* p: void * (as hex) */
#define NOSKIP 0x20 /* [ or c: do not skip blanks */
#define FASTINT 0x200 /* wfN: int_fastN_t */
#define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */
#define INTMAXT 0x800 /* j: intmax_t */
#define PTRDIFFT 0x1000 /* t: ptrdiff_t */
#define SIZET 0x2000 /* z: size_t */
#define SHORTSHORT 0x4000 /* hh: char */
#define UNSIGNED 0x8000 /* %[oupxX] conversions */
/*
* Conversion types.
*/
#define CT_CHAR 0 /* %c conversion */
#define CT_CCL 1 /* %[...] conversion */
#define CT_STRING 2 /* %s conversion */
#define CT_INT 3 /* %[dioupxX] conversion */
#define CT_FLOAT 4 /* %[efgEFG] conversion */
static const u_char *__sccl(char *, const u_char *);
#ifndef NO_FLOATING_POINT
static int parsefloat(FILE *, char *, char *, locale_t);
#endif
__weak_reference(__vfscanf, vfscanf);
/*
* Conversion functions are passed a pointer to this object instead of
* a real parameter to indicate that the assignment-suppression (*)
* flag was specified. We could use a NULL pointer to indicate this,
* but that would mask bugs in applications that call scanf() with a
* NULL pointer.
*/
static const int suppress;
#define SUPPRESS_PTR ((void *)&suppress)
static const mbstate_t initial_mbs;
/*
* The following conversion functions return the number of characters consumed,
* or -1 on input failure. Character class conversion returns 0 on match
* failure.
*/
static __inline int
convert_char(FILE *fp, char * p, int width)
{
int n;
if (p == SUPPRESS_PTR) {
size_t sum = 0;
for (;;) {
if ((n = fp->_r) < width) {
sum += n;
width -= n;
fp->_p += n;
if (__srefill(fp)) {
if (sum == 0)
return (-1);
break;
}
} else {
sum += width;
fp->_r -= width;
fp->_p += width;
break;
}
}
return (sum);
} else {
size_t r = __fread(p, 1, width, fp);
if (r == 0)
return (-1);
return (r);
}
}
static __inline int
convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale)
{
mbstate_t mbs;
int n, nread;
wint_t wi;
mbs = initial_mbs;
n = 0;
while (width-- != 0 &&
(wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF) {
if (wcp != SUPPRESS_PTR)
*wcp++ = (wchar_t)wi;
n += nread;
}
if (n == 0)
return (-1);
return (n);
}
static __inline int
convert_ccl(FILE *fp, char * p, int width, const char *ccltab)
{
char *p0;
int n;
if (p == SUPPRESS_PTR) {
n = 0;
while (ccltab[*fp->_p]) {
n++, fp->_r--, fp->_p++;
if (--width == 0)
break;
if (fp->_r <= 0 && __srefill(fp)) {
if (n == 0)
return (-1);
break;
}
}
} else {
p0 = p;
while (ccltab[*fp->_p]) {
fp->_r--;
*p++ = *fp->_p++;
if (--width == 0)
break;
if (fp->_r <= 0 && __srefill(fp)) {
if (p == p0)
return (-1);
break;
}
}
n = p - p0;
if (n == 0)
return (0);
*p = 0;
}
return (n);
}
static __inline int
convert_wccl(FILE *fp, wchar_t *wcp, int width, const char *ccltab,
locale_t locale)
{
mbstate_t mbs;
wint_t wi;
int n, nread;
mbs = initial_mbs;
n = 0;
if (wcp == SUPPRESS_PTR) {
while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
width-- != 0 && ccltab[wctob(wi)])
n += nread;
if (wi != WEOF)
__ungetwc(wi, fp, __get_locale());
} else {
while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
width-- != 0 && ccltab[wctob(wi)]) {
*wcp++ = (wchar_t)wi;
n += nread;
}
if (wi != WEOF)
__ungetwc(wi, fp, __get_locale());
if (n == 0)
return (0);
*wcp = 0;
}
return (n);
}
static __inline int
convert_string(FILE *fp, char * p, int width)
{
char *p0;
int n;
if (p == SUPPRESS_PTR) {
n = 0;
while (!isspace(*fp->_p)) {
n++, fp->_r--, fp->_p++;
if (--width == 0)
break;
if (fp->_r <= 0 && __srefill(fp))
break;
}
} else {
p0 = p;
while (!isspace(*fp->_p)) {
fp->_r--;
*p++ = *fp->_p++;
if (--width == 0)
break;
if (fp->_r <= 0 && __srefill(fp))
break;
}
*p = 0;
n = p - p0;
}
return (n);
}
static __inline int
convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
{
mbstate_t mbs;
wint_t wi;
int n, nread;
mbs = initial_mbs;
n = 0;
if (wcp == SUPPRESS_PTR) {
while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
width-- != 0 && !iswspace(wi))
n += nread;
if (wi != WEOF)
__ungetwc(wi, fp, __get_locale());
} else {
while ((wi = __fgetwc_mbs(fp, &mbs, &nread, locale)) != WEOF &&
width-- != 0 && !iswspace(wi)) {
*wcp++ = (wchar_t)wi;
n += nread;
}
if (wi != WEOF)
__ungetwc(wi, fp, __get_locale());
*wcp = '\0';
}
return (n);
}
enum parseint_state {
begin,
havesign,
havezero,
haveprefix,
any,
};
static __inline int
parseint_fsm(int c, enum parseint_state *state, int *base)
{
switch (c) {
case '+':
case '-':
if (*state == begin) {
*state = havesign;
return 1;
}
break;
case '0':
if (*state == begin || *state == havesign) {
*state = havezero;
} else {
*state = any;
}
return 1;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if (*state == havezero && *base == 0) {
*base = 8;
}
/* FALL THROUGH */
case '8':
case '9':
if (*state == begin ||
*state == havesign) {
if (*base == 0) {
*base = 10;
}
}
if (*state == begin ||
*state == havesign ||
*state == havezero ||
*state == haveprefix ||
*state == any) {
if (*base > c - '0') {
*state = any;
return 1;
}
}
break;
case 'b':
if (*state == havezero) {
if (*base == 0 || *base == 2) {
*state = haveprefix;
*base = 2;
return 1;
}
}
/* FALL THROUGH */
case 'a':
case 'c':
case 'd':
case 'e':
case 'f':
if (*state == begin ||
*state == havesign ||
*state == havezero ||
*state == haveprefix ||
*state == any) {
if (*base > c - 'a' + 10) {
*state = any;
return 1;
}
}
break;
case 'B':
if (*state == havezero) {
if (*base == 0 || *base == 2) {
*state = haveprefix;
*base = 2;
return 1;
}
}
/* FALL THROUGH */
case 'A':
case 'C':
case 'D':
case 'E':
case 'F':
if (*state == begin ||
*state == havesign ||
*state == havezero ||
*state == haveprefix ||
*state == any) {
if (*base > c - 'A' + 10) {
*state = any;
return 1;
}
}
break;
case 'x':
case 'X':
if (*state == havezero) {
if (*base == 0 || *base == 16) {
*state = haveprefix;
*base = 16;
return 1;
}
}
break;
}
return 0;
}
/*
* Read an integer, storing it in buf.
*
* Return 0 on a match failure, and the number of characters read
* otherwise.
*/
static __inline int
parseint(FILE *fp, char * __restrict buf, int width, int base)
{
enum parseint_state state = begin;
char *p;
int c;
for (p = buf; width; width--) {
c = __sgetc(fp);
if (c == EOF)
break;
if (!parseint_fsm(c, &state, &base))
break;
*p++ = c;
}
/*
* If we only had a sign, push it back. If we only had a 0b or 0x
* prefix (possibly preceded by a sign), we view it as "0" and
* push back the letter. In all other cases, if we stopped
* because we read a non-number character, push it back.
*/
if (state == havesign) {
p--;
(void) __ungetc(*(u_char *)p, fp);
} else if (state == haveprefix) {
p--;
(void) __ungetc(c, fp);
} else if (width && c != EOF) {
(void) __ungetc(c, fp);
}
return (p - buf);
}
/*
* __vfscanf - MT-safe version
*/
int
__vfscanf(FILE *fp, char const *fmt0, va_list ap)
{
int ret;
FLOCKFILE_CANCELSAFE(fp);
ret = __svfscanf(fp, __get_locale(), fmt0, ap);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
int
vfscanf_l(FILE *fp, locale_t locale, char const *fmt0, va_list ap)
{
int ret;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
ret = __svfscanf(fp, locale, fmt0, ap);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
/*
* __svfscanf - non-MT-safe version of __vfscanf
*/
int
__svfscanf(FILE *fp, locale_t locale, const char *fmt0, va_list ap)
{
#define GETARG(type) ((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type))
const u_char *fmt = (const u_char *)fmt0;
int c; /* character from format, or conversion */
size_t width; /* field width, or 0 */
int flags; /* flags as defined above */
int nassigned; /* number of fields assigned */
int nconversions; /* number of conversions */
int nr; /* characters read by the current conversion */
int nread; /* number of characters consumed from fp */
int base; /* base argument to conversion function */
char ccltab[256]; /* character class table for %[...] */
char buf[BUF]; /* buffer for numeric conversions */
ORIENT(fp, -1);
nassigned = 0;
nconversions = 0;
nread = 0;
for (;;) {
c = *fmt++;
if (c == 0)
return (nassigned);
if (isspace(c)) {
while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p))
nread++, fp->_r--, fp->_p++;
continue;
}
if (c != '%')
goto literal;
width = 0;
flags = 0;
/*
* switch on the format. continue if done;
* break once format type is derived.
*/
again: c = *fmt++;
switch (c) {
case '%':
literal:
if (fp->_r <= 0 && __srefill(fp))
goto input_failure;
if (*fp->_p != c)
goto match_failure;
fp->_r--, fp->_p++;
nread++;
continue;
case '*':
flags |= SUPPRESS;
goto again;
case 'j':
flags |= INTMAXT;
goto again;
case 'l':
if (flags & LONG) {
flags &= ~LONG;
flags |= LONGLONG;
} else
flags |= LONG;
goto again;
case 'q':
flags |= LONGLONG; /* not quite */
goto again;
case 't':
flags |= PTRDIFFT;
goto again;
case 'w':
/*
* Fixed-width integer types. On all platforms we
* support, int8_t is equivalent to char, int16_t
* is equivalent to short, int32_t is equivalent
* to int, int64_t is equivalent to long long int.
* Furthermore, int_fast8_t, int_fast16_t and
* int_fast32_t are equivalent to int, and
* int_fast64_t is equivalent to long long int.
*/
flags &= ~(SHORTSHORT|SHORT|LONG|LONGLONG|SIZET|INTMAXT|PTRDIFFT);
if (fmt[0] == 'f') {
flags |= FASTINT;
fmt++;
} else {
flags &= ~FASTINT;
}
if (fmt[0] == '8') {
if (!(flags & FASTINT))
flags |= SHORTSHORT;
else
/* no flag set = 32 */ ;
fmt += 1;
} else if (fmt[0] == '1' && fmt[1] == '6') {
if (!(flags & FASTINT))
flags |= SHORT;
else
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '3' && fmt[1] == '2') {
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '6' && fmt[1] == '4') {
flags |= LONGLONG;
fmt += 2;
} else {
goto match_failure;
}
goto again;
case 'z':
flags |= SIZET;
goto again;
case 'L':
flags |= LONGDBL;
goto again;
case 'h':
if (flags & SHORT) {
flags &= ~SHORT;
flags |= SHORTSHORT;
} else
flags |= SHORT;
goto again;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
width = width * 10 + c - '0';
goto again;
/*
* Conversions.
*/
case 'B':
case 'b':
c = CT_INT;
flags |= UNSIGNED;
base = 2;
break;
case 'd':
c = CT_INT;
base = 10;
break;
case 'i':
c = CT_INT;
base = 0;
break;
case 'o':
c = CT_INT;
flags |= UNSIGNED;
base = 8;
break;
case 'u':
c = CT_INT;
flags |= UNSIGNED;
base = 10;
break;
case 'X':
case 'x':
c = CT_INT;
flags |= UNSIGNED;
base = 16;
break;
#ifndef NO_FLOATING_POINT
case 'A': case 'E': case 'F': case 'G':
case 'a': case 'e': case 'f': case 'g':
c = CT_FLOAT;
break;
#endif
case 'S':
flags |= LONG;
/* FALLTHROUGH */
case 's':
c = CT_STRING;
break;
case '[':
fmt = __sccl(ccltab, fmt);
flags |= NOSKIP;
c = CT_CCL;
break;
case 'C':
flags |= LONG;
/* FALLTHROUGH */
case 'c':
flags |= NOSKIP;
c = CT_CHAR;
break;
case 'p': /* pointer format is like hex */
flags |= POINTER;
c = CT_INT; /* assumes sizeof(uintmax_t) */
flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
base = 16;
break;
case 'n':
if (flags & SUPPRESS) /* ??? */
continue;
if (flags & SHORTSHORT)
*va_arg(ap, char *) = nread;
else if (flags & SHORT)
*va_arg(ap, short *) = nread;
else if (flags & LONG)
*va_arg(ap, long *) = nread;
else if (flags & LONGLONG)
*va_arg(ap, long long *) = nread;
else if (flags & INTMAXT)
*va_arg(ap, intmax_t *) = nread;
else if (flags & SIZET)
*va_arg(ap, size_t *) = nread;
else if (flags & PTRDIFFT)
*va_arg(ap, ptrdiff_t *) = nread;
else
*va_arg(ap, int *) = nread;
continue;
default:
goto match_failure;
/*
* Disgusting backwards compatibility hack. XXX
*/
case '\0': /* compat */
return (EOF);
}
/*
* We have a conversion that requires input.
*/
if (fp->_r <= 0 && __srefill(fp))
goto input_failure;
/*
* Consume leading white space, except for formats
* that suppress this.
*/
if ((flags & NOSKIP) == 0) {
while (isspace(*fp->_p)) {
nread++;
if (--fp->_r > 0)
fp->_p++;
else if (__srefill(fp))
goto input_failure;
}
/*
* Note that there is at least one character in
* the buffer, so conversions that do not set NOSKIP
* ca no longer result in an input failure.
*/
}
/*
* Do the conversion.
*/
switch (c) {
case CT_CHAR:
/* scan arbitrary characters (sets NOSKIP) */
if (width == 0)
width = 1;
if (flags & LONG) {
nr = convert_wchar(fp, GETARG(wchar_t *),
width, locale);
} else {
nr = convert_char(fp, GETARG(char *), width);
}
if (nr < 0)
goto input_failure;
break;
case CT_CCL:
/* scan a (nonempty) character class (sets NOSKIP) */
if (width == 0)
width = (size_t)~0; /* `infinity' */
if (flags & LONG) {
nr = convert_wccl(fp, GETARG(wchar_t *), width,
ccltab, locale);
} else {
nr = convert_ccl(fp, GETARG(char *), width,
ccltab);
}
if (nr <= 0) {
if (nr < 0)
goto input_failure;
else /* nr == 0 */
goto match_failure;
}
break;
case CT_STRING:
/* like CCL, but zero-length string OK, & no NOSKIP */
if (width == 0)
width = (size_t)~0;
if (flags & LONG) {
nr = convert_wstring(fp, GETARG(wchar_t *),
width, locale);
} else {
nr = convert_string(fp, GETARG(char *), width);
}
if (nr < 0)
goto input_failure;
break;
case CT_INT:
/* scan an integer as if by the conversion function */
#ifdef hardway
if (width == 0 || width > sizeof(buf) - 1)
width = sizeof(buf) - 1;
#else
/* size_t is unsigned, hence this optimisation */
if (--width > sizeof(buf) - 2)
width = sizeof(buf) - 2;
width++;
#endif
nr = parseint(fp, buf, width, base);
if (nr == 0)
goto match_failure;
if ((flags & SUPPRESS) == 0) {
uintmax_t res;
buf[nr] = '\0';
if ((flags & UNSIGNED) == 0)
res = strtoimax_l(buf, (char **)NULL, base, locale);
else
res = strtoumax_l(buf, (char **)NULL, base, locale);
if (flags & POINTER)
*va_arg(ap, void **) =
(void *)(uintptr_t)res;
else if (flags & SHORTSHORT)
*va_arg(ap, char *) = res;
else if (flags & SHORT)
*va_arg(ap, short *) = res;
else if (flags & LONG)
*va_arg(ap, long *) = res;
else if (flags & LONGLONG)
*va_arg(ap, long long *) = res;
else if (flags & INTMAXT)
*va_arg(ap, intmax_t *) = res;
else if (flags & PTRDIFFT)
*va_arg(ap, ptrdiff_t *) = res;
else if (flags & SIZET)
*va_arg(ap, size_t *) = res;
else
*va_arg(ap, int *) = res;
}
break;
#ifndef NO_FLOATING_POINT
case CT_FLOAT:
/* scan a floating point number as if by strtod */
if (width == 0 || width > sizeof(buf) - 1)
width = sizeof(buf) - 1;
nr = parsefloat(fp, buf, buf + width, locale);
if (nr == 0)
goto match_failure;
if ((flags & SUPPRESS) == 0) {
if (flags & LONGDBL) {
long double res = strtold_l(buf, NULL,
locale);
*va_arg(ap, long double *) = res;
} else if (flags & LONG) {
double res = strtod_l(buf, NULL,
locale);
*va_arg(ap, double *) = res;
} else {
float res = strtof_l(buf, NULL, locale);
*va_arg(ap, float *) = res;
}
}
break;
#endif /* !NO_FLOATING_POINT */
}
if (!(flags & SUPPRESS))
nassigned++;
nread += nr;
nconversions++;
}
input_failure:
return (nconversions != 0 ? nassigned : EOF);
match_failure:
return (nassigned);
}
/*
* Fill in the given table from the scanset at the given format
* (just after `['). Return a pointer to the character past the
* closing `]'. The table has a 1 wherever characters should be
* considered part of the scanset.
*/
static const u_char *
__sccl(char *tab, const u_char *fmt)
{
int c, n, v, i;
struct xlocale_collate *table =
(struct xlocale_collate*)__get_locale()->components[XLC_COLLATE];
/* first `clear' the whole table */
c = *fmt++; /* first char hat => negated scanset */
if (c == '^') {
v = 1; /* default => accept */
c = *fmt++; /* get new first char */
} else
v = 0; /* default => reject */
/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
(void) memset(tab, v, 256);
if (c == 0)
return (fmt - 1);/* format ended before closing ] */
/*
* Now set the entries corresponding to the actual scanset
* to the opposite of the above.
*
* The first character may be ']' (or '-') without being special;
* the last character may be '-'.
*/
v = 1 - v;
for (;;) {
tab[c] = v; /* take character c */
doswitch:
n = *fmt++; /* and examine the next */
switch (n) {
case 0: /* format ended too soon */
return (fmt - 1);
case '-':
/*
* A scanset of the form
* [01+-]
* is defined as `the digit 0, the digit 1,
* the character +, the character -', but
* the effect of a scanset such as
* [a-zA-Z0-9]
* is implementation defined. The V7 Unix
* scanf treats `a-z' as `the letters a through
* z', but treats `a-a' as `the letter a, the
* character -, and the letter a'.
*
* For compatibility, the `-' is not considered
* to define a range if the character following
* it is either a close bracket (required by ANSI)
* or is not numerically greater than the character
* we just stored in the table (c).
*/
n = *fmt;
if (n == ']'
|| (table->__collate_load_error ? n < c :
__collate_range_cmp(n, c) < 0
)
) {
c = '-';
break; /* resume the for(;;) */
}
fmt++;
/* fill in the range */
if (table->__collate_load_error) {
do {
tab[++c] = v;
} while (c < n);
} else {
for (i = 0; i < 256; i ++)
if (__collate_range_cmp(c, i) <= 0 &&
__collate_range_cmp(i, n) <= 0
)
tab[i] = v;
}
#if 1 /* XXX another disgusting compatibility hack */
c = n;
/*
* Alas, the V7 Unix scanf also treats formats
* such as [a-c-e] as `the letters a through e'.
* This too is permitted by the standard....
*/
goto doswitch;
#else
c = *fmt++;
if (c == 0)
return (fmt - 1);
if (c == ']')
return (fmt);
#endif
break;
case ']': /* end of scanset */
return (fmt);
default: /* just another character */
c = n;
break;
}
}
/* NOTREACHED */
}
#ifndef NO_FLOATING_POINT
static int
parsefloat(FILE *fp, char *buf, char *end, locale_t locale)
{
char *commit, *p;
int infnanpos = 0, decptpos = 0;
enum {
S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
S_DIGITS, S_DECPT, S_FRAC, S_EXP, S_EXPDIGITS
} state = S_START;
unsigned char c;
const char *decpt = localeconv_l(locale)->decimal_point;
_Bool gotmantdig = 0, ishex = 0;
/*
* We set commit = p whenever the string we have read so far
* constitutes a valid representation of a floating point
* number by itself. At some point, the parse will complete
* or fail, and we will ungetc() back to the last commit point.
* To ensure that the file offset gets updated properly, it is
* always necessary to read at least one character that doesn't
* match; thus, we can't short-circuit "infinity" or "nan(...)".
*/
commit = buf - 1;
for (p = buf; p < end; ) {
c = *fp->_p;
reswitch:
switch (state) {
case S_START:
state = S_GOTSIGN;
if (c == '-' || c == '+')
break;
else
goto reswitch;
case S_GOTSIGN:
switch (c) {
case '0':
state = S_MAYBEHEX;
commit = p;
break;
case 'I':
case 'i':
state = S_INF;
break;
case 'N':
case 'n':
state = S_NAN;
break;
default:
state = S_DIGITS;
goto reswitch;
}
break;
case S_INF:
if (infnanpos > 6 ||
(c != "nfinity"[infnanpos] &&
c != "NFINITY"[infnanpos]))
goto parsedone;
if (infnanpos == 1 || infnanpos == 6)
commit = p; /* inf or infinity */
infnanpos++;
break;
case S_NAN:
switch (infnanpos) {
case 0:
if (c != 'A' && c != 'a')
goto parsedone;
break;
case 1:
if (c != 'N' && c != 'n')
goto parsedone;
else
commit = p;
break;
case 2:
if (c != '(')
goto parsedone;
break;
default:
if (c == ')') {
commit = p;
state = S_DONE;
} else if (!isalnum(c) && c != '_')
goto parsedone;
break;
}
infnanpos++;
break;
case S_DONE:
goto parsedone;
case S_MAYBEHEX:
state = S_DIGITS;
if (c == 'X' || c == 'x') {
ishex = 1;
break;
} else { /* we saw a '0', but no 'x' */
gotmantdig = 1;
goto reswitch;
}
case S_DIGITS:
if ((ishex && isxdigit(c)) || isdigit(c)) {
gotmantdig = 1;
commit = p;
break;
} else {
state = S_DECPT;
goto reswitch;
}
case S_DECPT:
if (c == decpt[decptpos]) {
if (decpt[++decptpos] == '\0') {
/* We read the complete decpt seq. */
state = S_FRAC;
if (gotmantdig)
commit = p;
}
break;
} else if (!decptpos) {
/* We didn't read any decpt characters. */
state = S_FRAC;
goto reswitch;
} else {
/*
* We read part of a multibyte decimal point,
* but the rest is invalid, so bail.
*/
goto parsedone;
}
case S_FRAC:
if (((c == 'E' || c == 'e') && !ishex) ||
((c == 'P' || c == 'p') && ishex)) {
if (!gotmantdig)
goto parsedone;
else
state = S_EXP;
} else if ((ishex && isxdigit(c)) || isdigit(c)) {
commit = p;
gotmantdig = 1;
} else
goto parsedone;
break;
case S_EXP:
state = S_EXPDIGITS;
if (c == '-' || c == '+')
break;
else
goto reswitch;
case S_EXPDIGITS:
if (isdigit(c))
commit = p;
else
goto parsedone;
break;
default:
abort();
}
*p++ = c;
if (--fp->_r > 0)
fp->_p++;
else if (__srefill(fp))
break; /* EOF */
}
parsedone:
while (commit < --p)
__ungetc(*(u_char *)p, fp);
*++commit = '\0';
return (commit - buf);
}
#endif
diff --git a/lib/libc/stdio/vfwprintf.c b/lib/libc/stdio/vfwprintf.c
index d298ed03f521..b606eec0d9a4 100644
--- a/lib/libc/stdio/vfwprintf.c
+++ b/lib/libc/stdio/vfwprintf.c
@@ -1,1166 +1,1165 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vfprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#endif
-#include <sys/cdefs.h>
/*
* Actual wprintf innards.
*
* Avoid making gratuitous changes to this source file; it should be kept
* as close as possible to vfprintf.c for ease of maintenance.
*/
#include "namespace.h"
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "fvwrite.h"
#include "printflocal.h"
#include "xlocale_private.h"
static int __sprint(FILE *, struct __suio *, locale_t);
static int __sbprintf(FILE *, locale_t, const wchar_t *, va_list) __noinline;
static wint_t __xfputwc(wchar_t, FILE *, locale_t);
static wchar_t *__mbsconv(char *, int);
#define CHAR wchar_t
#include "printfcommon.h"
struct grouping_state {
wchar_t thousands_sep; /* locale-specific thousands separator */
const char *grouping; /* locale-specific numeric grouping rules */
int lead; /* sig figs before decimal or group sep */
int nseps; /* number of group separators with ' */
int nrepeats; /* number of repeats of the last group */
};
static const mbstate_t initial_mbs;
static inline wchar_t
get_decpt(locale_t locale)
{
mbstate_t mbs;
wchar_t decpt;
int nconv;
mbs = initial_mbs;
nconv = mbrtowc(&decpt, localeconv_l(locale)->decimal_point, MB_CUR_MAX, &mbs);
if (nconv == (size_t)-1 || nconv == (size_t)-2)
decpt = '.'; /* failsafe */
return (decpt);
}
static inline wchar_t
get_thousep(locale_t locale)
{
mbstate_t mbs;
wchar_t thousep;
int nconv;
mbs = initial_mbs;
nconv = mbrtowc(&thousep, localeconv_l(locale)->thousands_sep,
MB_CUR_MAX, &mbs);
if (nconv == (size_t)-1 || nconv == (size_t)-2)
thousep = '\0'; /* failsafe */
return (thousep);
}
/*
* Initialize the thousands' grouping state in preparation to print a
* number with ndigits digits. This routine returns the total number
* of wide characters that will be printed.
*/
static int
grouping_init(struct grouping_state *gs, int ndigits, locale_t locale)
{
gs->grouping = localeconv_l(locale)->grouping;
gs->thousands_sep = get_thousep(locale);
gs->nseps = gs->nrepeats = 0;
gs->lead = ndigits;
while (*gs->grouping != CHAR_MAX) {
if (gs->lead <= *gs->grouping)
break;
gs->lead -= *gs->grouping;
if (*(gs->grouping+1)) {
gs->nseps++;
gs->grouping++;
} else
gs->nrepeats++;
}
return (gs->nseps + gs->nrepeats);
}
/*
* Print a number with thousands' separators.
*/
static int
grouping_print(struct grouping_state *gs, struct io_state *iop,
const CHAR *cp, const CHAR *ep, locale_t locale)
{
const CHAR *cp0 = cp;
if (io_printandpad(iop, cp, ep, gs->lead, zeroes, locale))
return (-1);
cp += gs->lead;
while (gs->nseps > 0 || gs->nrepeats > 0) {
if (gs->nrepeats > 0)
gs->nrepeats--;
else {
gs->grouping--;
gs->nseps--;
}
if (io_print(iop, &gs->thousands_sep, 1, locale))
return (-1);
if (io_printandpad(iop, cp, ep, *gs->grouping, zeroes, locale))
return (-1);
cp += *gs->grouping;
}
if (cp > ep)
cp = ep;
return (cp - cp0);
}
/*
* Flush out all the vectors defined by the given uio,
* then reset it so that it can be reused.
*
* XXX The fact that we do this a character at a time and convert to a
* multibyte character sequence even if the destination is a wide
* string eclipses the benefits of buffering.
*/
static int
__sprint(FILE *fp, struct __suio *uio, locale_t locale)
{
struct __siov *iov;
wchar_t *p;
int i, len;
iov = uio->uio_iov;
for (; uio->uio_resid != 0; uio->uio_resid -= len, iov++) {
p = (wchar_t *)iov->iov_base;
len = iov->iov_len;
for (i = 0; i < len; i++) {
if (__xfputwc(p[i], fp, locale) == WEOF)
return (-1);
}
}
uio->uio_iovcnt = 0;
return (0);
}
/*
* Helper function for `fprintf to unbuffered unix file': creates a
* temporary buffer. We only work on write-only files; this avoids
* worries about ungetc buffers and so forth.
*/
static int
__sbprintf(FILE *fp, locale_t locale, const wchar_t *fmt, va_list ap)
{
int ret;
FILE fake;
unsigned char buf[BUFSIZ];
/* XXX This is probably not needed. */
if (prepwrite(fp) != 0)
return (EOF);
/* copy the important variables */
fake._flags = fp->_flags & ~__SNBF;
fake._file = fp->_file;
fake._cookie = fp->_cookie;
fake._write = fp->_write;
fake._orientation = fp->_orientation;
fake._mbstate = fp->_mbstate;
/* set up the buffer */
fake._bf._base = fake._p = buf;
fake._bf._size = fake._w = sizeof(buf);
fake._lbfsize = 0; /* not actually used, but Just In Case */
/* do the work, then copy any error status */
ret = __vfwprintf(&fake, locale, fmt, ap);
if (ret >= 0 && __fflush(&fake))
ret = WEOF;
if (fake._flags & __SERR)
fp->_flags |= __SERR;
return (ret);
}
/*
* Like __fputwc, but handles fake string (__SSTR) files properly.
* File must already be locked.
*/
static wint_t
__xfputwc(wchar_t wc, FILE *fp, locale_t locale)
{
mbstate_t mbs;
char buf[MB_LEN_MAX];
struct __suio uio;
struct __siov iov;
size_t len;
if ((fp->_flags & __SSTR) == 0)
return (__fputwc(wc, fp, locale));
mbs = initial_mbs;
if ((len = wcrtomb(buf, wc, &mbs)) == (size_t)-1) {
fp->_flags |= __SERR;
return (WEOF);
}
uio.uio_iov = &iov;
uio.uio_resid = len;
uio.uio_iovcnt = 1;
iov.iov_base = buf;
iov.iov_len = len;
return (__sfvwrite(fp, &uio) != EOF ? (wint_t)wc : WEOF);
}
/*
* Convert a multibyte character string argument for the %s format to a wide
* string representation. ``prec'' specifies the maximum number of bytes
* to output. If ``prec'' is greater than or equal to zero, we can't assume
* that the multibyte char. string ends in a null character.
*/
static wchar_t *
__mbsconv(char *mbsarg, int prec)
{
mbstate_t mbs;
wchar_t *convbuf, *wcp;
const char *p;
size_t insize, nchars, nconv;
if (mbsarg == NULL)
return (NULL);
/*
* Supplied argument is a multibyte string; convert it to wide
* characters first.
*/
if (prec >= 0) {
/*
* String is not guaranteed to be NUL-terminated. Find the
* number of characters to print.
*/
p = mbsarg;
insize = nchars = nconv = 0;
mbs = initial_mbs;
while (nchars != (size_t)prec) {
nconv = mbrlen(p, MB_CUR_MAX, &mbs);
if (nconv == 0 || nconv == (size_t)-1 ||
nconv == (size_t)-2)
break;
p += nconv;
nchars++;
insize += nconv;
}
if (nconv == (size_t)-1 || nconv == (size_t)-2)
return (NULL);
} else {
insize = strlen(mbsarg);
nconv = 0;
}
/*
* Allocate buffer for the result and perform the conversion,
* converting at most `size' bytes of the input multibyte string to
* wide characters for printing.
*/
convbuf = malloc((insize + 1) * sizeof(*convbuf));
if (convbuf == NULL)
return (NULL);
wcp = convbuf;
p = mbsarg;
mbs = initial_mbs;
while (insize != 0) {
nconv = mbrtowc(wcp, p, insize, &mbs);
if (nconv == 0 || nconv == (size_t)-1 || nconv == (size_t)-2)
break;
wcp++;
p += nconv;
insize -= nconv;
}
if (nconv == (size_t)-1 || nconv == (size_t)-2) {
free(convbuf);
return (NULL);
}
*wcp = L'\0';
return (convbuf);
}
/*
* MT-safe version
*/
int
vfwprintf_l(FILE * __restrict fp, locale_t locale,
const wchar_t * __restrict fmt0, va_list ap)
{
int ret;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
/* optimise fprintf(stderr) (and other unbuffered Unix files) */
if ((fp->_flags & (__SNBF|__SWR|__SRW)) == (__SNBF|__SWR) &&
fp->_file >= 0)
ret = __sbprintf(fp, locale, fmt0, ap);
else
ret = __vfwprintf(fp, locale, fmt0, ap);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
int
vfwprintf(FILE * __restrict fp, const wchar_t * __restrict fmt0, va_list ap)
{
return vfwprintf_l(fp, __get_locale(), fmt0, ap);
}
/*
* The size of the buffer we use as scratch space for integer
* conversions, among other things. We need enough space to
* write a uintmax_t in octal (plus one byte).
*/
#if UINTMAX_MAX <= UINT64_MAX
#define BUF 32
#else
#error "BUF must be large enough to format a uintmax_t"
#endif
/*
* Non-MT-safe version
*/
int
__vfwprintf(FILE *fp, locale_t locale, const wchar_t *fmt0, va_list ap)
{
wchar_t *fmt; /* format string */
wchar_t ch; /* character from fmt */
int n, n2; /* handy integer (short term usage) */
wchar_t *cp; /* handy char pointer (short term usage) */
int flags; /* flags as above */
int ret; /* return value accumulator */
int width; /* width from format (%8d), or 0 */
int prec; /* precision from format; <0 for N/A */
wchar_t sign; /* sign prefix (' ', '+', '-', or \0) */
struct grouping_state gs; /* thousands' grouping info */
#ifndef NO_FLOATING_POINT
/*
* We can decompose the printed representation of floating
* point numbers into several parts, some of which may be empty:
*
* [+|-| ] [0x|0X] MMM . NNN [e|E|p|P] [+|-] ZZ
* A B ---C--- D E F
*
* A: 'sign' holds this value if present; '\0' otherwise
* B: ox[1] holds the 'x' or 'X'; '\0' if not hexadecimal
* C: cp points to the string MMMNNN. Leading and trailing
* zeros are not in the string and must be added.
* D: expchar holds this character; '\0' if no exponent, e.g. %f
* F: at least two digits for decimal, at least one digit for hex
*/
wchar_t decimal_point; /* locale specific decimal point */
int signflag; /* true if float is negative */
union { /* floating point arguments %[aAeEfFgG] */
double dbl;
long double ldbl;
} fparg;
int expt; /* integer value of exponent */
char expchar; /* exponent character: [eEpP\0] */
char *dtoaend; /* pointer to end of converted digits */
int expsize; /* character count for expstr */
int ndig; /* actual number of digits returned by dtoa */
wchar_t expstr[MAXEXPDIG+2]; /* buffer for exponent string: e+ZZZ */
char *dtoaresult; /* buffer allocated by dtoa */
#endif
u_long ulval; /* integer arguments %[diouxX] */
uintmax_t ujval; /* %j, %ll, %q, %t, %z integers */
int base; /* base for [diouxX] conversion */
int dprec; /* a copy of prec if [diouxX], 0 otherwise */
int realsz; /* field size expanded by dprec, sign, etc */
int size; /* size of converted field or string */
int prsize; /* max size of printed field */
const char *xdigs; /* digits for [xX] conversion */
struct io_state io; /* I/O buffering state */
wchar_t buf[BUF]; /* buffer with space for digits of uintmax_t */
wchar_t ox[2]; /* space for 0x hex-prefix */
union arg *argtable; /* args, built due to positional arg */
union arg statargtable [STATIC_ARG_TBL_SIZE];
int nextarg; /* 1-based argument index */
va_list orgap; /* original argument pointer */
wchar_t *convbuf; /* multibyte to wide conversion result */
int savserr;
static const char xdigs_lower[16] = "0123456789abcdef";
static const char xdigs_upper[16] = "0123456789ABCDEF";
/* BEWARE, these `goto error' on error. */
#define PRINT(ptr, len) do { \
if (io_print(&io, (ptr), (len), locale)) \
goto error; \
} while (0)
#define PAD(howmany, with) { \
if (io_pad(&io, (howmany), (with), locale)) \
goto error; \
}
#define PRINTANDPAD(p, ep, len, with) { \
if (io_printandpad(&io, (p), (ep), (len), (with), locale)) \
goto error; \
}
#define FLUSH() { \
if (io_flush(&io, locale)) \
goto error; \
}
/*
* Get the argument indexed by nextarg. If the argument table is
* built, use it to get the argument. If its not, get the next
* argument (and arguments must be gotten sequentially).
*/
#define GETARG(type) \
((argtable != NULL) ? *((type*)(&argtable[nextarg++])) : \
(nextarg++, va_arg(ap, type)))
/*
* To extend shorts properly, we need both signed and unsigned
* argument extraction methods.
*/
#define SARG() \
(flags&LONGINT ? GETARG(long) : \
flags&SHORTINT ? (long)(short)GETARG(int) : \
flags&CHARINT ? (long)(signed char)GETARG(int) : \
(long)GETARG(int))
#define UARG() \
(flags&LONGINT ? GETARG(u_long) : \
flags&SHORTINT ? (u_long)(u_short)GETARG(int) : \
flags&CHARINT ? (u_long)(u_char)GETARG(int) : \
(u_long)GETARG(u_int))
#define INTMAX_SIZE (INTMAXT|SIZET|PTRDIFFT|LLONGINT)
#define SJARG() \
(flags&INTMAXT ? GETARG(intmax_t) : \
flags&SIZET ? (intmax_t)GETARG(ssize_t) : \
flags&PTRDIFFT ? (intmax_t)GETARG(ptrdiff_t) : \
(intmax_t)GETARG(long long))
#define UJARG() \
(flags&INTMAXT ? GETARG(uintmax_t) : \
flags&SIZET ? (uintmax_t)GETARG(size_t) : \
flags&PTRDIFFT ? (uintmax_t)GETARG(ptrdiff_t) : \
(uintmax_t)GETARG(unsigned long long))
/*
* Get * arguments, including the form *nn$. Preserve the nextarg
* that the argument can be gotten once the type is determined.
*/
#define GETASTER(val) \
n2 = 0; \
cp = fmt; \
while (is_digit(*cp)) { \
n2 = 10 * n2 + to_digit(*cp); \
cp++; \
} \
if (*cp == '$') { \
int hold = nextarg; \
if (argtable == NULL) { \
argtable = statargtable; \
if (__find_warguments (fmt0, orgap, &argtable)) { \
ret = EOF; \
goto error; \
} \
} \
nextarg = n2; \
val = GETARG (int); \
nextarg = hold; \
fmt = ++cp; \
} else { \
val = GETARG (int); \
}
/* sorry, fwprintf(read_only_file, L"") returns WEOF, not 0 */
if (prepwrite(fp) != 0) {
errno = EBADF;
return (EOF);
}
savserr = fp->_flags & __SERR;
fp->_flags &= ~__SERR;
convbuf = NULL;
fmt = (wchar_t *)fmt0;
argtable = NULL;
nextarg = 1;
va_copy(orgap, ap);
io_init(&io, fp);
ret = 0;
#ifndef NO_FLOATING_POINT
decimal_point = get_decpt(locale);
#endif
/*
* Scan the format for conversions (`%' character).
*/
for (;;) {
for (cp = fmt; (ch = *fmt) != '\0' && ch != '%'; fmt++)
/* void */;
if ((n = fmt - cp) != 0) {
if ((unsigned)ret + n > INT_MAX) {
ret = EOF;
errno = EOVERFLOW;
goto error;
}
PRINT(cp, n);
ret += n;
}
if (ch == '\0')
goto done;
fmt++; /* skip over '%' */
flags = 0;
dprec = 0;
width = 0;
prec = -1;
gs.grouping = NULL;
sign = '\0';
ox[1] = '\0';
rflag: ch = *fmt++;
reswitch: switch (ch) {
case ' ':
/*-
* ``If the space and + flags both appear, the space
* flag will be ignored.''
* -- ANSI X3J11
*/
if (!sign)
sign = ' ';
goto rflag;
case '#':
flags |= ALT;
goto rflag;
case '*':
/*-
* ``A negative field width argument is taken as a
* - flag followed by a positive field width.''
* -- ANSI X3J11
* They don't exclude field widths read from args.
*/
GETASTER (width);
if (width >= 0)
goto rflag;
width = -width;
/* FALLTHROUGH */
case '-':
flags |= LADJUST;
goto rflag;
case '+':
sign = '+';
goto rflag;
case '\'':
flags |= GROUPING;
goto rflag;
case '.':
if ((ch = *fmt++) == '*') {
GETASTER (prec);
goto rflag;
}
prec = 0;
while (is_digit(ch)) {
prec = 10 * prec + to_digit(ch);
ch = *fmt++;
}
goto reswitch;
case '0':
/*-
* ``Note that 0 is taken as a flag, not as the
* beginning of a field width.''
* -- ANSI X3J11
*/
flags |= ZEROPAD;
goto rflag;
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do {
n = 10 * n + to_digit(ch);
ch = *fmt++;
} while (is_digit(ch));
if (ch == '$') {
nextarg = n;
if (argtable == NULL) {
argtable = statargtable;
if (__find_warguments (fmt0, orgap,
&argtable)) {
ret = EOF;
goto error;
}
}
goto rflag;
}
width = n;
goto reswitch;
#ifndef NO_FLOATING_POINT
case 'L':
flags |= LONGDBL;
goto rflag;
#endif
case 'h':
if (flags & SHORTINT) {
flags &= ~SHORTINT;
flags |= CHARINT;
} else
flags |= SHORTINT;
goto rflag;
case 'j':
flags |= INTMAXT;
goto rflag;
case 'l':
if (flags & LONGINT) {
flags &= ~LONGINT;
flags |= LLONGINT;
} else
flags |= LONGINT;
goto rflag;
case 'q':
flags |= LLONGINT; /* not necessarily */
goto rflag;
case 't':
flags |= PTRDIFFT;
goto rflag;
case 'w':
/*
* Fixed-width integer types. On all platforms we
* support, int8_t is equivalent to char, int16_t
* is equivalent to short, int32_t is equivalent
* to int, int64_t is equivalent to long long int.
* Furthermore, int_fast8_t, int_fast16_t and
* int_fast32_t are equivalent to int, and
* int_fast64_t is equivalent to long long int.
*/
flags &= ~(CHARINT|SHORTINT|LONGINT|LLONGINT|INTMAXT);
if (fmt[0] == 'f') {
flags |= FASTINT;
fmt++;
} else {
flags &= ~FASTINT;
}
if (fmt[0] == '8') {
if (!(flags & FASTINT))
flags |= CHARINT;
else
/* no flag set = 32 */ ;
fmt += 1;
} else if (fmt[0] == '1' && fmt[1] == '6') {
if (!(flags & FASTINT))
flags |= SHORTINT;
else
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '3' && fmt[1] == '2') {
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '6' && fmt[1] == '4') {
flags |= LLONGINT;
fmt += 2;
} else {
if (flags & FASTINT) {
flags &= ~FASTINT;
fmt--;
}
goto invalid;
}
goto rflag;
case 'z':
flags |= SIZET;
goto rflag;
case 'B':
case 'b':
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 2;
/* leading 0b/B only if non-zero */
if (flags & ALT &&
(flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
ox[1] = ch;
goto nosign;
break;
case 'C':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'c':
if (flags & LONGINT)
*(cp = buf) = (wchar_t)GETARG(wint_t);
else
*(cp = buf) = (wchar_t)btowc(GETARG(int));
size = 1;
sign = '\0';
break;
case 'D':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'd':
case 'i':
if (flags & INTMAX_SIZE) {
ujval = SJARG();
if ((intmax_t)ujval < 0) {
ujval = -ujval;
sign = '-';
}
} else {
ulval = SARG();
if ((long)ulval < 0) {
ulval = -ulval;
sign = '-';
}
}
base = 10;
goto number;
#ifndef NO_FLOATING_POINT
case 'a':
case 'A':
if (ch == 'a') {
ox[1] = 'x';
xdigs = xdigs_lower;
expchar = 'p';
} else {
ox[1] = 'X';
xdigs = xdigs_upper;
expchar = 'P';
}
if (prec >= 0)
prec++;
if (flags & LONGDBL) {
fparg.ldbl = GETARG(long double);
dtoaresult =
__hldtoa(fparg.ldbl, xdigs, prec,
&expt, &signflag, &dtoaend);
} else {
fparg.dbl = GETARG(double);
dtoaresult =
__hdtoa(fparg.dbl, xdigs, prec,
&expt, &signflag, &dtoaend);
}
if (prec < 0)
prec = dtoaend - dtoaresult;
if (expt == INT_MAX)
ox[1] = '\0';
if (convbuf != NULL)
free(convbuf);
ndig = dtoaend - dtoaresult;
cp = convbuf = __mbsconv(dtoaresult, -1);
freedtoa(dtoaresult);
goto fp_common;
case 'e':
case 'E':
expchar = ch;
if (prec < 0) /* account for digit before decpt */
prec = DEFPREC + 1;
else
prec++;
goto fp_begin;
case 'f':
case 'F':
expchar = '\0';
goto fp_begin;
case 'g':
case 'G':
expchar = ch - ('g' - 'e');
if (prec == 0)
prec = 1;
fp_begin:
if (prec < 0)
prec = DEFPREC;
if (convbuf != NULL)
free(convbuf);
if (flags & LONGDBL) {
fparg.ldbl = GETARG(long double);
dtoaresult =
__ldtoa(&fparg.ldbl, expchar ? 2 : 3, prec,
&expt, &signflag, &dtoaend);
} else {
fparg.dbl = GETARG(double);
dtoaresult =
dtoa(fparg.dbl, expchar ? 2 : 3, prec,
&expt, &signflag, &dtoaend);
if (expt == 9999)
expt = INT_MAX;
}
ndig = dtoaend - dtoaresult;
cp = convbuf = __mbsconv(dtoaresult, -1);
freedtoa(dtoaresult);
fp_common:
if (signflag)
sign = '-';
if (expt == INT_MAX) { /* inf or nan */
if (*cp == 'N') {
cp = (ch >= 'a') ? L"nan" : L"NAN";
sign = '\0';
} else
cp = (ch >= 'a') ? L"inf" : L"INF";
size = 3;
flags &= ~ZEROPAD;
break;
}
flags |= FPT;
if (ch == 'g' || ch == 'G') {
if (expt > -4 && expt <= prec) {
/* Make %[gG] smell like %[fF] */
expchar = '\0';
if (flags & ALT)
prec -= expt;
else
prec = ndig - expt;
if (prec < 0)
prec = 0;
} else {
/*
* Make %[gG] smell like %[eE], but
* trim trailing zeroes if no # flag.
*/
if (!(flags & ALT))
prec = ndig;
}
}
if (expchar) {
expsize = exponent(expstr, expt - 1, expchar);
size = expsize + prec;
if (prec > 1 || flags & ALT)
++size;
} else {
/* space for digits before decimal point */
if (expt > 0)
size = expt;
else /* "0" */
size = 1;
/* space for decimal pt and following digits */
if (prec || flags & ALT)
size += prec + 1;
if ((flags & GROUPING) && expt > 0)
size += grouping_init(&gs, expt, locale);
}
break;
#endif /* !NO_FLOATING_POINT */
case 'n':
/*
* Assignment-like behavior is specified if the
* value overflows or is otherwise unrepresentable.
* C99 says to use `signed char' for %hhn conversions.
*/
if (flags & LLONGINT)
*GETARG(long long *) = ret;
else if (flags & SIZET)
*GETARG(ssize_t *) = (ssize_t)ret;
else if (flags & PTRDIFFT)
*GETARG(ptrdiff_t *) = ret;
else if (flags & INTMAXT)
*GETARG(intmax_t *) = ret;
else if (flags & LONGINT)
*GETARG(long *) = ret;
else if (flags & SHORTINT)
*GETARG(short *) = ret;
else if (flags & CHARINT)
*GETARG(signed char *) = ret;
else
*GETARG(int *) = ret;
continue; /* no output */
case 'O':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'o':
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 8;
goto nosign;
case 'p':
/*-
* ``The argument shall be a pointer to void. The
* value of the pointer is converted to a sequence
* of printable characters, in an implementation-
* defined manner.''
* -- ANSI X3J11
*/
ujval = (uintmax_t)(uintptr_t)GETARG(void *);
base = 16;
xdigs = xdigs_lower;
flags = flags | INTMAXT;
ox[1] = 'x';
goto nosign;
case 'S':
flags |= LONGINT;
/*FALLTHROUGH*/
case 's':
if (flags & LONGINT) {
if ((cp = GETARG(wchar_t *)) == NULL)
cp = L"(null)";
} else {
char *mbp;
if (convbuf != NULL)
free(convbuf);
if ((mbp = GETARG(char *)) == NULL)
cp = L"(null)";
else {
convbuf = __mbsconv(mbp, prec);
if (convbuf == NULL) {
fp->_flags |= __SERR;
goto error;
}
cp = convbuf;
}
}
size = (prec >= 0) ? wcsnlen(cp, prec) : wcslen(cp);
sign = '\0';
break;
case 'U':
flags |= LONGINT;
/*FALLTHROUGH*/
case 'u':
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 10;
goto nosign;
case 'X':
xdigs = xdigs_upper;
goto hex;
case 'x':
xdigs = xdigs_lower;
hex:
if (flags & INTMAX_SIZE)
ujval = UJARG();
else
ulval = UARG();
base = 16;
/* leading 0x/X only if non-zero */
if (flags & ALT &&
(flags & INTMAX_SIZE ? ujval != 0 : ulval != 0))
ox[1] = ch;
flags &= ~GROUPING;
/* unsigned conversions */
nosign: sign = '\0';
/*-
* ``... diouXx conversions ... if a precision is
* specified, the 0 flag will be ignored.''
* -- ANSI X3J11
*/
number: if ((dprec = prec) >= 0)
flags &= ~ZEROPAD;
/*-
* ``The result of converting a zero value with an
* explicit precision of zero is no characters.''
* -- ANSI X3J11
*
* ``The C Standard is clear enough as is. The call
* printf("%#.0o", 0) should print 0.''
* -- Defect Report #151
*/
cp = buf + BUF;
if (flags & INTMAX_SIZE) {
if (ujval != 0 || prec != 0 ||
(flags & ALT && base == 8))
cp = __ujtoa(ujval, cp, base,
flags & ALT, xdigs);
} else {
if (ulval != 0 || prec != 0 ||
(flags & ALT && base == 8))
cp = __ultoa(ulval, cp, base,
flags & ALT, xdigs);
}
size = buf + BUF - cp;
if (size > BUF) /* should never happen */
abort();
if ((flags & GROUPING) && size != 0)
size += grouping_init(&gs, size, locale);
break;
default: /* "%?" prints ?, unless ? is NUL */
if (ch == '\0')
goto done;
invalid:
/* pretend it was %c with argument ch */
cp = buf;
*cp = ch;
size = 1;
sign = '\0';
break;
}
/*
* All reasonable formats wind up here. At this point, `cp'
* points to a string which (if not flags&LADJUST) should be
* padded out to `width' places. If flags&ZEROPAD, it should
* first be prefixed by any sign or other prefix; otherwise,
* it should be blank padded before the prefix is emitted.
* After any left-hand padding and prefixing, emit zeroes
* required by a decimal [diouxX] precision, then print the
* string proper, then emit zeroes required by any leftover
* floating precision; finally, if LADJUST, pad with blanks.
*
* Compute actual size, so we know how much to pad.
* size excludes decimal prec; realsz includes it.
*/
realsz = dprec > size ? dprec : size;
if (sign)
realsz++;
if (ox[1])
realsz += 2;
prsize = width > realsz ? width : realsz;
if ((unsigned)ret + prsize > INT_MAX) {
ret = EOF;
errno = EOVERFLOW;
goto error;
}
/* right-adjusting blank padding */
if ((flags & (LADJUST|ZEROPAD)) == 0)
PAD(width - realsz, blanks);
/* prefix */
if (sign)
PRINT(&sign, 1);
if (ox[1]) { /* ox[1] is either x, X, or \0 */
ox[0] = '0';
PRINT(ox, 2);
}
/* right-adjusting zero padding */
if ((flags & (LADJUST|ZEROPAD)) == ZEROPAD)
PAD(width - realsz, zeroes);
/* the string or number proper */
#ifndef NO_FLOATING_POINT
if ((flags & FPT) == 0) {
#endif
/* leading zeroes from decimal precision */
PAD(dprec - size, zeroes);
if (gs.grouping) {
if (grouping_print(&gs, &io, cp, buf+BUF, locale) < 0)
goto error;
} else {
PRINT(cp, size);
}
#ifndef NO_FLOATING_POINT
} else { /* glue together f_p fragments */
if (!expchar) { /* %[fF] or sufficiently short %[gG] */
if (expt <= 0) {
PRINT(zeroes, 1);
if (prec || flags & ALT)
PRINT(&decimal_point, 1);
PAD(-expt, zeroes);
/* already handled initial 0's */
prec += expt;
} else {
if (gs.grouping) {
n = grouping_print(&gs, &io,
cp, convbuf + ndig, locale);
if (n < 0)
goto error;
cp += n;
} else {
PRINTANDPAD(cp, convbuf + ndig,
expt, zeroes);
cp += expt;
}
if (prec || flags & ALT)
PRINT(&decimal_point, 1);
}
PRINTANDPAD(cp, convbuf + ndig, prec, zeroes);
} else { /* %[eE] or sufficiently long %[gG] */
if (prec > 1 || flags & ALT) {
buf[0] = *cp++;
buf[1] = decimal_point;
PRINT(buf, 2);
PRINT(cp, ndig-1);
PAD(prec - ndig, zeroes);
} else /* XeYYY */
PRINT(cp, 1);
PRINT(expstr, expsize);
}
}
#endif
/* left-adjusting padding (always blank) */
if (flags & LADJUST)
PAD(width - realsz, blanks);
/* finally, adjust ret */
ret += prsize;
FLUSH(); /* copy out the I/O vectors */
}
done:
FLUSH();
error:
va_end(orgap);
if (convbuf != NULL)
free(convbuf);
if (__sferror(fp))
ret = EOF;
else
fp->_flags |= savserr;
if ((argtable != NULL) && (argtable != statargtable))
free (argtable);
return (ret);
/* NOTREACHED */
}
diff --git a/lib/libc/stdio/vfwscanf.c b/lib/libc/stdio/vfwscanf.c
index e2c730b5e7a9..fff3dbeac9ea 100644
--- a/lib/libc/stdio/vfwscanf.c
+++ b/lib/libc/stdio/vfwscanf.c
@@ -1,1017 +1,1016 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Copyright (c) 2023 Dag-Erling Smørgrav
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vfscanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#endif
-#include <sys/cdefs.h>
#include "namespace.h"
#include <ctype.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <stdarg.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
#define BUF 513 /* Maximum length of numeric string. */
/*
* Flags used during conversion.
*/
#define LONG 0x01 /* l: long or double */
#define LONGDBL 0x02 /* L: long double */
#define SHORT 0x04 /* h: short */
#define SUPPRESS 0x08 /* *: suppress assignment */
#define POINTER 0x10 /* p: void * (as hex) */
#define NOSKIP 0x20 /* [ or c: do not skip blanks */
#define FASTINT 0x200 /* wfN: int_fastN_t */
#define LONGLONG 0x400 /* ll: long long (+ deprecated q: quad) */
#define INTMAXT 0x800 /* j: intmax_t */
#define PTRDIFFT 0x1000 /* t: ptrdiff_t */
#define SIZET 0x2000 /* z: size_t */
#define SHORTSHORT 0x4000 /* hh: char */
#define UNSIGNED 0x8000 /* %[oupxX] conversions */
/*
* Conversion types.
*/
#define CT_CHAR 0 /* %c conversion */
#define CT_CCL 1 /* %[...] conversion */
#define CT_STRING 2 /* %s conversion */
#define CT_INT 3 /* %[dioupxX] conversion */
#define CT_FLOAT 4 /* %[efgEFG] conversion */
#ifndef NO_FLOATING_POINT
static int parsefloat(FILE *, wchar_t *, wchar_t *, locale_t);
#endif
struct ccl {
const wchar_t *start; /* character class start */
const wchar_t *end; /* character class end */
int compl; /* ccl is complemented? */
};
static __inline int
inccl(const struct ccl *ccl, wint_t wi)
{
if (ccl->compl) {
return (wmemchr(ccl->start, wi, ccl->end - ccl->start)
== NULL);
} else {
return (wmemchr(ccl->start, wi, ccl->end - ccl->start) != NULL);
}
}
/*
* Conversion functions are passed a pointer to this object instead of
* a real parameter to indicate that the assignment-suppression (*)
* flag was specified. We could use a NULL pointer to indicate this,
* but that would mask bugs in applications that call scanf() with a
* NULL pointer.
*/
static const int suppress;
#define SUPPRESS_PTR ((void *)&suppress)
static const mbstate_t initial_mbs;
/*
* The following conversion functions return the number of characters consumed,
* or -1 on input failure. Character class conversion returns 0 on match
* failure.
*/
static __inline int
convert_char(FILE *fp, char * mbp, int width, locale_t locale)
{
mbstate_t mbs;
size_t nconv;
wint_t wi;
int n;
n = 0;
mbs = initial_mbs;
while (width-- != 0 && (wi = __fgetwc(fp, locale)) != WEOF) {
if (mbp != SUPPRESS_PTR) {
nconv = wcrtomb(mbp, wi, &mbs);
if (nconv == (size_t)-1)
return (-1);
mbp += nconv;
}
n++;
}
if (n == 0)
return (-1);
return (n);
}
static __inline int
convert_wchar(FILE *fp, wchar_t *wcp, int width, locale_t locale)
{
wint_t wi;
int n;
n = 0;
while (width-- != 0 && (wi = __fgetwc(fp, locale)) != WEOF) {
if (wcp != SUPPRESS_PTR)
*wcp++ = (wchar_t)wi;
n++;
}
if (n == 0)
return (-1);
return (n);
}
static __inline int
convert_ccl(FILE *fp, char * mbp, int width, const struct ccl *ccl,
locale_t locale)
{
mbstate_t mbs;
size_t nconv;
wint_t wi;
int n;
n = 0;
mbs = initial_mbs;
while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 && inccl(ccl, wi)) {
if (mbp != SUPPRESS_PTR) {
nconv = wcrtomb(mbp, wi, &mbs);
if (nconv == (size_t)-1)
return (-1);
mbp += nconv;
}
n++;
}
if (wi != WEOF)
__ungetwc(wi, fp, locale);
if (mbp != SUPPRESS_PTR)
*mbp = 0;
return (n);
}
static __inline int
convert_wccl(FILE *fp, wchar_t *wcp, int width, const struct ccl *ccl,
locale_t locale)
{
wchar_t *wcp0;
wint_t wi;
int n;
if (wcp == SUPPRESS_PTR) {
n = 0;
while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 && inccl(ccl, wi))
n++;
if (wi != WEOF)
__ungetwc(wi, fp, locale);
} else {
wcp0 = wcp;
while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 && inccl(ccl, wi))
*wcp++ = (wchar_t)wi;
if (wi != WEOF)
__ungetwc(wi, fp, locale);
n = wcp - wcp0;
if (n == 0)
return (0);
*wcp = 0;
}
return (n);
}
static __inline int
convert_string(FILE *fp, char * mbp, int width, locale_t locale)
{
mbstate_t mbs;
size_t nconv;
wint_t wi;
int nread;
mbs = initial_mbs;
nread = 0;
while ((wi = __fgetwc(fp, locale)) != WEOF && width-- != 0 &&
!iswspace(wi)) {
if (mbp != SUPPRESS_PTR) {
nconv = wcrtomb(mbp, wi, &mbs);
if (nconv == (size_t)-1)
return (-1);
mbp += nconv;
}
nread++;
}
if (wi != WEOF)
__ungetwc(wi, fp, locale);
if (mbp != SUPPRESS_PTR)
*mbp = 0;
return (nread);
}
static __inline int
convert_wstring(FILE *fp, wchar_t *wcp, int width, locale_t locale)
{
wint_t wi;
int nread;
nread = 0;
if (wcp == SUPPRESS_PTR) {
while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 && !iswspace(wi))
nread++;
if (wi != WEOF)
__ungetwc(wi, fp, locale);
} else {
while ((wi = __fgetwc(fp, locale)) != WEOF &&
width-- != 0 && !iswspace(wi)) {
*wcp++ = (wchar_t)wi;
nread++;
}
if (wi != WEOF)
__ungetwc(wi, fp, locale);
*wcp = '\0';
}
return (nread);
}
enum parseint_state {
begin,
havesign,
havezero,
haveprefix,
any,
};
static __inline int
parseint_fsm(wchar_t c, enum parseint_state *state, int *base)
{
switch (c) {
case '+':
case '-':
if (*state == begin) {
*state = havesign;
return 1;
}
break;
case '0':
if (*state == begin || *state == havesign) {
*state = havezero;
} else {
*state = any;
}
return 1;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
if (*state == havezero && *base == 0) {
*base = 8;
}
/* FALL THROUGH */
case '8':
case '9':
if (*state == begin ||
*state == havesign) {
if (*base == 0) {
*base = 10;
}
}
if (*state == begin ||
*state == havesign ||
*state == havezero ||
*state == haveprefix ||
*state == any) {
if (*base > c - '0') {
*state = any;
return 1;
}
}
break;
case 'b':
if (*state == havezero) {
if (*base == 0 || *base == 2) {
*state = haveprefix;
*base = 2;
return 1;
}
}
/* FALL THROUGH */
case 'a':
case 'c':
case 'd':
case 'e':
case 'f':
if (*state == begin ||
*state == havesign ||
*state == havezero ||
*state == haveprefix ||
*state == any) {
if (*base > c - 'a' + 10) {
*state = any;
return 1;
}
}
break;
case 'B':
if (*state == havezero) {
if (*base == 0 || *base == 2) {
*state = haveprefix;
*base = 2;
return 1;
}
}
/* FALL THROUGH */
case 'A':
case 'C':
case 'D':
case 'E':
case 'F':
if (*state == begin ||
*state == havesign ||
*state == havezero ||
*state == haveprefix ||
*state == any) {
if (*base > c - 'A' + 10) {
*state = any;
return 1;
}
}
break;
case 'x':
case 'X':
if (*state == havezero) {
if (*base == 0 || *base == 16) {
*state = haveprefix;
*base = 16;
return 1;
}
}
break;
}
return 0;
}
/*
* Read an integer, storing it in buf.
*
* Return 0 on a match failure, and the number of characters read
* otherwise.
*/
static __inline int
parseint(FILE *fp, wchar_t * __restrict buf, int width, int base,
locale_t locale)
{
enum parseint_state state = begin;
wchar_t *wcp;
int c;
for (wcp = buf; width; width--) {
c = __fgetwc(fp, locale);
if (c == WEOF)
break;
if (!parseint_fsm(c, &state, &base))
break;
*wcp++ = (wchar_t)c;
}
/*
* If we only had a sign, push it back. If we only had a 0b or 0x
* prefix (possibly preceded by a sign), we view it as "0" and
* push back the letter. In all other cases, if we stopped
* because we read a non-number character, push it back.
*/
if (state == havesign) {
wcp--;
__ungetwc(*wcp, fp, locale);
} else if (state == haveprefix) {
wcp--;
__ungetwc(c, fp, locale);
} else if (width && c != WEOF) {
__ungetwc(c, fp, locale);
}
return (wcp - buf);
}
/*
* MT-safe version.
*/
int
vfwscanf_l(FILE * __restrict fp, locale_t locale,
const wchar_t * __restrict fmt, va_list ap)
{
int ret;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(fp);
ORIENT(fp, 1);
ret = __vfwscanf(fp, locale, fmt, ap);
FUNLOCKFILE_CANCELSAFE();
return (ret);
}
int
vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
{
return vfwscanf_l(fp, __get_locale(), fmt, ap);
}
/*
* Non-MT-safe version.
*/
int
__vfwscanf(FILE * __restrict fp, locale_t locale,
const wchar_t * __restrict fmt, va_list ap)
{
#define GETARG(type) ((flags & SUPPRESS) ? SUPPRESS_PTR : va_arg(ap, type))
wint_t c; /* character from format, or conversion */
size_t width; /* field width, or 0 */
int flags; /* flags as defined above */
int nassigned; /* number of fields assigned */
int nconversions; /* number of conversions */
int nr; /* characters read by the current conversion */
int nread; /* number of characters consumed from fp */
int base; /* base argument to conversion function */
struct ccl ccl; /* character class info */
wchar_t buf[BUF]; /* buffer for numeric conversions */
wint_t wi; /* handy wint_t */
nassigned = 0;
nconversions = 0;
nread = 0;
ccl.start = ccl.end = NULL;
for (;;) {
c = *fmt++;
if (c == 0)
return (nassigned);
if (iswspace(c)) {
while ((c = __fgetwc(fp, locale)) != WEOF &&
iswspace_l(c, locale))
nread++;
if (c != WEOF)
__ungetwc(c, fp, locale);
continue;
}
if (c != '%')
goto literal;
width = 0;
flags = 0;
/*
* switch on the format. continue if done;
* break once format type is derived.
*/
again: c = *fmt++;
switch (c) {
case '%':
literal:
if ((wi = __fgetwc(fp, locale)) == WEOF)
goto input_failure;
if (wi != c) {
__ungetwc(wi, fp, locale);
goto match_failure;
}
nread++;
continue;
case '*':
flags |= SUPPRESS;
goto again;
case 'j':
flags |= INTMAXT;
goto again;
case 'l':
if (flags & LONG) {
flags &= ~LONG;
flags |= LONGLONG;
} else
flags |= LONG;
goto again;
case 'q':
flags |= LONGLONG; /* not quite */
goto again;
case 't':
flags |= PTRDIFFT;
goto again;
case 'w':
/*
* Fixed-width integer types. On all platforms we
* support, int8_t is equivalent to char, int16_t
* is equivalent to short, int32_t is equivalent
* to int, int64_t is equivalent to long long int.
* Furthermore, int_fast8_t, int_fast16_t and
* int_fast32_t are equivalent to int, and
* int_fast64_t is equivalent to long long int.
*/
flags &= ~(SHORTSHORT|SHORT|LONG|LONGLONG|SIZET|INTMAXT|PTRDIFFT);
if (fmt[0] == 'f') {
flags |= FASTINT;
fmt++;
} else {
flags &= ~FASTINT;
}
if (fmt[0] == '8') {
if (!(flags & FASTINT))
flags |= SHORTSHORT;
else
/* no flag set = 32 */ ;
fmt += 1;
} else if (fmt[0] == '1' && fmt[1] == '6') {
if (!(flags & FASTINT))
flags |= SHORT;
else
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '3' && fmt[1] == '2') {
/* no flag set = 32 */ ;
fmt += 2;
} else if (fmt[0] == '6' && fmt[1] == '4') {
flags |= LONGLONG;
fmt += 2;
} else {
goto match_failure;
}
goto again;
case 'z':
flags |= SIZET;
goto again;
case 'L':
flags |= LONGDBL;
goto again;
case 'h':
if (flags & SHORT) {
flags &= ~SHORT;
flags |= SHORTSHORT;
} else
flags |= SHORT;
goto again;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
width = width * 10 + c - '0';
goto again;
/*
* Conversions.
*/
case 'B':
case 'b':
c = CT_INT;
flags |= UNSIGNED;
base = 2;
break;
case 'd':
c = CT_INT;
base = 10;
break;
case 'i':
c = CT_INT;
base = 0;
break;
case 'o':
c = CT_INT;
flags |= UNSIGNED;
base = 8;
break;
case 'u':
c = CT_INT;
flags |= UNSIGNED;
base = 10;
break;
case 'X':
case 'x':
c = CT_INT;
flags |= UNSIGNED;
base = 16;
break;
#ifndef NO_FLOATING_POINT
case 'A': case 'E': case 'F': case 'G':
case 'a': case 'e': case 'f': case 'g':
c = CT_FLOAT;
break;
#endif
case 'S':
flags |= LONG;
/* FALLTHROUGH */
case 's':
c = CT_STRING;
break;
case '[':
ccl.start = fmt;
if (*fmt == '^') {
ccl.compl = 1;
fmt++;
} else
ccl.compl = 0;
if (*fmt == ']')
fmt++;
while (*fmt != '\0' && *fmt != ']')
fmt++;
ccl.end = fmt;
fmt++;
flags |= NOSKIP;
c = CT_CCL;
break;
case 'C':
flags |= LONG;
/* FALLTHROUGH */
case 'c':
flags |= NOSKIP;
c = CT_CHAR;
break;
case 'p': /* pointer format is like hex */
flags |= POINTER;
c = CT_INT; /* assumes sizeof(uintmax_t) */
flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
base = 16;
break;
case 'n':
if (flags & SUPPRESS) /* ??? */
continue;
if (flags & SHORTSHORT)
*va_arg(ap, char *) = nread;
else if (flags & SHORT)
*va_arg(ap, short *) = nread;
else if (flags & LONG)
*va_arg(ap, long *) = nread;
else if (flags & LONGLONG)
*va_arg(ap, long long *) = nread;
else if (flags & INTMAXT)
*va_arg(ap, intmax_t *) = nread;
else if (flags & SIZET)
*va_arg(ap, size_t *) = nread;
else if (flags & PTRDIFFT)
*va_arg(ap, ptrdiff_t *) = nread;
else
*va_arg(ap, int *) = nread;
continue;
default:
goto match_failure;
/*
* Disgusting backwards compatibility hack. XXX
*/
case '\0': /* compat */
return (EOF);
}
/*
* Consume leading white space, except for formats
* that suppress this.
*/
if ((flags & NOSKIP) == 0) {
while ((wi = __fgetwc(fp, locale)) != WEOF && iswspace(wi))
nread++;
if (wi == WEOF)
goto input_failure;
__ungetwc(wi, fp, locale);
}
/*
* Do the conversion.
*/
switch (c) {
case CT_CHAR:
/* scan arbitrary characters (sets NOSKIP) */
if (width == 0)
width = 1;
if (flags & LONG) {
nr = convert_wchar(fp, GETARG(wchar_t *), width,
locale);
} else {
nr = convert_char(fp, GETARG(char *), width,
locale);
}
if (nr < 0)
goto input_failure;
break;
case CT_CCL:
/* scan a (nonempty) character class (sets NOSKIP) */
if (width == 0)
width = (size_t)~0; /* `infinity' */
/* take only those things in the class */
if (flags & LONG) {
nr = convert_wccl(fp, GETARG(wchar_t *), width,
&ccl, locale);
} else {
nr = convert_ccl(fp, GETARG(char *), width,
&ccl, locale);
}
if (nr <= 0) {
if (nr < 0)
goto input_failure;
else /* nr == 0 */
goto match_failure;
}
break;
case CT_STRING:
/* like CCL, but zero-length string OK, & no NOSKIP */
if (width == 0)
width = (size_t)~0;
if (flags & LONG) {
nr = convert_wstring(fp, GETARG(wchar_t *),
width, locale);
} else {
nr = convert_string(fp, GETARG(char *), width,
locale);
}
if (nr < 0)
goto input_failure;
break;
case CT_INT:
/* scan an integer as if by the conversion function */
if (width == 0 || width > sizeof(buf) /
sizeof(*buf) - 1)
width = sizeof(buf) / sizeof(*buf) - 1;
nr = parseint(fp, buf, width, base, locale);
if (nr == 0)
goto match_failure;
if ((flags & SUPPRESS) == 0) {
uintmax_t res;
buf[nr] = L'\0';
if ((flags & UNSIGNED) == 0)
res = wcstoimax(buf, NULL, base);
else
res = wcstoumax(buf, NULL, base);
if (flags & POINTER)
*va_arg(ap, void **) =
(void *)(uintptr_t)res;
else if (flags & SHORTSHORT)
*va_arg(ap, char *) = res;
else if (flags & SHORT)
*va_arg(ap, short *) = res;
else if (flags & LONG)
*va_arg(ap, long *) = res;
else if (flags & LONGLONG)
*va_arg(ap, long long *) = res;
else if (flags & INTMAXT)
*va_arg(ap, intmax_t *) = res;
else if (flags & PTRDIFFT)
*va_arg(ap, ptrdiff_t *) = res;
else if (flags & SIZET)
*va_arg(ap, size_t *) = res;
else
*va_arg(ap, int *) = res;
}
break;
#ifndef NO_FLOATING_POINT
case CT_FLOAT:
/* scan a floating point number as if by strtod */
if (width == 0 || width > sizeof(buf) /
sizeof(*buf) - 1)
width = sizeof(buf) / sizeof(*buf) - 1;
nr = parsefloat(fp, buf, buf + width, locale);
if (nr == 0)
goto match_failure;
if ((flags & SUPPRESS) == 0) {
if (flags & LONGDBL) {
long double res = wcstold(buf, NULL);
*va_arg(ap, long double *) = res;
} else if (flags & LONG) {
double res = wcstod(buf, NULL);
*va_arg(ap, double *) = res;
} else {
float res = wcstof(buf, NULL);
*va_arg(ap, float *) = res;
}
}
break;
#endif /* !NO_FLOATING_POINT */
}
if (!(flags & SUPPRESS))
nassigned++;
nread += nr;
nconversions++;
}
input_failure:
return (nconversions != 0 ? nassigned : EOF);
match_failure:
return (nassigned);
}
#ifndef NO_FLOATING_POINT
static int
parsefloat(FILE *fp, wchar_t *buf, wchar_t *end, locale_t locale)
{
mbstate_t mbs;
size_t nconv;
wchar_t *commit, *p;
int infnanpos = 0;
enum {
S_START, S_GOTSIGN, S_INF, S_NAN, S_DONE, S_MAYBEHEX,
S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
} state = S_START;
wchar_t c;
wchar_t decpt;
_Bool gotmantdig = 0, ishex = 0;
mbs = initial_mbs;
nconv = mbrtowc(&decpt, localeconv()->decimal_point, MB_CUR_MAX, &mbs);
if (nconv == (size_t)-1 || nconv == (size_t)-2)
decpt = '.'; /* failsafe */
/*
* We set commit = p whenever the string we have read so far
* constitutes a valid representation of a floating point
* number by itself. At some point, the parse will complete
* or fail, and we will ungetc() back to the last commit point.
* To ensure that the file offset gets updated properly, it is
* always necessary to read at least one character that doesn't
* match; thus, we can't short-circuit "infinity" or "nan(...)".
*/
commit = buf - 1;
c = WEOF;
for (p = buf; p < end; ) {
if ((c = __fgetwc(fp, locale)) == WEOF)
break;
reswitch:
switch (state) {
case S_START:
state = S_GOTSIGN;
if (c == '-' || c == '+')
break;
else
goto reswitch;
case S_GOTSIGN:
switch (c) {
case '0':
state = S_MAYBEHEX;
commit = p;
break;
case 'I':
case 'i':
state = S_INF;
break;
case 'N':
case 'n':
state = S_NAN;
break;
default:
state = S_DIGITS;
goto reswitch;
}
break;
case S_INF:
if (infnanpos > 6 ||
(c != "nfinity"[infnanpos] &&
c != "NFINITY"[infnanpos]))
goto parsedone;
if (infnanpos == 1 || infnanpos == 6)
commit = p; /* inf or infinity */
infnanpos++;
break;
case S_NAN:
switch (infnanpos) {
case 0:
if (c != 'A' && c != 'a')
goto parsedone;
break;
case 1:
if (c != 'N' && c != 'n')
goto parsedone;
else
commit = p;
break;
case 2:
if (c != '(')
goto parsedone;
break;
default:
if (c == ')') {
commit = p;
state = S_DONE;
} else if (!iswalnum(c) && c != '_')
goto parsedone;
break;
}
infnanpos++;
break;
case S_DONE:
goto parsedone;
case S_MAYBEHEX:
state = S_DIGITS;
if (c == 'X' || c == 'x') {
ishex = 1;
break;
} else { /* we saw a '0', but no 'x' */
gotmantdig = 1;
goto reswitch;
}
case S_DIGITS:
if ((ishex && iswxdigit(c)) || iswdigit(c))
gotmantdig = 1;
else {
state = S_FRAC;
if (c != decpt)
goto reswitch;
}
if (gotmantdig)
commit = p;
break;
case S_FRAC:
if (((c == 'E' || c == 'e') && !ishex) ||
((c == 'P' || c == 'p') && ishex)) {
if (!gotmantdig)
goto parsedone;
else
state = S_EXP;
} else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
commit = p;
gotmantdig = 1;
} else
goto parsedone;
break;
case S_EXP:
state = S_EXPDIGITS;
if (c == '-' || c == '+')
break;
else
goto reswitch;
case S_EXPDIGITS:
if (iswdigit(c))
commit = p;
else
goto parsedone;
break;
default:
abort();
}
*p++ = c;
c = WEOF;
}
parsedone:
if (c != WEOF)
__ungetwc(c, fp, locale);
while (commit < --p)
__ungetwc(*p, fp, locale);
*++commit = '\0';
return (commit - buf);
}
#endif
diff --git a/lib/libc/stdio/vprintf.c b/lib/libc/stdio/vprintf.c
index 604870b93b1e..8198ead9a496 100644
--- a/lib/libc/stdio/vprintf.c
+++ b/lib/libc/stdio/vprintf.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <xlocale.h>
int
vprintf(const char * __restrict fmt, __va_list ap)
{
return (vfprintf(stdout, fmt, ap));
}
int
vprintf_l(locale_t locale, const char * __restrict fmt, __va_list ap)
{
return (vfprintf_l(stdout, locale, fmt, ap));
}
diff --git a/lib/libc/stdio/vscanf.c b/lib/libc/stdio/vscanf.c
index 58fd2a455389..4f5993ef7764 100644
--- a/lib/libc/stdio/vscanf.c
+++ b/lib/libc/stdio/vscanf.c
@@ -1,66 +1,65 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Donn Seeley at UUNET Technologies, Inc.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vscanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "local.h"
#include "xlocale_private.h"
int
vscanf_l(locale_t locale, const char * __restrict fmt, __va_list ap)
{
int retval;
FIX_LOCALE(locale);
FLOCKFILE_CANCELSAFE(stdin);
retval = __svfscanf(stdin, locale, fmt, ap);
FUNLOCKFILE_CANCELSAFE();
return (retval);
}
int
vscanf(const char * __restrict fmt, __va_list ap)
{
return vscanf_l(__get_locale(), fmt, ap);
}
diff --git a/lib/libc/stdio/vsnprintf.c b/lib/libc/stdio/vsnprintf.c
index 8fc7f9fdf725..c80f70924a2a 100644
--- a/lib/libc/stdio/vsnprintf.c
+++ b/lib/libc/stdio/vsnprintf.c
@@ -1,88 +1,87 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vsnprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include "local.h"
#include "xlocale_private.h"
int
vsnprintf_l(char * __restrict str, size_t n, locale_t locale,
const char * __restrict fmt, __va_list ap)
{
size_t on;
int ret;
char dummy[2];
FILE f = FAKE_FILE;
FIX_LOCALE(locale);
on = n;
if (n != 0)
n--;
if (n > INT_MAX) {
errno = EOVERFLOW;
*str = '\0';
return (EOF);
}
/* Stdio internals do not deal correctly with zero length buffer */
if (n == 0) {
if (on > 0)
*str = '\0';
str = dummy;
n = 1;
}
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = n;
ret = __vfprintf(&f, locale, fmt, ap);
if (on > 0)
*f._p = '\0';
return (ret);
}
int
vsnprintf(char * __restrict str, size_t n, const char * __restrict fmt,
__va_list ap)
{
return vsnprintf_l(str, n, __get_locale(), fmt, ap);
}
diff --git a/lib/libc/stdio/vsprintf.c b/lib/libc/stdio/vsprintf.c
index 68a2f70469f4..f23821360b47 100644
--- a/lib/libc/stdio/vsprintf.c
+++ b/lib/libc/stdio/vsprintf.c
@@ -1,68 +1,67 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vsprintf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <limits.h>
#include "local.h"
#include "xlocale_private.h"
int
vsprintf_l(char * __restrict str, locale_t locale,
const char * __restrict fmt, __va_list ap)
{
int ret;
FILE f = FAKE_FILE;
FIX_LOCALE(locale);
f._flags = __SWR | __SSTR;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._w = INT_MAX;
ret = __vfprintf(&f, locale, fmt, ap);
*f._p = 0;
return (ret);
}
int
vsprintf(char * __restrict str, const char * __restrict fmt, __va_list ap)
{
return vsprintf_l(str, __get_locale(), fmt, ap);
}
diff --git a/lib/libc/stdio/vsscanf.c b/lib/libc/stdio/vsscanf.c
index 0751f0e95b0b..e33ce2a8b3d0 100644
--- a/lib/libc/stdio/vsscanf.c
+++ b/lib/libc/stdio/vsscanf.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* This code is derived from software contributed to Berkeley by
* Donn Seeley at UUNET Technologies, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vsscanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdio.h>
#include <string.h>
#include "local.h"
#include "xlocale_private.h"
static int
eofread(void *, char *, int);
/* ARGSUSED */
static int
eofread(void *cookie, char *buf, int len)
{
return (0);
}
int
vsscanf_l(const char * __restrict str, locale_t locale,
const char * __restrict fmt, __va_list ap)
{
FILE f = FAKE_FILE;
FIX_LOCALE(locale);
f._flags = __SRD;
f._bf._base = f._p = (unsigned char *)str;
f._bf._size = f._r = strlen(str);
f._read = eofread;
return (__svfscanf(&f, locale, fmt, ap));
}
int
vsscanf(const char * __restrict str, const char * __restrict fmt,
__va_list ap)
{
return vsscanf_l(str, __get_locale(), fmt, ap);
}
diff --git a/lib/libc/stdio/vswprintf.c b/lib/libc/stdio/vswprintf.c
index db1b5d30d09d..d8c1d6720ebe 100644
--- a/lib/libc/stdio/vswprintf.c
+++ b/lib/libc/stdio/vswprintf.c
@@ -1,114 +1,113 @@
/* $OpenBSD: vasprintf.c,v 1.4 1998/06/21 22:13:47 millert Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#if 0
__FBSDID("FreeBSD: src/lib/libc/stdio/vasprintf.c,v 1.16 2002/08/21 16:19:57 mike Exp ");
#endif
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include "local.h"
#include "xlocale_private.h"
int
vswprintf_l(wchar_t * __restrict s, size_t n, locale_t locale,
const wchar_t * __restrict fmt, __va_list ap)
{
static const mbstate_t initial;
mbstate_t mbs;
FILE f = FAKE_FILE;
char *mbp;
int ret, sverrno;
size_t nwc;
FIX_LOCALE(locale);
if (n == 0) {
errno = EINVAL;
return (-1);
}
if (n - 1 > INT_MAX) {
errno = EOVERFLOW;
*s = L'\0';
return (-1);
}
f._flags = __SWR | __SSTR | __SALC;
f._bf._base = f._p = (unsigned char *)malloc(128);
if (f._bf._base == NULL) {
errno = ENOMEM;
*s = L'\0';
return (-1);
}
f._bf._size = f._w = 127; /* Leave room for the NUL */
ret = __vfwprintf(&f, locale, fmt, ap);
if (ret < 0) {
sverrno = errno;
free(f._bf._base);
errno = sverrno;
*s = L'\0';
return (-1);
}
*f._p = '\0';
mbp = f._bf._base;
/*
* XXX Undo the conversion from wide characters to multibyte that
* fputwc() did in __vfwprintf().
*/
mbs = initial;
nwc = mbsrtowcs_l(s, (const char **)&mbp, n, &mbs, locale);
free(f._bf._base);
if (nwc == (size_t)-1) {
errno = EILSEQ;
*s = L'\0';
return (-1);
}
if (nwc == n) {
s[n - 1] = L'\0';
errno = EOVERFLOW;
return (-1);
}
return (ret);
}
int
vswprintf(wchar_t * __restrict s, size_t n, const wchar_t * __restrict fmt,
__va_list ap)
{
return vswprintf_l(s, n, __get_locale(), fmt, ap);
}
diff --git a/lib/libc/stdio/vswscanf.c b/lib/libc/stdio/vswscanf.c
index ecdafbefdc75..8fecb81f96bb 100644
--- a/lib/libc/stdio/vswscanf.c
+++ b/lib/libc/stdio/vswscanf.c
@@ -1,104 +1,103 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Donn Seeley at UUNET Technologies, Inc.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)vsscanf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
__FBSDID("FreeBSD: src/lib/libc/stdio/vsscanf.c,v 1.11 2002/08/21 16:19:57 mike Exp ");
#endif
#include <limits.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "local.h"
#include "xlocale_private.h"
static int eofread(void *, char *, int);
static int
eofread(void *cookie, char *buf, int len)
{
return (0);
}
int
vswscanf_l(const wchar_t * __restrict str, locale_t locale,
const wchar_t * __restrict fmt, va_list ap)
{
static const mbstate_t initial;
mbstate_t mbs;
FILE f = FAKE_FILE;
char *mbstr;
size_t mlen;
int r;
const wchar_t *strp;
FIX_LOCALE(locale);
/*
* XXX Convert the wide character string to multibyte, which
* __vfwscanf() will convert back to wide characters.
*/
if ((mbstr = malloc(wcslen(str) * MB_CUR_MAX + 1)) == NULL)
return (EOF);
mbs = initial;
strp = str;
if ((mlen = wcsrtombs_l(mbstr, &strp, SIZE_T_MAX, &mbs, locale)) == (size_t)-1) {
free(mbstr);
return (EOF);
}
f._flags = __SRD;
f._bf._base = f._p = (unsigned char *)mbstr;
f._bf._size = f._r = mlen;
f._read = eofread;
r = __vfwscanf(&f, locale, fmt, ap);
free(mbstr);
return (r);
}
int
vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict fmt,
va_list ap)
{
return vswscanf_l(str, __get_locale(), fmt, ap);
}
diff --git a/lib/libc/stdio/vwprintf.c b/lib/libc/stdio/vwprintf.c
index b0e9ac26d3c6..0647130f9732 100644
--- a/lib/libc/stdio/vwprintf.c
+++ b/lib/libc/stdio/vwprintf.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
vwprintf(const wchar_t * __restrict fmt, va_list ap)
{
return (vfwprintf(stdout, fmt, ap));
}
int
vwprintf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
{
return (vfwprintf_l(stdout, locale, fmt, ap));
}
diff --git a/lib/libc/stdio/vwscanf.c b/lib/libc/stdio/vwscanf.c
index e2e16ac91e53..b4906184e2c0 100644
--- a/lib/libc/stdio/vwscanf.c
+++ b/lib/libc/stdio/vwscanf.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
vwscanf(const wchar_t * __restrict fmt, va_list ap)
{
return (vfwscanf(stdin, fmt, ap));
}
int
vwscanf_l(locale_t locale, const wchar_t * __restrict fmt, va_list ap)
{
return (vfwscanf_l(stdin, locale, fmt, ap));
}
diff --git a/lib/libc/stdio/wbuf.c b/lib/libc/stdio/wbuf.c
index acbe379ad90e..27ec67d28d80 100644
--- a/lib/libc/stdio/wbuf.c
+++ b/lib/libc/stdio/wbuf.c
@@ -1,100 +1,99 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)wbuf.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdio.h>
#include "local.h"
/*
* Write the given character into the (probably full) buffer for
* the given file. Flush the buffer out if it is or becomes full,
* or if c=='\n' and the file is line buffered.
*
* Non-MT-safe
*/
int
__swbuf(int c, FILE *fp)
{
unsigned char *old_p;
int n;
/*
* In case we cannot write, or longjmp takes us out early,
* make sure _w is 0 (if fully- or un-buffered) or -_bf._size
* (if line buffered) so that we will get called again.
* If we did not do this, a sufficient number of putc()
* calls might wrap _w from negative to positive.
*/
fp->_w = fp->_lbfsize;
if (prepwrite(fp) != 0) {
errno = EBADF;
return (EOF);
}
c = (unsigned char)c;
ORIENT(fp, -1);
/*
* If it is completely full, flush it out. Then, in any case,
* stuff c into the buffer. If this causes the buffer to fill
* completely, or if c is '\n' and the file is line buffered,
* flush it (perhaps a second time). The second flush will always
* happen on unbuffered streams, where _bf._size==1; fflush()
* guarantees that putc() will always call wbuf() by setting _w
* to 0, so we need not do anything else.
*/
n = fp->_p - fp->_bf._base;
if (n >= fp->_bf._size) {
if (__fflush(fp) != 0)
return (EOF);
n = 0;
}
fp->_w--;
*fp->_p++ = c;
old_p = fp->_p;
if (++n == fp->_bf._size || (fp->_flags & __SLBF && c == '\n')) {
if (__fflush(fp) != 0) {
if (fp->_p == old_p && errno == EINTR) {
fp->_p--;
fp->_w++;
}
return (EOF);
}
}
return (c);
}
diff --git a/lib/libc/stdio/wprintf.c b/lib/libc/stdio/wprintf.c
index c45640021927..0aa33cc78770 100644
--- a/lib/libc/stdio/wprintf.c
+++ b/lib/libc/stdio/wprintf.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
wprintf(const wchar_t * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfwprintf(stdout, fmt, ap);
va_end(ap);
return (ret);
}
int
wprintf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
{
int ret;
va_list ap;
va_start(ap, fmt);
ret = vfwprintf_l(stdout, locale, fmt, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdio/wscanf.c b/lib/libc/stdio/wscanf.c
index 9527fcd27767..8e2019c2c490 100644
--- a/lib/libc/stdio/wscanf.c
+++ b/lib/libc/stdio/wscanf.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
#include <xlocale.h>
int
wscanf(const wchar_t * __restrict fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vfwscanf(stdin, fmt, ap);
va_end(ap);
return (r);
}
int
wscanf_l(locale_t locale, const wchar_t * __restrict fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vfwscanf_l(stdin, locale, fmt, ap);
va_end(ap);
return (r);
}
diff --git a/lib/libc/stdio/wsetup.c b/lib/libc/stdio/wsetup.c
index b0dd89637b75..528c0241df67 100644
--- a/lib/libc/stdio/wsetup.c
+++ b/lib/libc/stdio/wsetup.c
@@ -1,92 +1,91 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)wsetup.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include "local.h"
/*
* Various output routines call wsetup to be sure it is safe to write,
* because either _flags does not include __SWR, or _buf is NULL.
* _wsetup returns 0 if OK to write; otherwise, it returns EOF and sets errno.
*/
int
__swsetup(FILE *fp)
{
/* make sure stdio is set up */
if (!__sdidinit)
__sinit();
/*
* If we are not writing, we had better be reading and writing.
*/
if ((fp->_flags & __SWR) == 0) {
if ((fp->_flags & __SRW) == 0) {
errno = EBADF;
fp->_flags |= __SERR;
return (EOF);
}
if (fp->_flags & __SRD) {
/* clobber any ungetc data */
if (HASUB(fp))
FREEUB(fp);
fp->_flags &= ~(__SRD|__SEOF);
fp->_r = 0;
fp->_p = fp->_bf._base;
}
fp->_flags |= __SWR;
}
/*
* Make a buffer if necessary, then set _w.
*/
if (fp->_bf._base == NULL)
__smakebuf(fp);
if (fp->_flags & __SLBF) {
/*
* It is line buffered, so make _lbfsize be -_bufsize
* for the putc() macro. We will change _lbfsize back
* to 0 whenever we turn off __SWR.
*/
fp->_w = 0;
fp->_lbfsize = -fp->_bf._size;
} else
fp->_w = fp->_flags & __SNBF ? 0 : fp->_bf._size;
return (0);
}
diff --git a/lib/libc/stdlib/abort.c b/lib/libc/stdlib/abort.c
index 5d8c39987b14..2765af856660 100644
--- a/lib/libc/stdlib/abort.c
+++ b/lib/libc/stdlib/abort.c
@@ -1,79 +1,78 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)abort.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <signal.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <pthread.h>
#include "un-namespace.h"
#include "libc_private.h"
void
abort(void)
{
struct sigaction act;
/*
* POSIX requires we flush stdio buffers on abort.
* XXX ISO C requires that abort() be async-signal-safe.
*/
if (__cleanup)
(*__cleanup)();
sigfillset(&act.sa_mask);
/*
* Don't block SIGABRT to give any handler a chance; we ignore
* any errors -- ISO C doesn't allow abort to return anyway.
*/
sigdelset(&act.sa_mask, SIGABRT);
(void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
(void)raise(SIGABRT);
/*
* If SIGABRT was ignored, or caught and the handler returns, do
* it again, only harder.
*/
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
sigfillset(&act.sa_mask);
(void)__libc_sigaction(SIGABRT, &act, NULL);
sigdelset(&act.sa_mask, SIGABRT);
(void)__libc_sigprocmask(SIG_SETMASK, &act.sa_mask, NULL);
(void)raise(SIGABRT);
exit(1);
}
diff --git a/lib/libc/stdlib/abs.c b/lib/libc/stdlib/abs.c
index c0f402381c02..a40e645c5dc0 100644
--- a/lib/libc/stdlib/abs.c
+++ b/lib/libc/stdlib/abs.c
@@ -1,42 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)abs.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h>
int
abs(int j)
{
return(j < 0 ? -j : j);
}
diff --git a/lib/libc/stdlib/atexit.c b/lib/libc/stdlib/atexit.c
index 6b63d9e728c4..b2c10ca4cca5 100644
--- a/lib/libc/stdlib/atexit.c
+++ b/lib/libc/stdlib/atexit.c
@@ -1,248 +1,247 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)atexit.c 8.2 (Berkeley) 7/3/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <errno.h>
#include <link.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include "atexit.h"
#include "un-namespace.h"
#include "block_abi.h"
#include "libc_private.h"
/**
* The _Block_copy() function is provided by the block runtime.
*/
__attribute__((weak)) void*
_Block_copy(void*);
#define ATEXIT_FN_EMPTY 0
#define ATEXIT_FN_STD 1
#define ATEXIT_FN_CXA 2
static pthread_mutex_t atexit_mutex = PTHREAD_MUTEX_INITIALIZER;
#define _MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
#define _MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
#define _MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x)
struct atexit {
struct atexit *next; /* next in list */
int ind; /* next index in this table */
struct atexit_fn {
int fn_type; /* ATEXIT_? from above */
union {
void (*std_func)(void);
void (*cxa_func)(void *);
} fn_ptr; /* function pointer */
void *fn_arg; /* argument for CXA callback */
void *fn_dso; /* shared module handle */
} fns[ATEXIT_SIZE]; /* the table itself */
};
static struct atexit *__atexit; /* points to head of LIFO stack */
typedef DECLARE_BLOCK(void, atexit_block, void);
int atexit_b(atexit_block);
int __cxa_atexit(void (*)(void *), void *, void *);
/*
* Register the function described by 'fptr' to be called at application
* exit or owning shared object unload time. This is a helper function
* for atexit and __cxa_atexit.
*/
static int
atexit_register(struct atexit_fn *fptr)
{
static struct atexit __atexit0; /* one guaranteed table */
struct atexit *p;
_MUTEX_LOCK(&atexit_mutex);
if ((p = __atexit) == NULL)
__atexit = p = &__atexit0;
else while (p->ind >= ATEXIT_SIZE) {
struct atexit *old__atexit;
old__atexit = __atexit;
_MUTEX_UNLOCK(&atexit_mutex);
if ((p = (struct atexit *)malloc(sizeof(*p))) == NULL)
return (-1);
_MUTEX_LOCK(&atexit_mutex);
if (old__atexit != __atexit) {
/* Lost race, retry operation */
_MUTEX_UNLOCK(&atexit_mutex);
free(p);
_MUTEX_LOCK(&atexit_mutex);
p = __atexit;
continue;
}
p->ind = 0;
p->next = __atexit;
__atexit = p;
}
p->fns[p->ind++] = *fptr;
_MUTEX_UNLOCK(&atexit_mutex);
return 0;
}
/*
* Register a function to be performed at exit.
*/
int
atexit(void (*func)(void))
{
struct atexit_fn fn;
int error;
fn.fn_type = ATEXIT_FN_STD;
fn.fn_ptr.std_func = func;
fn.fn_arg = NULL;
fn.fn_dso = NULL;
error = atexit_register(&fn);
return (error);
}
__weak_reference(atexit, __libc_atexit);
/**
* Register a block to be performed at exit.
*/
int
atexit_b(atexit_block func)
{
struct atexit_fn fn;
int error;
if (_Block_copy == 0) {
errno = ENOSYS;
return -1;
}
func = _Block_copy(func);
// Blocks are not C++ destructors, but they have the same signature (a
// single void* parameter), so we can pretend that they are.
fn.fn_type = ATEXIT_FN_CXA;
fn.fn_ptr.cxa_func = (void(*)(void*))GET_BLOCK_FUNCTION(func);
fn.fn_arg = func;
fn.fn_dso = NULL;
error = atexit_register(&fn);
return (error);
}
/*
* Register a function to be performed at exit or when an shared object
* with given dso handle is unloaded dynamically.
*/
int
__cxa_atexit(void (*func)(void *), void *arg, void *dso)
{
struct atexit_fn fn;
int error;
fn.fn_type = ATEXIT_FN_CXA;
fn.fn_ptr.cxa_func = func;
fn.fn_arg = arg;
fn.fn_dso = dso;
error = atexit_register(&fn);
return (error);
}
#pragma weak __pthread_cxa_finalize
void __pthread_cxa_finalize(const struct dl_phdr_info *);
static int global_exit;
/*
* Call all handlers registered with __cxa_atexit for the shared
* object owning 'dso'. Note: if 'dso' is NULL, then all remaining
* handlers are called.
*/
void
__cxa_finalize(void *dso)
{
struct dl_phdr_info phdr_info;
struct atexit *p;
struct atexit_fn fn;
int n, has_phdr;
if (dso != NULL) {
has_phdr = _rtld_addr_phdr(dso, &phdr_info);
} else {
has_phdr = 0;
global_exit = 1;
}
_MUTEX_LOCK(&atexit_mutex);
for (p = __atexit; p; p = p->next) {
for (n = p->ind; --n >= 0;) {
if (p->fns[n].fn_type == ATEXIT_FN_EMPTY)
continue; /* already been called */
fn = p->fns[n];
if (dso != NULL && dso != fn.fn_dso) {
/* wrong DSO ? */
if (!has_phdr || global_exit ||
!__elf_phdr_match_addr(&phdr_info,
fn.fn_ptr.cxa_func))
continue;
}
/*
Mark entry to indicate that this particular handler
has already been called.
*/
p->fns[n].fn_type = ATEXIT_FN_EMPTY;
_MUTEX_UNLOCK(&atexit_mutex);
/* Call the function of correct type. */
if (fn.fn_type == ATEXIT_FN_CXA)
fn.fn_ptr.cxa_func(fn.fn_arg);
else if (fn.fn_type == ATEXIT_FN_STD)
fn.fn_ptr.std_func();
_MUTEX_LOCK(&atexit_mutex);
}
}
_MUTEX_UNLOCK(&atexit_mutex);
if (dso == NULL)
_MUTEX_DESTROY(&atexit_mutex);
if (has_phdr && !global_exit && &__pthread_cxa_finalize != NULL)
__pthread_cxa_finalize(&phdr_info);
}
diff --git a/lib/libc/stdlib/atof.c b/lib/libc/stdlib/atof.c
index b058f10deb87..3ede84273fdf 100644
--- a/lib/libc/stdlib/atof.c
+++ b/lib/libc/stdlib/atof.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)atof.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <xlocale.h>
double
atof(const char *ascii)
{
return strtod(ascii, (char **)NULL);
}
double
atof_l(const char *ascii, locale_t locale)
{
return strtod_l(ascii, (char **)NULL, locale);
}
diff --git a/lib/libc/stdlib/atoi.c b/lib/libc/stdlib/atoi.c
index dfaf659458f5..c5add6403dc2 100644
--- a/lib/libc/stdlib/atoi.c
+++ b/lib/libc/stdlib/atoi.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)atoi.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <xlocale.h>
int
atoi(const char *str)
{
return (int)strtol(str, NULL, 10);
}
int
atoi_l(const char *str, locale_t locale)
{
return (int)strtol_l(str, NULL, 10, locale);
}
diff --git a/lib/libc/stdlib/atol.c b/lib/libc/stdlib/atol.c
index a36633f04d8c..375b3953101e 100644
--- a/lib/libc/stdlib/atol.c
+++ b/lib/libc/stdlib/atol.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)atol.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <xlocale.h>
long
atol(const char *str)
{
return strtol(str, (char **)NULL, 10);
}
long
atol_l(const char *str, locale_t locale)
{
return strtol_l(str, (char **)NULL, 10, locale);
}
diff --git a/lib/libc/stdlib/atoll.c b/lib/libc/stdlib/atoll.c
index 95efac77eb82..4819c3f56150 100644
--- a/lib/libc/stdlib/atoll.c
+++ b/lib/libc/stdlib/atoll.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <xlocale.h>
long long
atoll(const char *str)
{
return strtoll(str, (char **)NULL, 10);
}
long long
atoll_l(const char *str, locale_t locale)
{
return strtoll_l(str, (char **)NULL, 10, locale);
}
diff --git a/lib/libc/stdlib/bsearch.c b/lib/libc/stdlib/bsearch.c
index 9934716fd196..38538149270d 100644
--- a/lib/libc/stdlib/bsearch.c
+++ b/lib/libc/stdlib/bsearch.c
@@ -1,88 +1,87 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bsearch.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stddef.h>
#include <stdlib.h>
#ifdef I_AM_BSEARCH_B
#include "block_abi.h"
#define COMPAR(x,y) CALL_BLOCK(compar, x, y)
#else
#define COMPAR(x,y) compar(x, y)
#endif
/*
* Perform a binary search.
*
* The code below is a bit sneaky. After a comparison fails, we
* divide the work in half by moving either left or right. If lim
* is odd, moving left simply involves halving lim: e.g., when lim
* is 5 we look at item 2, so we change lim to 2 so that we will
* look at items 0 & 1. If lim is even, the same applies. If lim
* is odd, moving right again involves halving lim, this time moving
* the base up one item past p: e.g., when lim is 5 we change base
* to item 3 and make lim 2 so that we will look at items 3 and 4.
* If lim is even, however, we have to shrink it by one before
* halving: e.g., when lim is 4, we still looked at item 2, so we
* have to make lim 3, then halve, obtaining 1, so that we will only
* look at item 3.
*/
#ifdef I_AM_BSEARCH_B
void *
bsearch_b(const void *key, const void *base0, size_t nmemb, size_t size,
DECLARE_BLOCK(int, compar, const void *, const void *))
#else
void *
bsearch(const void *key, const void *base0, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
#endif
{
const char *base = base0;
size_t lim;
int cmp;
const void *p;
for (lim = nmemb; lim != 0; lim >>= 1) {
p = base + (lim >> 1) * size;
cmp = COMPAR(key, p);
if (cmp == 0)
return ((void *)p);
if (cmp > 0) { /* key > p: move right */
base = (char *)p + size;
lim--;
} /* else move left */
}
return (NULL);
}
diff --git a/lib/libc/stdlib/cxa_thread_atexit.c b/lib/libc/stdlib/cxa_thread_atexit.c
index c6eb1278fcd2..1715bc6d125c 100644
--- a/lib/libc/stdlib/cxa_thread_atexit.c
+++ b/lib/libc/stdlib/cxa_thread_atexit.c
@@ -1,37 +1,36 @@
/*-
* Copyright (c) 2017 The FreeBSD Foundation
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "libc_private.h"
int
__cxa_thread_atexit(void (*dtor_func)(void *), void *obj, void *dso_symbol)
{
return (__cxa_thread_atexit_hidden(dtor_func, obj, dso_symbol));
}
diff --git a/lib/libc/stdlib/cxa_thread_atexit_impl.c b/lib/libc/stdlib/cxa_thread_atexit_impl.c
index 6883f5290829..f95384b30347 100644
--- a/lib/libc/stdlib/cxa_thread_atexit_impl.c
+++ b/lib/libc/stdlib/cxa_thread_atexit_impl.c
@@ -1,152 +1,151 @@
/*-
* Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
* Copyright (c) 2016, 2017 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/queue.h>
#include "namespace.h"
#include <errno.h>
#include <link.h>
#include <pthread.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include "un-namespace.h"
#include "libc_private.h"
/*
* C++11 introduces the thread_local scope (like __thread with some
* additions). As a key-feature it should support non-trivial
* destructors, registered with __cxa_thread_atexit() to be executed
* at the thread termination.
*
* The implemention keeps a _Thread_local list of destructors per each
* thread, and calls __cxa_thread_call_dtors() on each thread's exit
* to do cleanup. For a thread calling exit(3), in particular, for
* the initial thread returning from main(), we call
* __cxa_thread_call_dtors() inside exit().
*
* It could be possible that a dynamically loaded library, use
* thread_local variable but is dlclose()'d before thread exit. The
* destructor of this variable will then try to access the address,
* for calling it but it's unloaded, so it'll crash. We're using
* __elf_phdr_match_addr() to detect and prevent such cases and so
* prevent the crash.
*/
#define CXA_DTORS_ITERATIONS 4
struct cxa_thread_dtor {
void *obj;
void (*func)(void *);
void *dso;
LIST_ENTRY(cxa_thread_dtor) entry;
};
static _Thread_local LIST_HEAD(dtor_list, cxa_thread_dtor) dtors =
LIST_HEAD_INITIALIZER(dtors);
int
__cxa_thread_atexit_impl(void (*dtor_func)(void *), void *obj,
void *dso_symbol)
{
return (__cxa_thread_atexit_hidden(dtor_func, obj, dso_symbol));
}
int
__cxa_thread_atexit_hidden(void (*dtor_func)(void *), void *obj,
void *dso_symbol)
{
struct cxa_thread_dtor *new_dtor;
new_dtor = malloc(sizeof(*new_dtor));
if (new_dtor == NULL) {
errno = ENOMEM; /* forcibly override malloc(3) error */
return (-1);
}
new_dtor->obj = obj;
new_dtor->func = dtor_func;
new_dtor->dso = dso_symbol;
LIST_INSERT_HEAD(&dtors, new_dtor, entry);
return (0);
}
static void
walk_cb_call(struct cxa_thread_dtor *dtor)
{
struct dl_phdr_info phdr_info;
if (_rtld_addr_phdr(dtor->dso, &phdr_info) &&
__elf_phdr_match_addr(&phdr_info, dtor->func))
dtor->func(dtor->obj);
else
fprintf(stderr,
"__cxa_thread_call_dtors: dtr %p from unloaded dso, skipping\n",
(void *)(dtor->func));
}
static void
walk_cb_nocall(struct cxa_thread_dtor *dtor __unused)
{
}
static void
cxa_thread_walk(void (*cb)(struct cxa_thread_dtor *))
{
struct cxa_thread_dtor *dtor, *tdtor;
LIST_FOREACH_SAFE(dtor, &dtors, entry, tdtor) {
LIST_REMOVE(dtor, entry);
cb(dtor);
free(dtor);
}
}
/*
* This is the callback function we use to call destructors, once for
* each thread. It is called in exit(3) in libc/stdlib/exit.c and
* before exit_thread() in libthr/thread/thr_exit.c.
*/
void
__cxa_thread_call_dtors(void)
{
int i;
for (i = 0; i < CXA_DTORS_ITERATIONS && !LIST_EMPTY(&dtors); i++)
cxa_thread_walk(walk_cb_call);
if (!LIST_EMPTY(&dtors)) {
fprintf(stderr, "Thread %p is exiting with more "
"thread-specific dtors created after %d iterations "
"of destructor calls\n",
_pthread_self(), i);
cxa_thread_walk(walk_cb_nocall);
}
}
diff --git a/lib/libc/stdlib/div.c b/lib/libc/stdlib/div.c
index c7bb8c44aa79..94be22f5cd23 100644
--- a/lib/libc/stdlib/div.c
+++ b/lib/libc/stdlib/div.c
@@ -1,78 +1,77 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)div.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h> /* div_t */
div_t
div(int num, int denom)
{
div_t r;
r.quot = num / denom;
r.rem = num % denom;
#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
/*
* The ANSI standard says that |r.quot| <= |n/d|, where
* n/d is to be computed in infinite precision. In other
* words, we should always truncate the quotient towards
* 0, never -infinity.
*
* Machine division and remainer may work either way when
* one or both of n or d is negative. If only one is
* negative and r.quot has been truncated towards -inf,
* r.rem will have the same sign as denom and the opposite
* sign of num; if both are negative and r.quot has been
* truncated towards -inf, r.rem will be positive (will
* have the opposite sign of num). These are considered
* `wrong'.
*
* If both are num and denom are positive, r will always
* be positive.
*
* This all boils down to:
* if num >= 0, but r.rem < 0, we got the wrong answer.
* In that case, to get the right answer, add 1 to r.quot and
* subtract denom from r.rem.
*/
if (num >= 0 && r.rem < 0) {
r.quot++;
r.rem -= denom;
}
#endif
return (r);
}
diff --git a/lib/libc/stdlib/exit.c b/lib/libc/stdlib/exit.c
index 111b735be0a0..a0c9622944c5 100644
--- a/lib/libc/stdlib/exit.c
+++ b/lib/libc/stdlib/exit.c
@@ -1,76 +1,75 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)exit.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdlib.h>
#include <unistd.h>
#include "un-namespace.h"
#include "atexit.h"
#include "libc_private.h"
void (*__cleanup)(void);
/*
* This variable is zero until a process has created a thread.
* It is used to avoid calling locking functions in libc when they
* are not required. By default, libc is intended to be(come)
* thread-safe, but without a (significant) penalty to non-threaded
* processes.
*/
int __isthreaded = 0;
/*
* Exit, flushing stdio buffers if necessary.
*/
void
exit(int status)
{
/* Ensure that the auto-initialization routine is linked in: */
extern int _thread_autoinit_dummy_decl;
_thread_autoinit_dummy_decl = 1;
/*
* We're dealing with cleaning up thread_local destructors in the case of
* the process termination through main() exit.
* Other cases are handled elsewhere.
*/
__cxa_thread_call_dtors();
__cxa_finalize(NULL);
if (__cleanup)
(*__cleanup)();
_exit(status);
}
diff --git a/lib/libc/stdlib/getenv.c b/lib/libc/stdlib/getenv.c
index f7206f3af29b..f8f59526421a 100644
--- a/lib/libc/stdlib/getenv.c
+++ b/lib/libc/stdlib/getenv.c
@@ -1,726 +1,725 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2007-2009 Sean C. Farley <scf@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer,
* without modification, immediately at the beginning of the file.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
static const char CorruptEnvFindMsg[] = "environment corrupt; unable to find ";
static const char CorruptEnvValueMsg[] =
"environment corrupt; missing value for ";
/*
* Standard environ. environ variable is exposed to entire process.
*
* origEnviron: Upon cleanup on unloading of library or failure, this
* allows environ to return to as it was before.
* environSize: Number of variables environ can hold. Can only
* increase.
* intEnviron: Internally-built environ. Exposed via environ during
* (re)builds of the environment.
*/
static char **origEnviron;
static char **intEnviron = NULL;
static int environSize = 0;
/*
* Array of environment variables built from environ. Each element records:
* name: Pointer to name=value string
* name length: Length of name not counting '=' character
* value: Pointer to value within same string as name
* value size: Size (not length) of space for value not counting the
* nul character
* active state: true/false value to signify whether variable is active.
* Useful since multiple variables with the same name can
* co-exist. At most, one variable can be active at any
* one time.
* putenv: Created from putenv() call. This memory must not be
* reused.
*/
static struct envVars {
size_t nameLen;
size_t valueSize;
char *name;
char *value;
bool active;
bool putenv;
} *envVars = NULL;
/*
* Environment array information.
*
* envActive: Number of active variables in array.
* envVarsSize: Size of array.
* envVarsTotal: Number of total variables in array (active or not).
*/
static int envActive = 0;
static int envVarsSize = 0;
static int envVarsTotal = 0;
/* Deinitialization of new environment. */
static void __attribute__ ((destructor)) __clean_env_destructor(void);
/*
* A simple version of warnx() to avoid the bloat of including stdio in static
* binaries.
*/
static void
__env_warnx(const char *msg, const char *name, size_t nameLen)
{
static const char nl[] = "\n";
static const char progSep[] = ": ";
_write(STDERR_FILENO, _getprogname(), strlen(_getprogname()));
_write(STDERR_FILENO, progSep, sizeof(progSep) - 1);
_write(STDERR_FILENO, msg, strlen(msg));
_write(STDERR_FILENO, name, nameLen);
_write(STDERR_FILENO, nl, sizeof(nl) - 1);
return;
}
/*
* Inline strlen() for performance. Also, perform check for an equals sign.
* Cheaper here than performing a strchr() later.
*/
static inline size_t
__strleneq(const char *str)
{
const char *s;
for (s = str; *s != '\0'; ++s)
if (*s == '=')
return (0);
return (s - str);
}
/*
* Comparison of an environment name=value to a name.
*/
static inline bool
strncmpeq(const char *nameValue, const char *name, size_t nameLen)
{
if (strncmp(nameValue, name, nameLen) == 0 && nameValue[nameLen] == '=')
return (true);
return (false);
}
/*
* Using environment, returns pointer to value associated with name, if any,
* else NULL. If the onlyActive flag is set to true, only variables that are
* active are returned else all are.
*/
static inline char *
__findenv(const char *name, size_t nameLen, int *envNdx, bool onlyActive)
{
int ndx;
/*
* Find environment variable from end of array (more likely to be
* active). A variable created by putenv is always active, or it is not
* tracked in the array.
*/
for (ndx = *envNdx; ndx >= 0; ndx--)
if (envVars[ndx].putenv) {
if (strncmpeq(envVars[ndx].name, name, nameLen)) {
*envNdx = ndx;
return (envVars[ndx].name + nameLen +
sizeof ("=") - 1);
}
} else if ((!onlyActive || envVars[ndx].active) &&
(envVars[ndx].nameLen == nameLen &&
strncmpeq(envVars[ndx].name, name, nameLen))) {
*envNdx = ndx;
return (envVars[ndx].value);
}
return (NULL);
}
/*
* Using environ, returns pointer to value associated with name, if any, else
* NULL. Used on the original environ passed into the program.
*/
static char *
__findenv_environ(const char *name, size_t nameLen)
{
int envNdx;
/* Find variable within environ. */
for (envNdx = 0; environ[envNdx] != NULL; envNdx++)
if (strncmpeq(environ[envNdx], name, nameLen))
return (&(environ[envNdx][nameLen + sizeof("=") - 1]));
return (NULL);
}
/*
* Remove variable added by putenv() from variable tracking array.
*/
static void
__remove_putenv(int envNdx)
{
envVarsTotal--;
if (envVarsTotal > envNdx)
memmove(&(envVars[envNdx]), &(envVars[envNdx + 1]),
(envVarsTotal - envNdx) * sizeof (*envVars));
memset(&(envVars[envVarsTotal]), 0, sizeof (*envVars));
return;
}
/*
* Deallocate the environment built from environ as well as environ then set
* both to NULL. Eases debugging of memory leaks.
*/
static void
__clean_env(bool freeVars)
{
int envNdx;
/* Deallocate environment and environ if created by *env(). */
if (envVars != NULL) {
for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--)
/* Free variables or deactivate them. */
if (envVars[envNdx].putenv) {
if (!freeVars)
__remove_putenv(envNdx);
} else {
if (freeVars)
free(envVars[envNdx].name);
else
envVars[envNdx].active = false;
}
if (freeVars) {
free(envVars);
envVars = NULL;
} else
envActive = 0;
/* Restore original environ if it has not updated by program. */
if (origEnviron != NULL) {
if (environ == intEnviron)
environ = origEnviron;
free(intEnviron);
intEnviron = NULL;
environSize = 0;
}
}
return;
}
/*
* Using the environment, rebuild the environ array for use by other C library
* calls that depend upon it.
*/
static int
__rebuild_environ(int newEnvironSize)
{
char **tmpEnviron;
int envNdx;
int environNdx;
int tmpEnvironSize;
/* Resize environ. */
if (newEnvironSize > environSize) {
tmpEnvironSize = newEnvironSize * 2;
tmpEnviron = reallocarray(intEnviron, tmpEnvironSize + 1,
sizeof(*intEnviron));
if (tmpEnviron == NULL)
return (-1);
environSize = tmpEnvironSize;
intEnviron = tmpEnviron;
}
envActive = newEnvironSize;
/* Assign active variables to environ. */
for (envNdx = envVarsTotal - 1, environNdx = 0; envNdx >= 0; envNdx--)
if (envVars[envNdx].active)
intEnviron[environNdx++] = envVars[envNdx].name;
intEnviron[environNdx] = NULL;
/* Always set environ which may have been replaced by program. */
environ = intEnviron;
return (0);
}
/*
* Enlarge new environment.
*/
static inline bool
__enlarge_env(void)
{
int newEnvVarsSize;
struct envVars *tmpEnvVars;
envVarsTotal++;
if (envVarsTotal > envVarsSize) {
newEnvVarsSize = envVarsTotal * 2;
tmpEnvVars = reallocarray(envVars, newEnvVarsSize,
sizeof(*envVars));
if (tmpEnvVars == NULL) {
envVarsTotal--;
return (false);
}
envVarsSize = newEnvVarsSize;
envVars = tmpEnvVars;
}
return (true);
}
/*
* Using environ, build an environment for use by standard C library calls.
*/
static int
__build_env(void)
{
char **env;
int activeNdx;
int envNdx;
int savedErrno;
size_t nameLen;
/* Check for non-existant environment. */
if (environ == NULL || environ[0] == NULL)
return (0);
/* Count environment variables. */
for (env = environ, envVarsTotal = 0; *env != NULL; env++)
envVarsTotal++;
envVarsSize = envVarsTotal * 2;
/* Create new environment. */
envVars = calloc(envVarsSize, sizeof(*envVars));
if (envVars == NULL)
goto Failure;
/* Copy environ values and keep track of them. */
for (envNdx = envVarsTotal - 1; envNdx >= 0; envNdx--) {
envVars[envNdx].putenv = false;
envVars[envNdx].name =
strdup(environ[envVarsTotal - envNdx - 1]);
if (envVars[envNdx].name == NULL)
goto Failure;
envVars[envNdx].value = strchr(envVars[envNdx].name, '=');
if (envVars[envNdx].value != NULL) {
envVars[envNdx].value++;
envVars[envNdx].valueSize =
strlen(envVars[envNdx].value);
} else {
__env_warnx(CorruptEnvValueMsg, envVars[envNdx].name,
strlen(envVars[envNdx].name));
errno = EFAULT;
goto Failure;
}
/*
* Find most current version of variable to make active. This
* will prevent multiple active variables from being created
* during this initialization phase.
*/
nameLen = envVars[envNdx].value - envVars[envNdx].name - 1;
envVars[envNdx].nameLen = nameLen;
activeNdx = envVarsTotal - 1;
if (__findenv(envVars[envNdx].name, nameLen, &activeNdx,
false) == NULL) {
__env_warnx(CorruptEnvFindMsg, envVars[envNdx].name,
nameLen);
errno = EFAULT;
goto Failure;
}
envVars[activeNdx].active = true;
}
/* Create a new environ. */
origEnviron = environ;
environ = NULL;
if (__rebuild_environ(envVarsTotal) == 0)
return (0);
Failure:
savedErrno = errno;
__clean_env(true);
errno = savedErrno;
return (-1);
}
/*
* Destructor function with default argument to __clean_env().
*/
static void
__clean_env_destructor(void)
{
__clean_env(true);
return;
}
/*
* Returns the value of a variable or NULL if none are found.
*/
char *
getenv(const char *name)
{
int envNdx;
size_t nameLen;
/* Check for malformed name. */
if (name == NULL || (nameLen = __strleneq(name)) == 0) {
errno = EINVAL;
return (NULL);
}
/*
* Variable search order:
* 1. Check for an empty environ. This allows an application to clear
* the environment.
* 2. Search the external environ array.
* 3. Search the internal environment.
*
* Since malloc() depends upon getenv(), getenv() must never cause the
* internal environment storage to be generated.
*/
if (environ == NULL || environ[0] == NULL)
return (NULL);
else if (envVars == NULL || environ != intEnviron)
return (__findenv_environ(name, nameLen));
else {
envNdx = envVarsTotal - 1;
return (__findenv(name, nameLen, &envNdx, true));
}
}
/*
* Runs getenv() unless the current process is tainted by uid or gid changes, in
* which case it will return NULL.
*/
char *
secure_getenv(const char *name)
{
if (issetugid())
return (NULL);
return (getenv(name));
}
/*
* Set the value of a variable. Older settings are labeled as inactive. If an
* older setting has enough room to store the new value, it will be reused. No
* previous variables are ever freed here to avoid causing a segmentation fault
* in a user's code.
*
* The variables nameLen and valueLen are passed into here to allow the caller
* to calculate the length by means besides just strlen().
*/
static int
__setenv(const char *name, size_t nameLen, const char *value, int overwrite)
{
bool reuse;
char *env;
int envNdx;
int newEnvActive;
size_t valueLen;
/* Find existing environment variable large enough to use. */
envNdx = envVarsTotal - 1;
newEnvActive = envActive;
valueLen = strlen(value);
reuse = false;
if (__findenv(name, nameLen, &envNdx, false) != NULL) {
/* Deactivate entry if overwrite is allowed. */
if (envVars[envNdx].active) {
if (overwrite == 0)
return (0);
envVars[envNdx].active = false;
newEnvActive--;
}
/* putenv() created variable cannot be reused. */
if (envVars[envNdx].putenv)
__remove_putenv(envNdx);
/* Entry is large enough to reuse. */
else if (envVars[envNdx].valueSize >= valueLen)
reuse = true;
}
/* Create new variable if none was found of sufficient size. */
if (! reuse) {
/* Enlarge environment. */
envNdx = envVarsTotal;
if (!__enlarge_env())
return (-1);
/* Create environment entry. */
envVars[envNdx].name = malloc(nameLen + sizeof ("=") +
valueLen);
if (envVars[envNdx].name == NULL) {
envVarsTotal--;
return (-1);
}
envVars[envNdx].nameLen = nameLen;
envVars[envNdx].valueSize = valueLen;
/* Save name of name/value pair. */
env = stpncpy(envVars[envNdx].name, name, nameLen);
*env++ = '=';
}
else
env = envVars[envNdx].value;
/* Save value of name/value pair. */
strcpy(env, value);
envVars[envNdx].value = env;
envVars[envNdx].active = true;
newEnvActive++;
/* No need to rebuild environ if an active variable was reused. */
if (reuse && newEnvActive == envActive)
return (0);
else
return (__rebuild_environ(newEnvActive));
}
/*
* If the program attempts to replace the array of environment variables
* (environ) environ or sets the first varible to NULL, then deactivate all
* variables and merge in the new list from environ.
*/
static int
__merge_environ(void)
{
char **env;
char *equals;
/*
* Internally-built environ has been replaced or cleared (detected by
* using the count of active variables against a NULL as the first value
* in environ). Clean up everything.
*/
if (intEnviron != NULL && (environ != intEnviron || (envActive > 0 &&
environ[0] == NULL))) {
/* Deactivate all environment variables. */
if (envActive > 0) {
origEnviron = NULL;
__clean_env(false);
}
/*
* Insert new environ into existing, yet deactivated,
* environment array.
*/
origEnviron = environ;
if (origEnviron != NULL)
for (env = origEnviron; *env != NULL; env++) {
if ((equals = strchr(*env, '=')) == NULL) {
__env_warnx(CorruptEnvValueMsg, *env,
strlen(*env));
errno = EFAULT;
return (-1);
}
if (__setenv(*env, equals - *env, equals + 1,
1) == -1)
return (-1);
}
}
return (0);
}
/*
* The exposed setenv() that performs a few tests before calling the function
* (__setenv()) that does the actual work of inserting a variable into the
* environment.
*/
int
setenv(const char *name, const char *value, int overwrite)
{
size_t nameLen;
/* Check for malformed name. */
if (name == NULL || (nameLen = __strleneq(name)) == 0) {
errno = EINVAL;
return (-1);
}
/* Initialize environment. */
if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
return (-1);
return (__setenv(name, nameLen, value, overwrite));
}
/*
* Insert a "name=value" string into the environment. Special settings must be
* made to keep setenv() from reusing this memory block and unsetenv() from
* allowing it to be tracked.
*/
int
putenv(char *string)
{
char *equals;
int envNdx;
int newEnvActive;
size_t nameLen;
/* Check for malformed argument. */
if (string == NULL || (equals = strchr(string, '=')) == NULL ||
(nameLen = equals - string) == 0) {
errno = EINVAL;
return (-1);
}
/* Initialize environment. */
if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
return (-1);
/* Deactivate previous environment variable. */
envNdx = envVarsTotal - 1;
newEnvActive = envActive;
if (__findenv(string, nameLen, &envNdx, true) != NULL) {
/* Reuse previous putenv slot. */
if (envVars[envNdx].putenv) {
envVars[envNdx].name = string;
return (__rebuild_environ(envActive));
} else {
newEnvActive--;
envVars[envNdx].active = false;
}
}
/* Enlarge environment. */
envNdx = envVarsTotal;
if (!__enlarge_env())
return (-1);
/* Create environment entry. */
envVars[envNdx].name = string;
envVars[envNdx].nameLen = -1;
envVars[envNdx].value = NULL;
envVars[envNdx].valueSize = -1;
envVars[envNdx].putenv = true;
envVars[envNdx].active = true;
newEnvActive++;
return (__rebuild_environ(newEnvActive));
}
/*
* Unset variable with the same name by flagging it as inactive. No variable is
* ever freed.
*/
int
unsetenv(const char *name)
{
int envNdx;
size_t nameLen;
int newEnvActive;
/* Check for malformed name. */
if (name == NULL || (nameLen = __strleneq(name)) == 0) {
errno = EINVAL;
return (-1);
}
/* Initialize environment. */
if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
return (-1);
/* Deactivate specified variable. */
/* Remove all occurrences. */
envNdx = envVarsTotal - 1;
newEnvActive = envActive;
while (__findenv(name, nameLen, &envNdx, true) != NULL) {
envVars[envNdx].active = false;
if (envVars[envNdx].putenv)
__remove_putenv(envNdx);
envNdx--;
newEnvActive--;
}
if (newEnvActive != envActive)
__rebuild_environ(newEnvActive);
return (0);
}
/*
* Unset all variable by flagging them as inactive. No variable is
* ever freed.
*/
int
clearenv(void)
{
int ndx;
/* Initialize environment. */
if (__merge_environ() == -1 || (envVars == NULL && __build_env() == -1))
return (-1);
/* Remove from the end to not shuffle memory too much. */
for (ndx = envVarsTotal - 1; ndx >= 0; ndx--) {
envVars[ndx].active = false;
if (envVars[ndx].putenv)
__remove_putenv(ndx);
}
__rebuild_environ(0);
return (0);
}
diff --git a/lib/libc/stdlib/getopt.c b/lib/libc/stdlib/getopt.c
index 5b50d587c92e..5b58bb2304a1 100644
--- a/lib/libc/stdlib/getopt.c
+++ b/lib/libc/stdlib/getopt.c
@@ -1,137 +1,136 @@
/* $NetBSD: getopt.c,v 1.29 2014/06/05 22:00:22 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1987, 1993, 1994
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getopt.c 8.3 (Berkeley) 4/27/95";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
int opterr = 1, /* if error message should be printed */
optind = 1, /* index into parent argv vector */
optopt, /* character checked for validity */
optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#define BADCH (int)'?'
#define BADARG (int)':'
static char EMSG[] = "";
/*
* getopt --
* Parse argc/argv argument vector.
*/
int
getopt(int nargc, char * const nargv[], const char *ostr)
{
static char *place = EMSG; /* option letter processing */
char *oli; /* option letter list index */
if (optreset || *place == 0) { /* update scanning pointer */
optreset = 0;
place = nargv[optind];
if (optind >= nargc || *place++ != '-') {
/* Argument is absent or is not an option */
place = EMSG;
return (-1);
}
optopt = *place++;
if (optopt == '-' && *place == 0) {
/* "--" => end of options */
++optind;
place = EMSG;
return (-1);
}
if (optopt == 0) {
/* Solitary '-', treat as a '-' option
if the program (eg su) is looking for it. */
place = EMSG;
if (strchr(ostr, '-') == NULL)
return (-1);
optopt = '-';
}
} else
optopt = *place++;
/* See if option letter is one the caller wanted... */
if (optopt == ':' || (oli = strchr(ostr, optopt)) == NULL) {
if (*place == 0)
++optind;
if (opterr && *ostr != ':')
(void)fprintf(stderr,
"%s: illegal option -- %c\n", _getprogname(),
optopt);
return (BADCH);
}
/* Does this option need an argument? */
if (oli[1] != ':') {
/* don't need argument */
optarg = NULL;
if (*place == 0)
++optind;
} else {
/* Option-argument is either the rest of this argument or the
entire next argument. */
if (*place)
optarg = place;
else if (oli[2] == ':')
/*
* GNU Extension, for optional arguments if the rest of
* the argument is empty, we return NULL
*/
optarg = NULL;
else if (nargc > ++optind)
optarg = nargv[optind];
else {
/* option-argument absent */
place = EMSG;
if (*ostr == ':')
return (BADARG);
if (opterr)
(void)fprintf(stderr,
"%s: option requires an argument -- %c\n",
_getprogname(), optopt);
return (BADCH);
}
place = EMSG;
++optind;
}
return (optopt); /* return option letter */
}
diff --git a/lib/libc/stdlib/getopt_long.c b/lib/libc/stdlib/getopt_long.c
index 3e6e3fd431bb..a31bf5f5b37b 100644
--- a/lib/libc/stdlib/getopt_long.c
+++ b/lib/libc/stdlib/getopt_long.c
@@ -1,612 +1,611 @@
/* $OpenBSD: getopt_long.c,v 1.26 2013/06/08 22:47:56 millert Exp $ */
/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */
/*
* Copyright (c) 2002 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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.
*
* Sponsored in part by the Defense Advanced Research Projects
* Agency (DARPA) and Air Force Research Laboratory, Air Force
* Materiel Command, USAF, under agreement number F39502-99-1-0512.
*/
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Dieter Baron and Thomas Klausner.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: getopt_long.c,v 1.16 2004/02/04 18:17:25 millert Exp $";
#endif /* LIBC_SCCS and not lint */
#endif
-#include <sys/cdefs.h>
#include <err.h>
#include <errno.h>
#include <getopt.h>
#include <stdlib.h>
#include <string.h>
#define GNU_COMPATIBLE /* Be more compatible, configure's use us! */
#if 0 /* we prefer to keep our getopt(3) */
#define REPLACE_GETOPT /* use this getopt as the system getopt(3) */
#endif
#ifdef REPLACE_GETOPT
int opterr = 1; /* if error message should be printed */
int optind = 1; /* index into parent argv vector */
int optopt = '?'; /* character checked for validity */
int optreset; /* reset getopt */
char *optarg; /* argument associated with option */
#endif
#define PRINT_ERROR ((opterr) && (*options != ':'))
#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */
#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */
#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */
/* return values */
#define BADCH (int)'?'
#define BADARG ((*options == ':') ? (int)':' : (int)'?')
#define INORDER (int)1
static char EMSG[] = "";
#ifdef GNU_COMPATIBLE
#define NO_PREFIX (-1)
#define D_PREFIX 0
#define DD_PREFIX 1
#define W_PREFIX 2
#endif
static int getopt_internal(int, char * const *, const char *,
const struct option *, int *, int);
static int parse_long_options(char * const *, const char *,
const struct option *, int *, int, int);
static int gcd(int, int);
static void permute_args(int, int, int, char * const *);
static char *place = EMSG; /* option letter processing */
/* XXX: set optreset to 1 rather than these two */
static int nonopt_start = -1; /* first non option argument (for permute) */
static int nonopt_end = -1; /* first option after non options (for permute) */
/* Error messages */
static const char recargchar[] = "option requires an argument -- %c";
static const char illoptchar[] = "illegal option -- %c"; /* From P1003.2 */
#ifdef GNU_COMPATIBLE
static int dash_prefix = NO_PREFIX;
static const char gnuoptchar[] = "invalid option -- %c";
static const char recargstring[] = "option `%s%s' requires an argument";
static const char ambig[] = "option `%s%.*s' is ambiguous";
static const char noarg[] = "option `%s%.*s' doesn't allow an argument";
static const char illoptstring[] = "unrecognized option `%s%s'";
#else
static const char recargstring[] = "option requires an argument -- %s";
static const char ambig[] = "ambiguous option -- %.*s";
static const char noarg[] = "option doesn't take an argument -- %.*s";
static const char illoptstring[] = "unknown option -- %s";
#endif
/*
* Compute the greatest common divisor of a and b.
*/
static int
gcd(int a, int b)
{
int c;
c = a % b;
while (c != 0) {
a = b;
b = c;
c = a % b;
}
return (b);
}
/*
* Exchange the block from nonopt_start to nonopt_end with the block
* from nonopt_end to opt_end (keeping the same order of arguments
* in each block).
*/
static void
permute_args(int panonopt_start, int panonopt_end, int opt_end,
char * const *nargv)
{
int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos;
char *swap;
/*
* compute lengths of blocks and number and size of cycles
*/
nnonopts = panonopt_end - panonopt_start;
nopts = opt_end - panonopt_end;
ncycle = gcd(nnonopts, nopts);
cyclelen = (opt_end - panonopt_start) / ncycle;
for (i = 0; i < ncycle; i++) {
cstart = panonopt_end+i;
pos = cstart;
for (j = 0; j < cyclelen; j++) {
if (pos >= panonopt_end)
pos -= nnonopts;
else
pos += nopts;
swap = nargv[pos];
/* LINTED const cast */
((char **) nargv)[pos] = nargv[cstart];
/* LINTED const cast */
((char **)nargv)[cstart] = swap;
}
}
}
/*
* parse_long_options --
* Parse long options in argc/argv argument vector.
* Returns -1 if short_too is set and the option does not match long_options.
*/
static int
parse_long_options(char * const *nargv, const char *options,
const struct option *long_options, int *idx, int short_too, int flags)
{
char *current_argv, *has_equal;
#ifdef GNU_COMPATIBLE
const char *current_dash;
#endif
size_t current_argv_len;
int i, match, exact_match, second_partial_match;
current_argv = place;
#ifdef GNU_COMPATIBLE
switch (dash_prefix) {
case D_PREFIX:
current_dash = "-";
break;
case DD_PREFIX:
current_dash = "--";
break;
case W_PREFIX:
current_dash = "-W ";
break;
default:
current_dash = "";
break;
}
#endif
match = -1;
exact_match = 0;
second_partial_match = 0;
optind++;
if ((has_equal = strchr(current_argv, '=')) != NULL) {
/* argument found (--option=arg) */
current_argv_len = has_equal - current_argv;
has_equal++;
} else
current_argv_len = strlen(current_argv);
for (i = 0; long_options[i].name; i++) {
/* find matching long option */
if (strncmp(current_argv, long_options[i].name,
current_argv_len))
continue;
if (strlen(long_options[i].name) == current_argv_len) {
/* exact match */
match = i;
exact_match = 1;
break;
}
/*
* If this is a known short option, don't allow
* a partial match of a single character.
*/
if (short_too && current_argv_len == 1)
continue;
if (match == -1) /* first partial match */
match = i;
else if ((flags & FLAG_LONGONLY) ||
long_options[i].has_arg !=
long_options[match].has_arg ||
long_options[i].flag != long_options[match].flag ||
long_options[i].val != long_options[match].val)
second_partial_match = 1;
}
if (!exact_match && second_partial_match) {
/* ambiguous abbreviation */
if (PRINT_ERROR)
warnx(ambig,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
(int)current_argv_len,
current_argv);
optopt = 0;
return (BADCH);
}
if (match != -1) { /* option found */
if (long_options[match].has_arg == no_argument
&& has_equal) {
if (PRINT_ERROR)
warnx(noarg,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
(int)current_argv_len,
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
#ifdef GNU_COMPATIBLE
return (BADCH);
#else
return (BADARG);
#endif
}
if (long_options[match].has_arg == required_argument ||
long_options[match].has_arg == optional_argument) {
if (has_equal)
optarg = has_equal;
else if (long_options[match].has_arg ==
required_argument) {
/*
* optional argument doesn't use next nargv
*/
optarg = nargv[optind++];
}
}
if ((long_options[match].has_arg == required_argument)
&& (optarg == NULL)) {
/*
* Missing argument; leading ':' indicates no error
* should be generated.
*/
if (PRINT_ERROR)
warnx(recargstring,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
current_argv);
/*
* XXX: GNU sets optopt to val regardless of flag
*/
if (long_options[match].flag == NULL)
optopt = long_options[match].val;
else
optopt = 0;
--optind;
return (BADARG);
}
} else { /* unknown option */
if (short_too) {
--optind;
return (-1);
}
if (PRINT_ERROR)
warnx(illoptstring,
#ifdef GNU_COMPATIBLE
current_dash,
#endif
current_argv);
optopt = 0;
return (BADCH);
}
if (idx)
*idx = match;
if (long_options[match].flag) {
*long_options[match].flag = long_options[match].val;
return (0);
} else
return (long_options[match].val);
}
/*
* getopt_internal --
* Parse argc/argv argument vector. Called by user level routines.
*/
static int
getopt_internal(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx, int flags)
{
char *oli; /* option letter list index */
int optchar, short_too;
static int posixly_correct = -1;
if (options == NULL)
return (-1);
/*
* XXX Some GNU programs (like cvs) set optind to 0 instead of
* XXX using optreset. Work around this braindamage.
*/
if (optind == 0)
optind = optreset = 1;
/*
* Disable GNU extensions if POSIXLY_CORRECT is set or options
* string begins with a '+'.
*/
if (posixly_correct == -1 || optreset)
posixly_correct = (getenv("POSIXLY_CORRECT") != NULL);
if (*options == '-')
flags |= FLAG_ALLARGS;
else if (posixly_correct || *options == '+')
flags &= ~FLAG_PERMUTE;
if (*options == '+' || *options == '-')
options++;
optarg = NULL;
if (optreset)
nonopt_start = nonopt_end = -1;
start:
if (optreset || !*place) { /* update scanning pointer */
optreset = 0;
if (optind >= nargc) { /* end of argument vector */
place = EMSG;
if (nonopt_end != -1) {
/* do permutation, if we have to */
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
else if (nonopt_start != -1) {
/*
* If we skipped non-options, set optind
* to the first of them.
*/
optind = nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
if (*(place = nargv[optind]) != '-' ||
#ifdef GNU_COMPATIBLE
place[1] == '\0') {
#else
(place[1] == '\0' && strchr(options, '-') == NULL)) {
#endif
place = EMSG; /* found non-option */
if (flags & FLAG_ALLARGS) {
/*
* GNU extension:
* return non-option as argument to option 1
*/
optarg = nargv[optind++];
return (INORDER);
}
if (!(flags & FLAG_PERMUTE)) {
/*
* If no permutation wanted, stop parsing
* at first non-option.
*/
return (-1);
}
/* do permutation */
if (nonopt_start == -1)
nonopt_start = optind;
else if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
nonopt_start = optind -
(nonopt_end - nonopt_start);
nonopt_end = -1;
}
optind++;
/* process next argument */
goto start;
}
if (nonopt_start != -1 && nonopt_end == -1)
nonopt_end = optind;
/*
* If we have "-" do nothing, if "--" we are done.
*/
if (place[1] != '\0' && *++place == '-' && place[1] == '\0') {
optind++;
place = EMSG;
/*
* We found an option (--), so if we skipped
* non-options, we have to permute.
*/
if (nonopt_end != -1) {
permute_args(nonopt_start, nonopt_end,
optind, nargv);
optind -= nonopt_end - nonopt_start;
}
nonopt_start = nonopt_end = -1;
return (-1);
}
}
/*
* Check long options if:
* 1) we were passed some
* 2) the arg is not just "-"
* 3) either the arg starts with -- we are getopt_long_only()
*/
if (long_options != NULL && place != nargv[optind] &&
(*place == '-' || (flags & FLAG_LONGONLY))) {
short_too = 0;
#ifdef GNU_COMPATIBLE
dash_prefix = D_PREFIX;
#endif
if (*place == '-') {
place++; /* --foo long option */
if (*place == '\0')
return (BADARG); /* malformed option */
#ifdef GNU_COMPATIBLE
dash_prefix = DD_PREFIX;
#endif
} else if (*place != ':' && strchr(options, *place) != NULL)
short_too = 1; /* could be short option too */
optchar = parse_long_options(nargv, options, long_options,
idx, short_too, flags);
if (optchar != -1) {
place = EMSG;
return (optchar);
}
}
if ((optchar = (int)*place++) == (int)':' ||
(optchar == (int)'-' && *place != '\0') ||
(oli = strchr(options, optchar)) == NULL) {
/*
* If the user specified "-" and '-' isn't listed in
* options, return -1 (non-option) as per POSIX.
* Otherwise, it is an unknown option character (or ':').
*/
if (optchar == (int)'-' && *place == '\0')
return (-1);
if (!*place)
++optind;
#ifdef GNU_COMPATIBLE
if (PRINT_ERROR)
warnx(posixly_correct ? illoptchar : gnuoptchar,
optchar);
#else
if (PRINT_ERROR)
warnx(illoptchar, optchar);
#endif
optopt = optchar;
return (BADCH);
}
if (long_options != NULL && optchar == 'W' && oli[1] == ';') {
/* -W long-option */
if (*place) /* no space */
/* NOTHING */;
else if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else /* white space */
place = nargv[optind];
#ifdef GNU_COMPATIBLE
dash_prefix = W_PREFIX;
#endif
optchar = parse_long_options(nargv, options, long_options,
idx, 0, flags);
place = EMSG;
return (optchar);
}
if (*++oli != ':') { /* doesn't take argument */
if (!*place)
++optind;
} else { /* takes (optional) argument */
optarg = NULL;
if (*place) /* no white space */
optarg = place;
else if (oli[1] != ':') { /* arg not optional */
if (++optind >= nargc) { /* no arg */
place = EMSG;
if (PRINT_ERROR)
warnx(recargchar, optchar);
optopt = optchar;
return (BADARG);
} else
optarg = nargv[optind];
}
place = EMSG;
++optind;
}
/* dump back option letter */
return (optchar);
}
#ifdef REPLACE_GETOPT
/*
* getopt --
* Parse argc/argv argument vector.
*
* [eventually this will replace the BSD getopt]
*/
int
getopt(int nargc, char * const *nargv, const char *options)
{
/*
* We don't pass FLAG_PERMUTE to getopt_internal() since
* the BSD getopt(3) (unlike GNU) has never done this.
*
* Furthermore, since many privileged programs call getopt()
* before dropping privileges it makes sense to keep things
* as simple (and bug-free) as possible.
*/
return (getopt_internal(nargc, nargv, options, NULL, NULL, 0));
}
#endif /* REPLACE_GETOPT */
/*
* getopt_long --
* Parse argc/argv argument vector.
*/
int
getopt_long(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE));
}
/*
* getopt_long_only --
* Parse argc/argv argument vector.
*/
int
getopt_long_only(int nargc, char * const *nargv, const char *options,
const struct option *long_options, int *idx)
{
return (getopt_internal(nargc, nargv, options, long_options, idx,
FLAG_PERMUTE|FLAG_LONGONLY));
}
diff --git a/lib/libc/stdlib/getsubopt.c b/lib/libc/stdlib/getsubopt.c
index dfcca7a7209d..e7bc22045ab1 100644
--- a/lib/libc/stdlib/getsubopt.c
+++ b/lib/libc/stdlib/getsubopt.c
@@ -1,95 +1,94 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)getsubopt.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <string.h>
/*
* The SVID interface to getsubopt provides no way of figuring out which
* part of the suboptions list wasn't matched. This makes error messages
* tricky... The extern variable suboptarg is a pointer to the token
* which didn't match.
*/
char *suboptarg;
int
getsubopt(char **optionp, char * const *tokens, char **valuep)
{
int cnt;
char *p;
suboptarg = *valuep = NULL;
if (!optionp || !*optionp)
return(-1);
/* skip leading white-space, commas */
for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
if (!*p) {
*optionp = p;
return(-1);
}
/* save the start of the token, and skip the rest of the token. */
for (suboptarg = p;
*++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';);
if (*p) {
/*
* If there's an equals sign, set the value pointer, and
* skip over the value part of the token. Terminate the
* token.
*/
if (*p == '=') {
*p = '\0';
for (*valuep = ++p;
*p && *p != ',' && *p != ' ' && *p != '\t'; ++p);
if (*p)
*p++ = '\0';
} else
*p++ = '\0';
/* Skip any whitespace or commas after this token. */
for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p);
}
/* set optionp for next round. */
*optionp = p;
for (cnt = 0; *tokens; ++tokens, ++cnt)
if (!strcmp(suboptarg, *tokens))
return(cnt);
return(-1);
}
diff --git a/lib/libc/stdlib/hcreate.c b/lib/libc/stdlib/hcreate.c
index 969e31bfc461..261f55bfec39 100644
--- a/lib/libc/stdlib/hcreate.c
+++ b/lib/libc/stdlib/hcreate.c
@@ -1,73 +1,72 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <search.h>
#include <stdbool.h>
#include <stddef.h>
/*
* Thread unsafe interface: use a single process-wide hash table and
* forward calls to *_r() functions.
*/
static struct hsearch_data global_hashtable;
static bool global_hashtable_initialized = false;
int
hcreate(size_t nel)
{
return (1);
}
void
hdestroy(void)
{
/* Destroy global hash table if present. */
if (global_hashtable_initialized) {
hdestroy_r(&global_hashtable);
global_hashtable_initialized = false;
}
}
ENTRY *
hsearch(ENTRY item, ACTION action)
{
ENTRY *retval;
/* Create global hash table if needed. */
if (!global_hashtable_initialized) {
if (hcreate_r(0, &global_hashtable) == 0)
return (NULL);
global_hashtable_initialized = true;
}
if (hsearch_r(item, action, &retval, &global_hashtable) == 0)
return (NULL);
return (retval);
}
diff --git a/lib/libc/stdlib/hcreate_r.c b/lib/libc/stdlib/hcreate_r.c
index 82204b7982be..90eff3318be9 100644
--- a/lib/libc/stdlib/hcreate_r.c
+++ b/lib/libc/stdlib/hcreate_r.c
@@ -1,61 +1,60 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <search.h>
#include <stdlib.h>
#include "hsearch.h"
int
hcreate_r(size_t nel, struct hsearch_data *htab)
{
struct __hsearch *hsearch;
/*
* Allocate a hash table object. Ignore the provided hint and start
* off with a table of sixteen entries. In most cases this hint is
* just a wild guess. Resizing the table dynamically if the use
* increases a threshold does not affect the worst-case running time.
*/
hsearch = malloc(sizeof(*hsearch));
if (hsearch == NULL)
return 0;
hsearch->entries = calloc(16, sizeof(ENTRY));
if (hsearch->entries == NULL) {
free(hsearch);
return 0;
}
/*
* Pick a random initialization for the FNV-1a hashing. This makes it
* hard to come up with a fixed set of keys to force hash collisions.
*/
arc4random_buf(&hsearch->offset_basis, sizeof(hsearch->offset_basis));
hsearch->index_mask = 0xf;
hsearch->entries_used = 0;
htab->__hsearch = hsearch;
return 1;
}
diff --git a/lib/libc/stdlib/hdestroy_r.c b/lib/libc/stdlib/hdestroy_r.c
index 42ad8b1b4e0d..e9435c43bca1 100644
--- a/lib/libc/stdlib/hdestroy_r.c
+++ b/lib/libc/stdlib/hdestroy_r.c
@@ -1,41 +1,40 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <search.h>
#include <stdlib.h>
#include "hsearch.h"
void
hdestroy_r(struct hsearch_data *htab)
{
struct __hsearch *hsearch;
/* Free hash table object and its entries. */
hsearch = htab->__hsearch;
free(hsearch->entries);
free(hsearch);
}
diff --git a/lib/libc/stdlib/heapsort.c b/lib/libc/stdlib/heapsort.c
index 3a795db70448..b0f1a0e7f50a 100644
--- a/lib/libc/stdlib/heapsort.c
+++ b/lib/libc/stdlib/heapsort.c
@@ -1,200 +1,199 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2014 David T. Chisnall
* All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Ronnie Kon at Mindcraft Inc., Kevin Lew and Elmer Yglesias.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)heapsort.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#ifdef I_AM_HEAPSORT_B
#include "block_abi.h"
#define COMPAR(x, y) CALL_BLOCK(compar, x, y)
typedef DECLARE_BLOCK(int, heapsort_block, const void *, const void *);
#else
#define COMPAR(x, y) compar(x, y)
#endif
/*
* Swap two areas of size number of bytes. Although qsort(3) permits random
* blocks of memory to be sorted, sorting pointers is almost certainly the
* common case (and, were it not, could easily be made so). Regardless, it
* isn't worth optimizing; the SWAP's get sped up by the cache, and pointer
* arithmetic gets lost in the time required for comparison function calls.
*/
#define SWAP(a, b, count, size, tmp) { \
count = size; \
do { \
tmp = *a; \
*a++ = *b; \
*b++ = tmp; \
} while (--count); \
}
/* Copy one block of size size to another. */
#define COPY(a, b, count, size, tmp1, tmp2) { \
count = size; \
tmp1 = a; \
tmp2 = b; \
do { \
*tmp1++ = *tmp2++; \
} while (--count); \
}
/*
* Build the list into a heap, where a heap is defined such that for
* the records K1 ... KN, Kj/2 >= Kj for 1 <= j/2 <= j <= N.
*
* There two cases. If j == nmemb, select largest of Ki and Kj. If
* j < nmemb, select largest of Ki, Kj and Kj+1.
*/
#define CREATE(initval, nmemb, par_i, child_i, par, child, size, count, tmp) { \
for (par_i = initval; (child_i = par_i * 2) <= nmemb; \
par_i = child_i) { \
child = base + child_i * size; \
if (child_i < nmemb && COMPAR(child, child + size) < 0) { \
child += size; \
++child_i; \
} \
par = base + par_i * size; \
if (COMPAR(child, par) <= 0) \
break; \
SWAP(par, child, count, size, tmp); \
} \
}
/*
* Select the top of the heap and 'heapify'. Since by far the most expensive
* action is the call to the compar function, a considerable optimization
* in the average case can be achieved due to the fact that k, the displaced
* elememt, is usually quite small, so it would be preferable to first
* heapify, always maintaining the invariant that the larger child is copied
* over its parent's record.
*
* Then, starting from the *bottom* of the heap, finding k's correct place,
* again maintianing the invariant. As a result of the invariant no element
* is 'lost' when k is assigned its correct place in the heap.
*
* The time savings from this optimization are on the order of 15-20% for the
* average case. See Knuth, Vol. 3, page 158, problem 18.
*
* XXX Don't break the #define SELECT line, below. Reiser cpp gets upset.
*/
#define SELECT(par_i, child_i, nmemb, par, child, size, k, count, tmp1, tmp2) { \
for (par_i = 1; (child_i = par_i * 2) <= nmemb; par_i = child_i) { \
child = base + child_i * size; \
if (child_i < nmemb && COMPAR(child, child + size) < 0) { \
child += size; \
++child_i; \
} \
par = base + par_i * size; \
COPY(par, child, count, size, tmp1, tmp2); \
} \
for (;;) { \
child_i = par_i; \
par_i = child_i / 2; \
child = base + child_i * size; \
par = base + par_i * size; \
if (child_i == 1 || COMPAR(k, par) < 0) { \
COPY(child, k, count, size, tmp1, tmp2); \
break; \
} \
COPY(child, par, count, size, tmp1, tmp2); \
} \
}
#ifdef I_AM_HEAPSORT_B
int heapsort_b(void *, size_t, size_t, heapsort_block);
#else
int heapsort(void *, size_t, size_t,
int (*)(const void *, const void *));
#endif
/*
* Heapsort -- Knuth, Vol. 3, page 145. Runs in O (N lg N), both average
* and worst. While heapsort is faster than the worst case of quicksort,
* the BSD quicksort does median selection so that the chance of finding
* a data set that will trigger the worst case is nonexistent. Heapsort's
* only advantage over quicksort is that it requires little additional memory.
*/
#ifdef I_AM_HEAPSORT_B
int
heapsort_b(void *vbase, size_t nmemb, size_t size, heapsort_block compar)
#else
int
heapsort(void *vbase, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
#endif
{
size_t cnt, i, j, l;
char tmp, *tmp1, *tmp2;
char *base, *k, *p, *t;
if (nmemb <= 1)
return (0);
if (!size) {
errno = EINVAL;
return (-1);
}
if ((k = malloc(size)) == NULL)
return (-1);
/*
* Items are numbered from 1 to nmemb, so offset from size bytes
* below the starting address.
*/
base = (char *)vbase - size;
for (l = nmemb / 2 + 1; --l;)
CREATE(l, nmemb, i, j, t, p, size, cnt, tmp);
/*
* For each element of the heap, save the largest element into its
* final slot, save the displaced element (k), then recreate the
* heap.
*/
while (nmemb > 1) {
COPY(k, base + nmemb * size, cnt, size, tmp1, tmp2);
COPY(base + nmemb * size, base + size, cnt, size, tmp1, tmp2);
--nmemb;
SELECT(i, j, nmemb, t, p, size, k, cnt, tmp1, tmp2);
}
free(k);
return (0);
}
diff --git a/lib/libc/stdlib/hsearch_r.c b/lib/libc/stdlib/hsearch_r.c
index e398a1d5b913..15c2c156fbec 100644
--- a/lib/libc/stdlib/hsearch_r.c
+++ b/lib/libc/stdlib/hsearch_r.c
@@ -1,148 +1,147 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <search.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "hsearch.h"
/*
* Look up an unused entry in the hash table for a given hash. For this
* implementation we use quadratic probing. Quadratic probing has the
* advantage of preventing primary clustering.
*/
static ENTRY *
hsearch_lookup_free(struct __hsearch *hsearch, size_t hash)
{
size_t index, i;
for (index = hash, i = 0;; index += ++i) {
ENTRY *entry = &hsearch->entries[index & hsearch->index_mask];
if (entry->key == NULL)
return (entry);
}
}
/*
* Computes an FNV-1a hash of the key. Depending on the pointer size, this
* either uses the 32- or 64-bit FNV prime.
*/
static size_t
hsearch_hash(size_t offset_basis, const char *str)
{
size_t hash;
hash = offset_basis;
while (*str != '\0') {
hash ^= (uint8_t)*str++;
if (sizeof(size_t) * CHAR_BIT <= 32)
hash *= UINT32_C(16777619);
else
hash *= UINT64_C(1099511628211);
}
return (hash);
}
int
hsearch_r(ENTRY item, ACTION action, ENTRY **retval, struct hsearch_data *htab)
{
struct __hsearch *hsearch;
ENTRY *entry, *old_entries, *new_entries;
size_t hash, index, i, old_hash, old_count, new_count;
hsearch = htab->__hsearch;
hash = hsearch_hash(hsearch->offset_basis, item.key);
/*
* Search the hash table for an existing entry for this key.
* Stop searching if we run into an unused hash table entry.
*/
for (index = hash, i = 0;; index += ++i) {
entry = &hsearch->entries[index & hsearch->index_mask];
if (entry->key == NULL)
break;
if (strcmp(entry->key, item.key) == 0) {
*retval = entry;
return (1);
}
}
/* Only perform the insertion if action is set to ENTER. */
if (action == FIND) {
errno = ESRCH;
return (0);
}
if (hsearch->entries_used * 2 >= hsearch->index_mask) {
/* Preserve the old hash table entries. */
old_count = hsearch->index_mask + 1;
old_entries = hsearch->entries;
/*
* Allocate and install a new table if insertion would
* yield a hash table that is more than 50% used. By
* using 50% as a threshold, a lookup will only take up
* to two steps on average.
*/
new_count = (hsearch->index_mask + 1) * 2;
new_entries = calloc(new_count, sizeof(ENTRY));
if (new_entries == NULL)
return (0);
hsearch->entries = new_entries;
hsearch->index_mask = new_count - 1;
/* Copy over the entries from the old table to the new table. */
for (i = 0; i < old_count; ++i) {
entry = &old_entries[i];
if (entry->key != NULL) {
old_hash = hsearch_hash(hsearch->offset_basis,
entry->key);
*hsearch_lookup_free(hsearch, old_hash) =
*entry;
}
}
/* Destroy the old hash table entries. */
free(old_entries);
/*
* Perform a new lookup for a free table entry, so that
* we insert the entry into the new hash table.
*/
hsearch = htab->__hsearch;
entry = hsearch_lookup_free(hsearch, hash);
}
/* Insert the new entry into the hash table. */
*entry = item;
++hsearch->entries_used;
*retval = entry;
return (1);
}
diff --git a/lib/libc/stdlib/imaxabs.c b/lib/libc/stdlib/imaxabs.c
index ad7c3fd26e47..08a27ac98da7 100644
--- a/lib/libc/stdlib/imaxabs.c
+++ b/lib/libc/stdlib/imaxabs.c
@@ -1,36 +1,35 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <inttypes.h>
intmax_t
imaxabs(intmax_t j)
{
return (j < 0 ? -j : j);
}
diff --git a/lib/libc/stdlib/imaxdiv.c b/lib/libc/stdlib/imaxdiv.c
index a2ed360fa868..de72ead031d5 100644
--- a/lib/libc/stdlib/imaxdiv.c
+++ b/lib/libc/stdlib/imaxdiv.c
@@ -1,47 +1,46 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <inttypes.h>
/* See comments in div.c for implementation details. */
imaxdiv_t
imaxdiv(intmax_t numer, intmax_t denom)
{
imaxdiv_t retval;
retval.quot = numer / denom;
retval.rem = numer % denom;
#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
if (numer >= 0 && retval.rem < 0) {
retval.quot++;
retval.rem -= denom;
}
#endif
return (retval);
}
diff --git a/lib/libc/stdlib/insque.c b/lib/libc/stdlib/insque.c
index 46b250893264..3af31eb15554 100644
--- a/lib/libc/stdlib/insque.c
+++ b/lib/libc/stdlib/insque.c
@@ -1,45 +1,44 @@
/*
* Initial implementation:
* Copyright (c) 2002 Robert Drehmel
* All rights reserved.
*
* As long as the above copyright statement and this notice remain
* unchanged, you can do what ever you want with this file.
*/
-#include <sys/cdefs.h>
#define _SEARCH_PRIVATE
#include <search.h>
#ifdef DEBUG
#include <stdio.h>
#else
#include <stdlib.h> /* for NULL */
#endif
void
insque(void *element, void *pred)
{
struct que_elem *prev, *next, *elem;
elem = (struct que_elem *)element;
prev = (struct que_elem *)pred;
if (prev == NULL) {
elem->prev = elem->next = NULL;
return;
}
next = prev->next;
if (next != NULL) {
#ifdef DEBUG
if (next->prev != prev) {
fprintf(stderr, "insque: Inconsistency detected:"
" next(%p)->prev(%p) != prev(%p)\n",
next, next->prev, prev);
}
#endif
next->prev = elem;
}
prev->next = elem;
elem->prev = prev;
elem->next = next;
}
diff --git a/lib/libc/stdlib/labs.c b/lib/libc/stdlib/labs.c
index 8eb58252dd83..4a4cb52e722e 100644
--- a/lib/libc/stdlib/labs.c
+++ b/lib/libc/stdlib/labs.c
@@ -1,42 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)labs.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h>
long
labs(long j)
{
return(j < 0 ? -j : j);
}
diff --git a/lib/libc/stdlib/ldiv.c b/lib/libc/stdlib/ldiv.c
index 0d1835a03d0c..bdcc284b069b 100644
--- a/lib/libc/stdlib/ldiv.c
+++ b/lib/libc/stdlib/ldiv.c
@@ -1,57 +1,56 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ldiv.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stdlib.h> /* ldiv_t */
ldiv_t
ldiv(long num, long denom)
{
ldiv_t r;
/* see div.c for comments */
r.quot = num / denom;
r.rem = num % denom;
#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
if (num >= 0 && r.rem < 0) {
r.quot++;
r.rem -= denom;
}
#endif
return (r);
}
diff --git a/lib/libc/stdlib/llabs.c b/lib/libc/stdlib/llabs.c
index ad7fbdda1660..ac151e3a5036 100644
--- a/lib/libc/stdlib/llabs.c
+++ b/lib/libc/stdlib/llabs.c
@@ -1,36 +1,35 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
long long
llabs(long long j)
{
return (j < 0 ? -j : j);
}
diff --git a/lib/libc/stdlib/lldiv.c b/lib/libc/stdlib/lldiv.c
index 91dc062e9e15..f7030e7ae1ff 100644
--- a/lib/libc/stdlib/lldiv.c
+++ b/lib/libc/stdlib/lldiv.c
@@ -1,47 +1,46 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
/* See comments in div.c for implementation details. */
lldiv_t
lldiv(long long numer, long long denom)
{
lldiv_t retval;
retval.quot = numer / denom;
retval.rem = numer % denom;
#if !defined(__STDC_VERSION__) || (__STDC_VERSION__ < 199901L)
if (numer >= 0 && retval.rem < 0) {
retval.quot++;
retval.rem -= denom;
}
#endif
return (retval);
}
diff --git a/lib/libc/stdlib/lsearch.c b/lib/libc/stdlib/lsearch.c
index 1ca55cc9002e..e2b83473411e 100644
--- a/lib/libc/stdlib/lsearch.c
+++ b/lib/libc/stdlib/lsearch.c
@@ -1,58 +1,57 @@
/*
* Initial implementation:
* Copyright (c) 2002 Robert Drehmel
* All rights reserved.
*
* As long as the above copyright statement and this notice remain
* unchanged, you can do what ever you want with this file.
*/
#include <sys/types.h>
-#include <sys/cdefs.h>
#define _SEARCH_PRIVATE
#include <search.h>
#include <stdint.h> /* for uint8_t */
#include <stdlib.h> /* for NULL */
#include <string.h> /* for memcpy() prototype */
static void *lwork(const void *, const void *, size_t *, size_t,
int (*)(const void *, const void *), int);
void *lsearch(const void *key, void *base, size_t *nelp, size_t width,
int (*compar)(const void *, const void *))
{
return (lwork(key, base, nelp, width, compar, 1));
}
void *lfind(const void *key, const void *base, size_t *nelp, size_t width,
int (*compar)(const void *, const void *))
{
return (lwork(key, base, nelp, width, compar, 0));
}
static void *
lwork(const void *key, const void *base, size_t *nelp, size_t width,
int (*compar)(const void *, const void *), int addelem)
{
uint8_t *ep, *endp;
ep = __DECONST(uint8_t *, base);
for (endp = (uint8_t *)(ep + width * *nelp); ep < endp; ep += width) {
if (compar(key, ep) == 0)
return (ep);
}
/* lfind() shall return when the key was not found. */
if (!addelem)
return (NULL);
/*
* lsearch() adds the key to the end of the table and increments
* the number of elements.
*/
memcpy(endp, key, width);
++*nelp;
return (endp);
}
diff --git a/lib/libc/stdlib/merge.c b/lib/libc/stdlib/merge.c
index 42f061be17a8..726c3b7b14cc 100644
--- a/lib/libc/stdlib/merge.c
+++ b/lib/libc/stdlib/merge.c
@@ -1,353 +1,352 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Peter McIlroy.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)merge.c 8.2 (Berkeley) 2/14/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* Hybrid exponential search/linear search merge sort with hybrid
* natural/pairwise first pass. Requires about .3% more comparisons
* for random data than LSMS with pairwise first pass alone.
* It works for objects as small as two bytes.
*/
#define NATURAL
#define THRESHOLD 16 /* Best choice for natural merge cut-off. */
/* #define NATURAL to get hybrid natural merge.
* (The default is pairwise merging.)
*/
#include <sys/param.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifdef I_AM_MERGESORT_B
#include "block_abi.h"
#define DECLARE_CMP DECLARE_BLOCK(int, cmp, const void *, const void *)
typedef DECLARE_BLOCK(int, cmp_t, const void *, const void *);
#define CMP(x, y) CALL_BLOCK(cmp, x, y)
#else
typedef int (*cmp_t)(const void *, const void *);
#define CMP(x, y) cmp(x, y)
#endif
static void setup(u_char *, u_char *, size_t, size_t, cmp_t);
static void insertionsort(u_char *, size_t, size_t, cmp_t);
#define ISIZE sizeof(int)
#define PSIZE sizeof(u_char *)
#define ICOPY_LIST(src, dst, last) \
do \
*(int*)dst = *(int*)src, src += ISIZE, dst += ISIZE; \
while(src < last)
#define ICOPY_ELT(src, dst, i) \
do \
*(int*) dst = *(int*) src, src += ISIZE, dst += ISIZE; \
while (i -= ISIZE)
#define CCOPY_LIST(src, dst, last) \
do \
*dst++ = *src++; \
while (src < last)
#define CCOPY_ELT(src, dst, i) \
do \
*dst++ = *src++; \
while (i -= 1)
/*
* Find the next possible pointer head. (Trickery for forcing an array
* to do double duty as a linked list when objects do not align with word
* boundaries.
*/
/* Assumption: PSIZE is a power of 2. */
#define EVAL(p) (u_char **)roundup2((uintptr_t)p, PSIZE)
#ifdef I_AM_MERGESORT_B
int mergesort_b(void *, size_t, size_t, cmp_t);
#else
int mergesort(void *, size_t, size_t, cmp_t);
#endif
/*
* Arguments are as for qsort.
*/
int
#ifdef I_AM_MERGESORT_B
mergesort_b(void *base, size_t nmemb, size_t size, cmp_t cmp)
#else
mergesort(void *base, size_t nmemb, size_t size, cmp_t cmp)
#endif
{
size_t i;
int sense;
int big, iflag;
u_char *f1, *f2, *t, *b, *tp2, *q, *l1, *l2;
u_char *list2, *list1, *p2, *p, *last, **p1;
if (size < PSIZE / 2) { /* Pointers must fit into 2 * size. */
errno = EINVAL;
return (-1);
}
if (nmemb == 0)
return (0);
iflag = 0;
if (__is_aligned(size, ISIZE) && __is_aligned(base, ISIZE))
iflag = 1;
if ((list2 = malloc(nmemb * size + PSIZE)) == NULL)
return (-1);
list1 = base;
setup(list1, list2, nmemb, size, cmp);
last = list2 + nmemb * size;
i = big = 0;
while (*EVAL(list2) != last) {
l2 = list1;
p1 = EVAL(list1);
for (tp2 = p2 = list2; p2 != last; p1 = EVAL(l2)) {
p2 = *EVAL(p2);
f1 = l2;
f2 = l1 = list1 + (p2 - list2);
if (p2 != last)
p2 = *EVAL(p2);
l2 = list1 + (p2 - list2);
while (f1 < l1 && f2 < l2) {
if (CMP(f1, f2) <= 0) {
q = f2;
b = f1, t = l1;
sense = -1;
} else {
q = f1;
b = f2, t = l2;
sense = 0;
}
if (!big) { /* here i = 0 */
while ((b += size) < t && CMP(q, b) >sense)
if (++i == 6) {
big = 1;
goto EXPONENTIAL;
}
} else {
EXPONENTIAL: for (i = size; ; i <<= 1)
if ((p = (b + i)) >= t) {
if ((p = t - size) > b &&
CMP(q, p) <= sense)
t = p;
else
b = p;
break;
} else if (CMP(q, p) <= sense) {
t = p;
if (i == size)
big = 0;
goto FASTCASE;
} else
b = p;
while (t > b+size) {
i = (((t - b) / size) >> 1) * size;
if (CMP(q, p = b + i) <= sense)
t = p;
else
b = p;
}
goto COPY;
FASTCASE: while (i > size)
if (CMP(q,
p = b + (i >>= 1)) <= sense)
t = p;
else
b = p;
COPY: b = t;
}
i = size;
if (q == f1) {
if (iflag) {
ICOPY_LIST(f2, tp2, b);
ICOPY_ELT(f1, tp2, i);
} else {
CCOPY_LIST(f2, tp2, b);
CCOPY_ELT(f1, tp2, i);
}
} else {
if (iflag) {
ICOPY_LIST(f1, tp2, b);
ICOPY_ELT(f2, tp2, i);
} else {
CCOPY_LIST(f1, tp2, b);
CCOPY_ELT(f2, tp2, i);
}
}
}
if (f2 < l2) {
if (iflag)
ICOPY_LIST(f2, tp2, l2);
else
CCOPY_LIST(f2, tp2, l2);
} else if (f1 < l1) {
if (iflag)
ICOPY_LIST(f1, tp2, l1);
else
CCOPY_LIST(f1, tp2, l1);
}
*p1 = l2;
}
tp2 = list1; /* swap list1, list2 */
list1 = list2;
list2 = tp2;
last = list2 + nmemb*size;
}
if (base == list2) {
memmove(list2, list1, nmemb*size);
list2 = list1;
}
free(list2);
return (0);
}
#define swap(a, b) { \
s = b; \
i = size; \
do { \
tmp = *a; *a++ = *s; *s++ = tmp; \
} while (--i); \
a -= size; \
}
#define reverse(bot, top) { \
s = top; \
do { \
i = size; \
do { \
tmp = *bot; *bot++ = *s; *s++ = tmp; \
} while (--i); \
s -= size2; \
} while(bot < s); \
}
/*
* Optional hybrid natural/pairwise first pass. Eats up list1 in runs of
* increasing order, list2 in a corresponding linked list. Checks for runs
* when THRESHOLD/2 pairs compare with same sense. (Only used when NATURAL
* is defined. Otherwise simple pairwise merging is used.)
*/
void
setup(u_char *list1, u_char *list2, size_t n, size_t size, cmp_t cmp)
{
int i, length, size2, tmp, sense;
u_char *f1, *f2, *s, *l2, *last, *p2;
size2 = size*2;
if (n <= 5) {
insertionsort(list1, n, size, cmp);
*EVAL(list2) = (u_char*) list2 + n*size;
return;
}
/*
* Avoid running pointers out of bounds; limit n to evens
* for simplicity.
*/
i = 4 + (n & 1);
insertionsort(list1 + (n - i) * size, i, size, cmp);
last = list1 + size * (n - i);
*EVAL(list2 + (last - list1)) = list2 + n * size;
#ifdef NATURAL
p2 = list2;
f1 = list1;
sense = (CMP(f1, f1 + size) > 0);
for (; f1 < last; sense = !sense) {
length = 2;
/* Find pairs with same sense. */
for (f2 = f1 + size2; f2 < last; f2 += size2) {
if ((CMP(f2, f2+ size) > 0) != sense)
break;
length += 2;
}
if (length < THRESHOLD) { /* Pairwise merge */
do {
p2 = *EVAL(p2) = f1 + size2 - list1 + list2;
if (sense > 0)
swap (f1, f1 + size);
} while ((f1 += size2) < f2);
} else { /* Natural merge */
l2 = f2;
for (f2 = f1 + size2; f2 < l2; f2 += size2) {
if ((CMP(f2-size, f2) > 0) != sense) {
p2 = *EVAL(p2) = f2 - list1 + list2;
if (sense > 0)
reverse(f1, f2-size);
f1 = f2;
}
}
if (sense > 0)
reverse (f1, f2-size);
f1 = f2;
if (f2 < last || CMP(f2 - size, f2) > 0)
p2 = *EVAL(p2) = f2 - list1 + list2;
else
p2 = *EVAL(p2) = list2 + n*size;
}
}
#else /* pairwise merge only. */
for (f1 = list1, p2 = list2; f1 < last; f1 += size2) {
p2 = *EVAL(p2) = p2 + size2;
if (CMP (f1, f1 + size) > 0)
swap(f1, f1 + size);
}
#endif /* NATURAL */
}
/*
* This is to avoid out-of-bounds addresses in sorting the
* last 4 elements.
*/
static void
insertionsort(u_char *a, size_t n, size_t size, cmp_t cmp)
{
u_char *ai, *s, *t, *u, tmp;
int i;
for (ai = a+size; --n >= 1; ai += size)
for (t = ai; t > a; t -= size) {
u = t - size;
if (CMP(u, t) <= 0)
break;
swap(u, t);
}
}
diff --git a/lib/libc/stdlib/ptsname.c b/lib/libc/stdlib/ptsname.c
index 13fe1479cb0d..ea1bc9c7b7f6 100644
--- a/lib/libc/stdlib/ptsname.c
+++ b/lib/libc/stdlib/ptsname.c
@@ -1,118 +1,117 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Portions of this software were developed under sponsorship from Snow
* B.V., the Netherlands.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#ifndef lint
#endif /* not lint */
#include "namespace.h"
#include <sys/param.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <paths.h>
#include <stdlib.h>
#include <string.h>
#include "un-namespace.h"
/*
* __isptmaster(): return whether the file descriptor refers to a
* pseudo-terminal master device.
*/
static int
__isptmaster(int fildes)
{
if (_ioctl(fildes, TIOCPTMASTER) == 0)
return (0);
if (errno != EBADF)
errno = EINVAL;
return (-1);
}
/*
* In our implementation, grantpt() and unlockpt() don't actually have
* any use, because PTY's are created on the fly and already have proper
* permissions upon creation.
*
* Just make sure `fildes' actually points to a real PTY master device.
*/
__strong_reference(__isptmaster, grantpt);
__strong_reference(__isptmaster, unlockpt);
/*
* ptsname_r(): return the pathname of the slave pseudo-terminal device
* associated with the specified master.
*/
int
__ptsname_r(int fildes, char *buffer, size_t buflen)
{
if (buflen <= sizeof(_PATH_DEV)) {
errno = ERANGE;
return (-1);
}
/* Make sure fildes points to a master device. */
if (__isptmaster(fildes) != 0)
return (-1);
memcpy(buffer, _PATH_DEV, sizeof(_PATH_DEV));
buffer += sizeof(_PATH_DEV) - 1;
buflen -= sizeof(_PATH_DEV) - 1;
if (fdevname_r(fildes, buffer, buflen) == NULL) {
if (errno == EINVAL)
errno = ERANGE;
return (-1);
}
return (0);
}
__strong_reference(__ptsname_r, ptsname_r);
/*
* ptsname(): return the pathname of the slave pseudo-terminal device
* associated with the specified master.
*/
char *
ptsname(int fildes)
{
static char pt_slave[sizeof(_PATH_DEV) + SPECNAMELEN];
if (__ptsname_r(fildes, pt_slave, sizeof(pt_slave)) == 0)
return (pt_slave);
return (NULL);
}
diff --git a/lib/libc/stdlib/qsort.c b/lib/libc/stdlib/qsort.c
index d6b6005333f5..22308887de1a 100644
--- a/lib/libc/stdlib/qsort.c
+++ b/lib/libc/stdlib/qsort.c
@@ -1,265 +1,264 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)qsort.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "libc_private.h"
#if defined(I_AM_QSORT_R)
typedef int cmp_t(const void *, const void *, void *);
#elif defined(I_AM_QSORT_R_COMPAT)
typedef int cmp_t(void *, const void *, const void *);
#elif defined(I_AM_QSORT_S)
typedef int cmp_t(const void *, const void *, void *);
#else
typedef int cmp_t(const void *, const void *);
#endif
static inline char *med3(char *, char *, char *, cmp_t *, void *);
#define MIN(a, b) ((a) < (b) ? a : b)
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*/
static inline void
swapfunc(char *a, char *b, size_t es)
{
char t;
do {
t = *a;
*a++ = *b;
*b++ = t;
} while (--es > 0);
}
#define vecswap(a, b, n) \
if ((n) > 0) swapfunc(a, b, n)
#if defined(I_AM_QSORT_R)
#define CMP(t, x, y) (cmp((x), (y), (t)))
#elif defined(I_AM_QSORT_R_COMPAT)
#define CMP(t, x, y) (cmp((t), (x), (y)))
#elif defined(I_AM_QSORT_S)
#define CMP(t, x, y) (cmp((x), (y), (t)))
#else
#define CMP(t, x, y) (cmp((x), (y)))
#endif
static inline char *
med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
#if !defined(I_AM_QSORT_R) && !defined(I_AM_QSORT_R_COMPAT) && !defined(I_AM_QSORT_S)
__unused
#endif
)
{
return CMP(thunk, a, b) < 0 ?
(CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
:(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
}
/*
* The actual qsort() implementation is static to avoid preemptible calls when
* recursing. Also give them different names for improved debugging.
*/
#if defined(I_AM_QSORT_R)
#define local_qsort local_qsort_r
#elif defined(I_AM_QSORT_R_COMPAT)
#define local_qsort local_qsort_r_compat
#elif defined(I_AM_QSORT_S)
#define local_qsort local_qsort_s
#endif
static void
local_qsort(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
size_t d1, d2;
int cmp_result;
int swap_cnt;
/* if there are less than 2 elements, then sorting is not needed */
if (__predict_false(n < 2))
return;
loop:
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swapfunc(pl, pl - es, es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
size_t d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
pm = med3(pm - d, pm, pm + d, cmp, thunk);
pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
}
pm = med3(pl, pm, pn, cmp, thunk);
}
swapfunc(a, pm, es);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swapfunc(pa, pb, es);
pa += es;
}
pb += es;
}
while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swapfunc(pc, pd, es);
pd -= es;
}
pc -= es;
}
if (pb > pc)
break;
swapfunc(pb, pc, es);
swap_cnt = 1;
pb += es;
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swapfunc(pl, pl - es, es);
return;
}
pn = (char *)a + n * es;
d1 = MIN(pa - (char *)a, pb - pa);
vecswap(a, pb - d1, d1);
/*
* Cast es to preserve signedness of right-hand side of MIN()
* expression, to avoid sign ambiguity in the implied comparison. es
* is safely within [0, SSIZE_MAX].
*/
d1 = MIN(pd - pc, pn - pd - (ssize_t)es);
vecswap(pb, pn - d1, d1);
d1 = pb - pa;
d2 = pd - pc;
if (d1 <= d2) {
/* Recurse on left partition, then iterate on right partition */
if (d1 > es) {
local_qsort(a, d1 / es, es, cmp, thunk);
}
if (d2 > es) {
/* Iterate rather than recurse to save stack space */
/* qsort(pn - d2, d2 / es, es, cmp); */
a = pn - d2;
n = d2 / es;
goto loop;
}
} else {
/* Recurse on right partition, then iterate on left partition */
if (d2 > es) {
local_qsort(pn - d2, d2 / es, es, cmp, thunk);
}
if (d1 > es) {
/* Iterate rather than recurse to save stack space */
/* qsort(a, d1 / es, es, cmp); */
n = d1 / es;
goto loop;
}
}
}
#if defined(I_AM_QSORT_R)
void
(qsort_r)(void *a, size_t n, size_t es, cmp_t *cmp, void *thunk)
{
local_qsort_r(a, n, es, cmp, thunk);
}
#elif defined(I_AM_QSORT_R_COMPAT)
void
__qsort_r_compat(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
{
local_qsort_r_compat(a, n, es, cmp, thunk);
}
#elif defined(I_AM_QSORT_S)
errno_t
qsort_s(void *a, rsize_t n, rsize_t es, cmp_t *cmp, void *thunk)
{
if (n > RSIZE_MAX) {
__throw_constraint_handler_s("qsort_s : n > RSIZE_MAX", EINVAL);
return (EINVAL);
} else if (es > RSIZE_MAX) {
__throw_constraint_handler_s("qsort_s : es > RSIZE_MAX",
EINVAL);
return (EINVAL);
} else if (n != 0) {
if (a == NULL) {
__throw_constraint_handler_s("qsort_s : a == NULL",
EINVAL);
return (EINVAL);
} else if (cmp == NULL) {
__throw_constraint_handler_s("qsort_s : cmp == NULL",
EINVAL);
return (EINVAL);
} else if (es <= 0) {
__throw_constraint_handler_s("qsort_s : es <= 0",
EINVAL);
return (EINVAL);
}
}
local_qsort_s(a, n, es, cmp, thunk);
return (0);
}
#else
void
qsort(void *a, size_t n, size_t es, cmp_t *cmp)
{
local_qsort(a, n, es, cmp, NULL);
}
#endif
diff --git a/lib/libc/stdlib/radixsort.c b/lib/libc/stdlib/radixsort.c
index 2f5b959cd549..3942102d2ed4 100644
--- a/lib/libc/stdlib/radixsort.c
+++ b/lib/libc/stdlib/radixsort.c
@@ -1,311 +1,310 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Peter McIlroy and by Dan Bernstein at New York University,
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)radixsort.c 8.2 (Berkeley) 4/28/95";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
/*
* Radixsort routines.
*
* Program r_sort_a() is unstable but uses O(logN) extra memory for a stack.
* Use radixsort(a, n, trace, endchar) for this case.
*
* For stable sorting (using N extra pointers) use sradixsort(), which calls
* r_sort_b().
*
* For a description of this code, see D. McIlroy, P. McIlroy, K. Bostic,
* "Engineering Radix Sort".
*/
#include <sys/types.h>
#include <stdlib.h>
#include <stddef.h>
#include <errno.h>
typedef struct {
const u_char **sa;
int sn, si;
} stack;
static inline void simplesort
(const u_char **, int, int, const u_char *, u_int);
static void r_sort_a(const u_char **, int, int, const u_char *, u_int);
static void r_sort_b(const u_char **, const u_char **, int, int,
const u_char *, u_int);
#define THRESHOLD 20 /* Divert to simplesort(). */
#define SIZE 512 /* Default stack size. */
#define SETUP { \
if (tab == NULL) { \
tr = tr0; \
for (c = 0; c < endch; c++) \
tr0[c] = c + 1; \
tr0[c] = 0; \
for (c++; c < 256; c++) \
tr0[c] = c; \
endch = 0; \
} else { \
endch = tab[endch]; \
tr = tab; \
if (endch != 0 && endch != 255) { \
errno = EINVAL; \
return (-1); \
} \
} \
}
int
radixsort(const u_char **a, int n, const u_char *tab, u_int endch)
{
const u_char *tr;
int c;
u_char tr0[256];
SETUP;
r_sort_a(a, n, 0, tr, endch);
return (0);
}
int
sradixsort(const u_char **a, int n, const u_char *tab, u_int endch)
{
const u_char *tr, **ta;
int c;
u_char tr0[256];
SETUP;
if (n < THRESHOLD)
simplesort(a, n, 0, tr, endch);
else {
if ((ta = malloc(n * sizeof(a))) == NULL)
return (-1);
r_sort_b(a, ta, n, 0, tr, endch);
free(ta);
}
return (0);
}
#define empty(s) (s >= sp)
#define pop(a, n, i) a = (--sp)->sa, n = sp->sn, i = sp->si
#define push(a, n, i) sp->sa = a, sp->sn = n, (sp++)->si = i
#define swap(a, b, t) t = a, a = b, b = t
/* Unstable, in-place sort. */
static void
r_sort_a(const u_char **a, int n, int i, const u_char *tr, u_int endch)
{
static int count[256], nc, bmin;
int c;
const u_char **ak, *r;
stack s[SIZE], *sp, *sp0, *sp1, temp;
int *cp, bigc;
const u_char **an, *t, **aj, **top[256];
/* Set up stack. */
sp = s;
push(a, n, i);
while (!empty(s)) {
pop(a, n, i);
if (n < THRESHOLD) {
simplesort(a, n, i, tr, endch);
continue;
}
an = a + n;
/* Make character histogram. */
if (nc == 0) {
bmin = 255; /* First occupied bin, excluding eos. */
for (ak = a; ak < an;) {
c = tr[(*ak++)[i]];
if (++count[c] == 1 && c != endch) {
if (c < bmin)
bmin = c;
nc++;
}
}
if (sp + nc > s + SIZE) { /* Get more stack. */
r_sort_a(a, n, i, tr, endch);
continue;
}
}
/*
* Special case: if all strings have the same
* character at position i, move on to the next
* character.
*/
if (nc == 1 && count[bmin] == n) {
push(a, n, i+1);
nc = count[bmin] = 0;
continue;
}
/*
* Set top[]; push incompletely sorted bins onto stack.
* top[] = pointers to last out-of-place element in bins.
* count[] = counts of elements in bins.
* Before permuting: top[c-1] + count[c] = top[c];
* during deal: top[c] counts down to top[c-1].
*/
sp0 = sp1 = sp; /* Stack position of biggest bin. */
bigc = 2; /* Size of biggest bin. */
if (endch == 0) /* Special case: set top[eos]. */
top[0] = ak = a + count[0];
else {
ak = a;
top[255] = an;
}
for (cp = count + bmin; nc > 0; cp++) {
while (*cp == 0) /* Find next non-empty pile. */
cp++;
if (*cp > 1) {
if (*cp > bigc) {
bigc = *cp;
sp1 = sp;
}
push(ak, *cp, i+1);
}
top[cp-count] = ak += *cp;
nc--;
}
swap(*sp0, *sp1, temp); /* Play it safe -- biggest bin last. */
/*
* Permute misplacements home. Already home: everything
* before aj, and in bin[c], items from top[c] on.
* Inner loop:
* r = next element to put in place;
* ak = top[r[i]] = location to put the next element.
* aj = bottom of 1st disordered bin.
* Outer loop:
* Once the 1st disordered bin is done, ie. aj >= ak,
* aj<-aj + count[c] connects the bins in a linked list;
* reset count[c].
*/
for (aj = a; aj < an; *aj = r, aj += count[c], count[c] = 0)
for (r = *aj; aj < (ak = --top[c = tr[r[i]]]);)
swap(*ak, r, t);
}
}
/* Stable sort, requiring additional memory. */
static void
r_sort_b(const u_char **a, const u_char **ta, int n, int i, const u_char *tr,
u_int endch)
{
static int count[256], nc, bmin;
int c;
const u_char **ak, **ai;
stack s[512], *sp, *sp0, *sp1, temp;
const u_char **top[256];
int *cp, bigc;
sp = s;
push(a, n, i);
while (!empty(s)) {
pop(a, n, i);
if (n < THRESHOLD) {
simplesort(a, n, i, tr, endch);
continue;
}
if (nc == 0) {
bmin = 255;
for (ak = a + n; --ak >= a;) {
c = tr[(*ak)[i]];
if (++count[c] == 1 && c != endch) {
if (c < bmin)
bmin = c;
nc++;
}
}
if (sp + nc > s + SIZE) {
r_sort_b(a, ta, n, i, tr, endch);
continue;
}
}
sp0 = sp1 = sp;
bigc = 2;
if (endch == 0) {
top[0] = ak = a + count[0];
count[0] = 0;
} else {
ak = a;
top[255] = a + n;
count[255] = 0;
}
for (cp = count + bmin; nc > 0; cp++) {
while (*cp == 0)
cp++;
if ((c = *cp) > 1) {
if (c > bigc) {
bigc = c;
sp1 = sp;
}
push(ak, c, i+1);
}
top[cp-count] = ak += c;
*cp = 0; /* Reset count[]. */
nc--;
}
swap(*sp0, *sp1, temp);
for (ak = ta + n, ai = a+n; ak > ta;) /* Copy to temp. */
*--ak = *--ai;
for (ak = ta+n; --ak >= ta;) /* Deal to piles. */
*--top[tr[(*ak)[i]]] = *ak;
}
}
/* insertion sort */
static inline void
simplesort(const u_char **a, int n, int b, const u_char *tr, u_int endch)
{
u_char ch;
const u_char **ak, **ai, *s, *t;
for (ak = a+1; --n >= 1; ak++)
for (ai = ak; ai > a; ai--) {
for (s = ai[0] + b, t = ai[-1] + b;
(ch = tr[*s]) != endch; s++, t++)
if (ch != tr[*t])
break;
if (ch >= tr[*t])
break;
swap(ai[0], ai[-1], s);
}
}
diff --git a/lib/libc/stdlib/rand.c b/lib/libc/stdlib/rand.c
index f02839e06fc9..15b1054b9104 100644
--- a/lib/libc/stdlib/rand.c
+++ b/lib/libc/stdlib/rand.c
@@ -1,166 +1,165 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Posix rand_r function added May 1999 by Wes Peters <wes@softweyr.com>.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rand.c 8.1 (Berkeley) 6/14/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/sysctl.h>
#include <assert.h>
#include <pthread.h>
#include <stdbool.h>
#include <stdlib.h>
#include <syslog.h>
#include "un-namespace.h"
#include "libc_private.h"
#include "random.h"
/*
* Implement rand(3), the standard C PRNG API, using the non-standard but
* higher quality random(3) implementation and the same size 128-byte state
* LFSR as the random(3) default.
*
* It turns out there are portable applications that want a PRNG but are too
* lazy to use better-but-nonstandard interfaces like random(3), when
* available, and too lazy to import higher-quality and faster PRNGs into their
* codebase (such as any of SFC, JSF, 128-bit LCGs, PCG, or Splitmix64).
*
* Since we're stuck with rand(3) due to the C standard, we can at least have
* it produce a relatively good PRNG sequence using our existing random(3)
* LFSR. The random(3) design is not particularly fast nor compact, but it has
* the advantage of being the one already in the tree.
*/
static struct __random_state *rand3_state;
static pthread_once_t rand3_state_once = PTHREAD_ONCE_INIT;
static void
initialize_rand3(void)
{
int error;
rand3_state = allocatestate(TYPE_3);
error = initstate_r(rand3_state, 1, rand3_state->rst_randtbl, BREAK_3);
assert(error == 0);
}
int
rand(void)
{
_once(&rand3_state_once, initialize_rand3);
return ((int)random_r(rand3_state));
}
void
srand(unsigned seed)
{
_once(&rand3_state_once, initialize_rand3);
srandom_r(rand3_state, seed);
}
/*
* FreeBSD 12 and prior compatibility implementation of rand(3).
*/
static int
do_rand(unsigned long *ctx)
{
/*
* Compute x = (7^5 * x) mod (2^31 - 1)
* without overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
long hi, lo, x;
/* Transform to [1, 0x7ffffffe] range. */
x = (*ctx % 0x7ffffffe) + 1;
hi = x / 127773;
lo = x % 127773;
x = 16807 * lo - 2836 * hi;
if (x < 0)
x += 0x7fffffff;
/* Transform to [0, 0x7ffffffd] range. */
x--;
*ctx = x;
return (x);
}
/*
* Can't fix this garbage; too little state.
*/
int
rand_r(unsigned *ctx)
{
u_long val;
int r;
val = *ctx;
r = do_rand(&val);
*ctx = (unsigned)val;
return (r);
}
static u_long next = 1;
int __rand_fbsd12(void);
int
__rand_fbsd12(void)
{
return (do_rand(&next));
}
__sym_compat(rand, __rand_fbsd12, FBSD_1.0);
void __srand_fbsd12(unsigned seed);
void
__srand_fbsd12(unsigned seed)
{
next = seed;
}
__sym_compat(srand, __srand_fbsd12, FBSD_1.0);
void __sranddev_fbsd12(void);
void
__sranddev_fbsd12(void)
{
static bool warned = false;
if (!warned) {
syslog(LOG_DEBUG, "Deprecated function sranddev() called");
warned = true;
}
}
__sym_compat(sranddev, __sranddev_fbsd12, FBSD_1.0);
diff --git a/lib/libc/stdlib/random.c b/lib/libc/stdlib/random.c
index 8e0832754b3b..0dd24dbdcc1d 100644
--- a/lib/libc/stdlib/random.c
+++ b/lib/libc/stdlib/random.c
@@ -1,505 +1,504 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1983, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)random.c 8.2 (Berkeley) 5/19/95";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/sysctl.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include "un-namespace.h"
#include "random.h"
/*
* random.c:
*
* An improved random number generation package. In addition to the standard
* rand()/srand() like interface, this package also has a special state info
* interface. The initstate() routine is called with a seed, an array of
* bytes, and a count of how many bytes are being passed in; this array is
* then initialized to contain information for random number generation with
* that much state information. Good sizes for the amount of state
* information are 32, 64, 128, and 256 bytes. The state can be switched by
* calling the setstate() routine with the same array as was initiallized
* with initstate(). By default, the package runs with 128 bytes of state
* information and generates far better random numbers than a linear
* congruential generator. If the amount of state information is less than
* 32 bytes, a simple linear congruential R.N.G. is used.
*
* Internally, the state information is treated as an array of uint32_t's; the
* zeroeth element of the array is the type of R.N.G. being used (small
* integer); the remainder of the array is the state information for the
* R.N.G. Thus, 32 bytes of state information will give 7 ints worth of
* state information, which will allow a degree seven polynomial. (Note:
* the zeroeth word of state information also has some other information
* stored in it -- see setstate() for details).
*
* The random number generation technique is a linear feedback shift register
* approach, employing trinomials (since there are fewer terms to sum up that
* way). In this approach, the least significant bit of all the numbers in
* the state table will act as a linear feedback shift register, and will
* have period 2^deg - 1 (where deg is the degree of the polynomial being
* used, assuming that the polynomial is irreducible and primitive). The
* higher order bits will have longer periods, since their values are also
* influenced by pseudo-random carries out of the lower bits. The total
* period of the generator is approximately deg*(2**deg - 1); thus doubling
* the amount of state information has a vast influence on the period of the
* generator. Note: the deg*(2**deg - 1) is an approximation only good for
* large deg, when the period of the shift is the dominant factor.
* With deg equal to seven, the period is actually much longer than the
* 7*(2**7 - 1) predicted by this formula.
*
* Modified 28 December 1994 by Jacob S. Rosenberg.
* The following changes have been made:
* All references to the type u_int have been changed to unsigned long.
* All references to type int have been changed to type long. Other
* cleanups have been made as well. A warning for both initstate and
* setstate has been inserted to the effect that on Sparc platforms
* the 'arg_state' variable must be forced to begin on word boundaries.
* This can be easily done by casting a long integer array to char *.
* The overall logic has been left STRICTLY alone. This software was
* tested on both a VAX and Sun SpacsStation with exactly the same
* results. The new version and the original give IDENTICAL results.
* The new version is somewhat faster than the original. As the
* documentation says: "By default, the package runs with 128 bytes of
* state information and generates far better random numbers than a linear
* congruential generator. If the amount of state information is less than
* 32 bytes, a simple linear congruential R.N.G. is used." For a buffer of
* 128 bytes, this new version runs about 19 percent faster and for a 16
* byte buffer it is about 5 percent faster.
*/
#define NSHUFF 50 /* to drop some "seed -> 1st value" linearity */
static const int degrees[MAX_TYPES] = { DEG_0, DEG_1, DEG_2, DEG_3, DEG_4 };
static const int seps[MAX_TYPES] = { SEP_0, SEP_1, SEP_2, SEP_3, SEP_4 };
static const int breaks[MAX_TYPES] = {
BREAK_0, BREAK_1, BREAK_2, BREAK_3, BREAK_4
};
/*
* Initially, everything is set up as if from:
*
* initstate(1, randtbl, 128);
*
* Note that this initialization takes advantage of the fact that srandom()
* advances the front and rear pointers 10*rand_deg times, and hence the
* rear pointer which starts at 0 will also end up at zero; thus the zeroeth
* element of the state information, which contains info about the current
* position of the rear pointer is just
*
* MAX_TYPES * (rptr - state) + TYPE_3 == TYPE_3.
*/
static struct __random_state implicit = {
.rst_randtbl = {
TYPE_3,
0x2cf41758, 0x27bb3711, 0x4916d4d1, 0x7b02f59f, 0x9b8e28eb, 0xc0e80269,
0x696f5c16, 0x878f1ff5, 0x52d9c07f, 0x916a06cd, 0xb50b3a20, 0x2776970a,
0xee4eb2a6, 0xe94640ec, 0xb1d65612, 0x9d1ed968, 0x1043f6b7, 0xa3432a76,
0x17eacbb9, 0x3c09e2eb, 0x4f8c2b3, 0x708a1f57, 0xee341814, 0x95d0e4d2,
0xb06f216c, 0x8bd2e72e, 0x8f7c38d7, 0xcfc6a8fc, 0x2a59495, 0xa20d2a69,
0xe29d12d1
},
/*
* fptr and rptr are two pointers into the state info, a front and a rear
* pointer. These two pointers are always rand_sep places aparts, as they
* cycle cyclically through the state information. (Yes, this does mean we
* could get away with just one pointer, but the code for random() is more
* efficient this way). The pointers are left positioned as they would be
* from the call
*
* initstate(1, randtbl, 128);
*
* (The position of the rear pointer, rptr, is really 0 (as explained above
* in the initialization of randtbl) because the state table pointer is set
* to point to randtbl[1] (as explained below).
*/
.rst_fptr = &implicit.rst_randtbl[SEP_3 + 1],
.rst_rptr = &implicit.rst_randtbl[1],
/*
* The following things are the pointer to the state information table, the
* type of the current generator, the degree of the current polynomial being
* used, and the separation between the two pointers. Note that for efficiency
* of random(), we remember the first location of the state information, not
* the zeroeth. Hence it is valid to access state[-1], which is used to
* store the type of the R.N.G. Also, we remember the last location, since
* this is more efficient than indexing every time to find the address of
* the last element to see if the front and rear pointers have wrapped.
*/
.rst_state = &implicit.rst_randtbl[1],
.rst_type = TYPE_3,
.rst_deg = DEG_3,
.rst_sep = SEP_3,
.rst_end_ptr = &implicit.rst_randtbl[DEG_3 + 1],
};
/*
* This is the same low quality PRNG used in rand(3) in FreeBSD 12 and prior.
* It may be sufficient for distributing bits and expanding a small seed
* integer into a larger state.
*/
static inline uint32_t
parkmiller32(uint32_t ctx)
{
/*
* Compute x = (7^5 * x) mod (2^31 - 1)
* wihout overflowing 31 bits:
* (2^31 - 1) = 127773 * (7^5) + 2836
* From "Random number generators: good ones are hard to find",
* Park and Miller, Communications of the ACM, vol. 31, no. 10,
* October 1988, p. 1195.
*/
int32_t hi, lo, x;
/* Transform to [1, 0x7ffffffe] range. */
x = (ctx % 0x7ffffffe) + 1;
hi = x / 127773;
lo = x % 127773;
x = 16807 * lo - 2836 * hi;
if (x < 0)
x += 0x7fffffff;
/* Transform to [0, 0x7ffffffd] range. */
return (x - 1);
}
/*
* srandom:
*
* Initialize the random number generator based on the given seed. If the
* type is the trivial no-state-information type, just remember the seed.
* Otherwise, initializes state[] based on the given "seed" via a linear
* congruential generator. Then, the pointers are set to known locations
* that are exactly rand_sep places apart. Lastly, it cycles the state
* information a given number of times to get rid of any initial dependencies
* introduced by the L.C.R.N.G. Note that the initialization of randtbl[]
* for default usage relies on values produced by this routine.
*/
void
srandom_r(struct __random_state *estate, unsigned x)
{
int i, lim;
estate->rst_state[0] = (uint32_t)x;
if (estate->rst_type == TYPE_0)
lim = NSHUFF;
else {
for (i = 1; i < estate->rst_deg; i++)
estate->rst_state[i] =
parkmiller32(estate->rst_state[i - 1]);
estate->rst_fptr = &estate->rst_state[estate->rst_sep];
estate->rst_rptr = &estate->rst_state[0];
lim = 10 * estate->rst_deg;
}
for (i = 0; i < lim; i++)
(void)random_r(estate);
}
void
srandom(unsigned x)
{
srandom_r(&implicit, x);
}
/*
* srandomdev:
*
* Many programs choose the seed value in a totally predictable manner.
* This often causes problems. We seed the generator using pseudo-random
* data from the kernel.
*
* Note that this particular seeding procedure can generate states
* which are impossible to reproduce by calling srandom() with any
* value, since the succeeding terms in the state buffer are no longer
* derived from the LC algorithm applied to a fixed seed.
*/
void
srandomdev_r(struct __random_state *estate)
{
int mib[2];
size_t expected, len;
if (estate->rst_type == TYPE_0)
len = sizeof(estate->rst_state[0]);
else
len = estate->rst_deg * sizeof(estate->rst_state[0]);
expected = len;
mib[0] = CTL_KERN;
mib[1] = KERN_ARND;
if (sysctl(mib, 2, estate->rst_state, &len, NULL, 0) == -1 ||
len != expected) {
/*
* The sysctl cannot fail. If it does fail on some FreeBSD
* derivative or after some future change, just abort so that
* the problem will be found and fixed. abort is not normally
* suitable for a library but makes sense here.
*/
abort();
}
if (estate->rst_type != TYPE_0) {
estate->rst_fptr = &estate->rst_state[estate->rst_sep];
estate->rst_rptr = &estate->rst_state[0];
}
}
void
srandomdev(void)
{
srandomdev_r(&implicit);
}
/*
* initstate_r:
*
* Initialize the state information in the given array of n bytes for future
* random number generation. Based on the number of bytes we are given, and
* the break values for the different R.N.G.'s, we choose the best (largest)
* one we can and set things up for it. srandom() is then called to
* initialize the state information.
*
* Returns zero on success, or an error number on failure.
*
* Note: There is no need for a setstate_r(); just use a new context.
*/
int
initstate_r(struct __random_state *estate, unsigned seed, uint32_t *arg_state,
size_t sz)
{
if (sz < BREAK_0)
return (EINVAL);
if (sz < BREAK_1) {
estate->rst_type = TYPE_0;
estate->rst_deg = DEG_0;
estate->rst_sep = SEP_0;
} else if (sz < BREAK_2) {
estate->rst_type = TYPE_1;
estate->rst_deg = DEG_1;
estate->rst_sep = SEP_1;
} else if (sz < BREAK_3) {
estate->rst_type = TYPE_2;
estate->rst_deg = DEG_2;
estate->rst_sep = SEP_2;
} else if (sz < BREAK_4) {
estate->rst_type = TYPE_3;
estate->rst_deg = DEG_3;
estate->rst_sep = SEP_3;
} else {
estate->rst_type = TYPE_4;
estate->rst_deg = DEG_4;
estate->rst_sep = SEP_4;
}
estate->rst_state = arg_state + 1;
estate->rst_end_ptr = &estate->rst_state[estate->rst_deg];
srandom_r(estate, seed);
return (0);
}
/*
* initstate:
*
* Note: the first thing we do is save the current state, if any, just like
* setstate() so that it doesn't matter when initstate is called.
*
* Note that on return from initstate_r(), we set state[-1] to be the type
* multiplexed with the current value of the rear pointer; this is so
* successive calls to initstate() won't lose this information and will be able
* to restart with setstate().
*
* Returns a pointer to the old state.
*
* Despite the misleading "char *" type, arg_state must alias an array of
* 32-bit unsigned integer values. Naturally, such an array is 32-bit aligned.
* Usually objects are naturally aligned to at least 32-bits on all platforms,
* but if you treat the provided 'state' as char* you may inadvertently
* misalign it. Don't do that.
*/
char *
initstate(unsigned int seed, char *arg_state, size_t n)
{
char *ostate = (char *)(&implicit.rst_state[-1]);
uint32_t *int_arg_state = (uint32_t *)arg_state;
int error;
/*
* Persist rptr offset and rst_type in the first word of the prior
* state we are replacing.
*/
if (implicit.rst_type == TYPE_0)
implicit.rst_state[-1] = implicit.rst_type;
else
implicit.rst_state[-1] = MAX_TYPES *
(implicit.rst_rptr - implicit.rst_state) +
implicit.rst_type;
error = initstate_r(&implicit, seed, int_arg_state, n);
if (error != 0)
return (NULL);
/*
* Persist rptr offset and rst_type of the new state in its first word.
*/
if (implicit.rst_type == TYPE_0)
int_arg_state[0] = implicit.rst_type;
else
int_arg_state[0] = MAX_TYPES *
(implicit.rst_rptr - implicit.rst_state) +
implicit.rst_type;
return (ostate);
}
/*
* setstate:
*
* Restore the state from the given state array.
*
* Note: it is important that we also remember the locations of the pointers
* in the current state information, and restore the locations of the pointers
* from the old state information. This is done by multiplexing the pointer
* location into the zeroeth word of the state information.
*
* Note that due to the order in which things are done, it is OK to call
* setstate() with the same state as the current state.
*
* Returns a pointer to the old state information.
*
* Note: The Sparc platform requires that arg_state begin on an int
* word boundary; otherwise a bus error will occur. Even so, lint will
* complain about mis-alignment, but you should disregard these messages.
*/
char *
setstate(char *arg_state)
{
uint32_t *new_state = (uint32_t *)arg_state;
uint32_t type = new_state[0] % MAX_TYPES;
uint32_t rear = new_state[0] / MAX_TYPES;
char *ostate = (char *)(&implicit.rst_state[-1]);
if (type != TYPE_0 && rear >= degrees[type])
return (NULL);
if (implicit.rst_type == TYPE_0)
implicit.rst_state[-1] = implicit.rst_type;
else
implicit.rst_state[-1] = MAX_TYPES *
(implicit.rst_rptr - implicit.rst_state) +
implicit.rst_type;
implicit.rst_type = type;
implicit.rst_deg = degrees[type];
implicit.rst_sep = seps[type];
implicit.rst_state = new_state + 1;
if (implicit.rst_type != TYPE_0) {
implicit.rst_rptr = &implicit.rst_state[rear];
implicit.rst_fptr = &implicit.rst_state[
(rear + implicit.rst_sep) % implicit.rst_deg];
}
implicit.rst_end_ptr = &implicit.rst_state[implicit.rst_deg];
return (ostate);
}
/*
* random:
*
* If we are using the trivial TYPE_0 R.N.G., just do the old linear
* congruential bit. Otherwise, we do our fancy trinomial stuff, which is
* the same in all the other cases due to all the global variables that have
* been set up. The basic operation is to add the number at the rear pointer
* into the one at the front pointer. Then both pointers are advanced to
* the next location cyclically in the table. The value returned is the sum
* generated, reduced to 31 bits by throwing away the "least random" low bit.
*
* Note: the code takes advantage of the fact that both the front and
* rear pointers can't wrap on the same call by not testing the rear
* pointer if the front one has wrapped.
*
* Returns a 31-bit random number.
*/
long
random_r(struct __random_state *estate)
{
uint32_t i;
uint32_t *f, *r;
if (estate->rst_type == TYPE_0) {
i = estate->rst_state[0];
i = parkmiller32(i);
estate->rst_state[0] = i;
} else {
/*
* Use local variables rather than static variables for speed.
*/
f = estate->rst_fptr;
r = estate->rst_rptr;
*f += *r;
i = *f >> 1; /* chucking least random bit */
if (++f >= estate->rst_end_ptr) {
f = estate->rst_state;
++r;
}
else if (++r >= estate->rst_end_ptr) {
r = estate->rst_state;
}
estate->rst_fptr = f;
estate->rst_rptr = r;
}
return ((long)i);
}
long
random(void)
{
return (random_r(&implicit));
}
struct __random_state *
allocatestate(unsigned type)
{
size_t asize;
/* No point using this interface to get the Park-Miller LCG. */
if (type < TYPE_1)
abort();
/* Clamp to widest supported variant. */
if (type > (MAX_TYPES - 1))
type = (MAX_TYPES - 1);
asize = sizeof(struct __random_state) + (size_t)breaks[type];
return (malloc(asize));
}
diff --git a/lib/libc/stdlib/reallocarray.c b/lib/libc/stdlib/reallocarray.c
index 76e4d331c4ce..0868804486cc 100644
--- a/lib/libc/stdlib/reallocarray.c
+++ b/lib/libc/stdlib/reallocarray.c
@@ -1,40 +1,39 @@
/* $OpenBSD: reallocarray.c,v 1.2 2014/12/08 03:45:00 bcook Exp $ */
/*
* Copyright (c) 2008 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 <sys/cdefs.h>
#include <sys/types.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
/*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW ((size_t)1 << (sizeof(size_t) * 4))
void *
reallocarray(void *optr, size_t nmemb, size_t size)
{
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
errno = ENOMEM;
return (NULL);
}
return (realloc(optr, size * nmemb));
}
diff --git a/lib/libc/stdlib/reallocf.c b/lib/libc/stdlib/reallocf.c
index 63c42383a8bf..3ab90bfdf471 100644
--- a/lib/libc/stdlib/reallocf.c
+++ b/lib/libc/stdlib/reallocf.c
@@ -1,47 +1,46 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 1998 M. Warner Losh <imp@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
void *
reallocf(void *ptr, size_t size)
{
void *nptr;
nptr = realloc(ptr, size);
/*
* When the System V compatibility option (malloc "V" flag) is
* in effect, realloc(ptr, 0) frees the memory and returns NULL.
* So, to avoid double free, call free() only when size != 0.
* realloc(ptr, 0) can't fail when ptr != NULL.
*/
if (!nptr && ptr && size != 0)
free(ptr);
return (nptr);
}
diff --git a/lib/libc/stdlib/realpath.c b/lib/libc/stdlib/realpath.c
index 302e3c1a8c8c..64f1dbdf1b7d 100644
--- a/lib/libc/stdlib/realpath.c
+++ b/lib/libc/stdlib/realpath.c
@@ -1,237 +1,236 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The names of the authors may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include "un-namespace.h"
#include "libc_private.h"
extern int __realpathat(int fd, const char *path, char *buf, size_t size,
int flags);
/*
* Find the real name of path, by removing all ".", ".." and symlink
* components. Returns (resolved) on success, or (NULL) on failure,
* in which case the path which caused trouble is left in (resolved).
*/
static char * __noinline
realpath1(const char *path, char *resolved)
{
struct stat sb;
char *p, *q;
size_t left_len, resolved_len, next_token_len;
unsigned symlinks;
ssize_t slen;
char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX];
symlinks = 0;
if (path[0] == '/') {
resolved[0] = '/';
resolved[1] = '\0';
if (path[1] == '\0')
return (resolved);
resolved_len = 1;
left_len = strlcpy(left, path + 1, sizeof(left));
} else {
if (getcwd(resolved, PATH_MAX) == NULL) {
resolved[0] = '.';
resolved[1] = '\0';
return (NULL);
}
resolved_len = strlen(resolved);
left_len = strlcpy(left, path, sizeof(left));
}
if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) {
errno = ENAMETOOLONG;
return (NULL);
}
/*
* Iterate over path components in `left'.
*/
while (left_len != 0) {
/*
* Extract the next path component and adjust `left'
* and its length.
*/
p = strchr(left, '/');
next_token_len = p != NULL ? (size_t)(p - left) : left_len;
memcpy(next_token, left, next_token_len);
next_token[next_token_len] = '\0';
if (p != NULL) {
left_len -= next_token_len + 1;
memmove(left, p + 1, left_len + 1);
} else {
left[0] = '\0';
left_len = 0;
}
if (resolved[resolved_len - 1] != '/') {
if (resolved_len + 1 >= PATH_MAX) {
errno = ENAMETOOLONG;
return (NULL);
}
resolved[resolved_len++] = '/';
resolved[resolved_len] = '\0';
}
if (next_token[0] == '\0') {
/* Handle consequential slashes. */
continue;
} else if (strcmp(next_token, ".") == 0) {
continue;
} else if (strcmp(next_token, "..") == 0) {
/*
* Strip the last path component except when we have
* single "/"
*/
if (resolved_len > 1) {
resolved[resolved_len - 1] = '\0';
q = strrchr(resolved, '/') + 1;
*q = '\0';
resolved_len = q - resolved;
}
continue;
}
/*
* Append the next path component and lstat() it.
*/
resolved_len = strlcat(resolved, next_token, PATH_MAX);
if (resolved_len >= PATH_MAX) {
errno = ENAMETOOLONG;
return (NULL);
}
if (lstat(resolved, &sb) != 0)
return (NULL);
if (S_ISLNK(sb.st_mode)) {
if (symlinks++ > MAXSYMLINKS) {
errno = ELOOP;
return (NULL);
}
slen = readlink(resolved, symlink, sizeof(symlink));
if (slen <= 0 || slen >= (ssize_t)sizeof(symlink)) {
if (slen < 0)
; /* keep errno from readlink(2) call */
else if (slen == 0)
errno = ENOENT;
else
errno = ENAMETOOLONG;
return (NULL);
}
symlink[slen] = '\0';
if (symlink[0] == '/') {
resolved[1] = 0;
resolved_len = 1;
} else {
/* Strip the last path component. */
q = strrchr(resolved, '/') + 1;
*q = '\0';
resolved_len = q - resolved;
}
/*
* If there are any path components left, then
* append them to symlink. The result is placed
* in `left'.
*/
if (p != NULL) {
if (symlink[slen - 1] != '/') {
if (slen + 1 >= (ssize_t)sizeof(symlink)) {
errno = ENAMETOOLONG;
return (NULL);
}
symlink[slen] = '/';
symlink[slen + 1] = 0;
}
left_len = strlcat(symlink, left,
sizeof(symlink));
if (left_len >= sizeof(symlink)) {
errno = ENAMETOOLONG;
return (NULL);
}
}
left_len = strlcpy(left, symlink, sizeof(left));
} else if (!S_ISDIR(sb.st_mode) && p != NULL) {
errno = ENOTDIR;
return (NULL);
}
}
/*
* Remove trailing slash except when the resolved pathname
* is a single "/".
*/
if (resolved_len > 1 && resolved[resolved_len - 1] == '/')
resolved[resolved_len - 1] = '\0';
return (resolved);
}
char *
realpath(const char * __restrict path, char * __restrict resolved)
{
char *m, *res;
if (path == NULL) {
errno = EINVAL;
return (NULL);
}
if (path[0] == '\0') {
errno = ENOENT;
return (NULL);
}
if (resolved != NULL) {
m = NULL;
} else {
m = resolved = malloc(PATH_MAX);
if (resolved == NULL)
return (NULL);
}
if (__getosreldate() >= 1300080) {
if (__realpathat(AT_FDCWD, path, resolved, PATH_MAX, 0) == 0)
return (resolved);
}
res = realpath1(path, resolved);
if (res == NULL)
free(m);
return (res);
}
diff --git a/lib/libc/stdlib/remque.c b/lib/libc/stdlib/remque.c
index 783ffc3a9934..1b532ce11ff6 100644
--- a/lib/libc/stdlib/remque.c
+++ b/lib/libc/stdlib/remque.c
@@ -1,28 +1,27 @@
/*
* Initial implementation:
* Copyright (c) 2002 Robert Drehmel
* All rights reserved.
*
* As long as the above copyright statement and this notice remain
* unchanged, you can do what ever you want with this file.
*/
-#include <sys/cdefs.h>
#define _SEARCH_PRIVATE
#include <search.h>
#include <stdlib.h> /* for NULL */
void
remque(void *element)
{
struct que_elem *prev, *next, *elem;
elem = (struct que_elem *)element;
prev = elem->prev;
next = elem->next;
if (prev != NULL)
prev->next = next;
if (next != NULL)
next->prev = prev;
}
diff --git a/lib/libc/stdlib/set_constraint_handler_s.c b/lib/libc/stdlib/set_constraint_handler_s.c
index 76f9ecfe5a52..298c4d94a4b9 100644
--- a/lib/libc/stdlib/set_constraint_handler_s.c
+++ b/lib/libc/stdlib/set_constraint_handler_s.c
@@ -1,99 +1,98 @@
/*-
* Copyright (c) 2017 Juniper Networks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <machine/atomic.h>
#include <errno.h>
#include <pthread.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include "libc_private.h"
/*
* Rationale recommends allocating new memory each time.
*/
static constraint_handler_t *_ch = NULL;
static pthread_mutex_t ch_lock = PTHREAD_MUTEX_INITIALIZER;
constraint_handler_t
set_constraint_handler_s(constraint_handler_t handler)
{
constraint_handler_t *new, *old, ret;
new = malloc(sizeof(constraint_handler_t));
if (new == NULL)
return (NULL);
*new = handler;
if (__isthreaded)
_pthread_mutex_lock(&ch_lock);
old = _ch;
_ch = new;
if (__isthreaded)
_pthread_mutex_unlock(&ch_lock);
if (old == NULL) {
ret = NULL;
} else {
ret = *old;
free(old);
}
return (ret);
}
void
__throw_constraint_handler_s(const char * restrict msg, errno_t error)
{
constraint_handler_t ch;
if (__isthreaded)
_pthread_mutex_lock(&ch_lock);
ch = _ch != NULL ? *_ch : NULL;
if (__isthreaded)
_pthread_mutex_unlock(&ch_lock);
if (ch != NULL)
ch(msg, NULL, error);
}
void
abort_handler_s(const char * restrict msg, void * restrict ptr __unused,
errno_t error __unused)
{
static const char ahs[] = "abort_handler_s : ";
(void) _write(STDERR_FILENO, ahs, sizeof(ahs) - 1);
(void) _write(STDERR_FILENO, msg, strlen(msg));
(void) _write(STDERR_FILENO, "\n", 1);
abort();
}
void
ignore_handler_s(const char * restrict msg __unused,
void * restrict ptr __unused, errno_t error __unused)
{
}
diff --git a/lib/libc/stdlib/strfmon.c b/lib/libc/stdlib/strfmon.c
index 0e36eb0babe5..b2d76fbed769 100644
--- a/lib/libc/stdlib/strfmon.c
+++ b/lib/libc/stdlib/strfmon.c
@@ -1,668 +1,667 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <monetary.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "xlocale_private.h"
/* internal flags */
#define NEED_GROUPING 0x01 /* print digits grouped (default) */
#define SIGN_POSN_USED 0x02 /* '+' or '(' usage flag */
#define LOCALE_POSN 0x04 /* use locale defined +/- (default) */
#define PARENTH_POSN 0x08 /* enclose negative amount in () */
#define SUPPRESS_CURR_SYMBOL 0x10 /* suppress the currency from output */
#define LEFT_JUSTIFY 0x20 /* left justify */
#define USE_INTL_CURRENCY 0x40 /* use international currency symbol */
#define IS_NEGATIVE 0x80 /* is argument value negative ? */
/* internal macros */
#define PRINT(CH) do { \
if (dst >= s + maxsize) \
goto e2big_error; \
*dst++ = CH; \
} while (0)
#define PRINTS(STR) do { \
char *tmps = STR; \
while (*tmps != '\0') \
PRINT(*tmps++); \
} while (0)
#define GET_NUMBER(VAR, LOC) do { \
VAR = 0; \
while (isdigit_l((unsigned char)*fmt, LOC)) { \
if (VAR > INT_MAX / 10) \
goto e2big_error; \
VAR *= 10; \
VAR += *fmt - '0'; \
if (VAR < 0) \
goto e2big_error; \
fmt++; \
} \
} while (0)
#define GRPCPY(howmany) do { \
int i = howmany; \
while (i-- > 0) { \
avalue_size--; \
*--bufend = *(avalue + avalue_size + padded); \
} \
} while (0)
#define GRPSEP do { \
bufend -= thousands_sep_size; \
memcpy(bufend, thousands_sep, thousands_sep_size); \
groups++; \
} while (0)
static void __setup_vars(int, char *, char *, char *, char **, struct lconv *);
static int __calc_left_pad(int, char *, struct lconv *);
static char *__format_grouped_double(double, int *, int, int, int,
struct lconv *, locale_t);
static ssize_t
vstrfmon_l(char * __restrict s, size_t maxsize, locale_t loc,
const char * __restrict format, va_list ap)
{
char *dst; /* output destination pointer */
const char *fmt; /* current format poistion pointer */
struct lconv *lc; /* pointer to lconv structure */
char *asciivalue; /* formatted double pointer */
int flags; /* formatting options */
int pad_char; /* padding character */
int pad_size; /* pad size */
int width; /* field width */
int left_prec; /* left precision */
int right_prec; /* right precision */
double value; /* just value */
char space_char = ' '; /* space after currency */
char cs_precedes, /* values gathered from struct lconv */
sep_by_space,
sign_posn,
*signstr,
*currency_symbol;
char *tmpptr; /* temporary vars */
int sverrno;
FIX_LOCALE(loc);
lc = localeconv_l(loc);
dst = s;
fmt = format;
asciivalue = NULL;
currency_symbol = NULL;
while (*fmt) {
/* pass nonformating characters AS IS */
if (*fmt != '%')
goto literal;
/* '%' found ! */
/* "%%" mean just '%' */
if (*(fmt + 1) == '%') {
fmt++;
literal:
PRINT(*fmt++);
continue;
}
/* set up initial values */
flags = (NEED_GROUPING|LOCALE_POSN);
pad_char = ' '; /* padding character is "space" */
pad_size = 0; /* no padding initially */
left_prec = -1; /* no left precision specified */
right_prec = -1; /* no right precision specified */
width = -1; /* no width specified */
value = 0; /* we have no value to print now */
/* Flags */
while (1) {
switch (*++fmt) {
case '=': /* fill character */
pad_char = *++fmt;
if (pad_char == '\0')
goto format_error;
continue;
case '^': /* not group currency */
flags &= ~(NEED_GROUPING);
continue;
case '+': /* use locale defined signs */
if (flags & SIGN_POSN_USED)
goto format_error;
flags |= (SIGN_POSN_USED|LOCALE_POSN);
continue;
case '(': /* enclose negatives with () */
if (flags & SIGN_POSN_USED)
goto format_error;
flags |= (SIGN_POSN_USED|PARENTH_POSN);
continue;
case '!': /* suppress currency symbol */
flags |= SUPPRESS_CURR_SYMBOL;
continue;
case '-': /* alignment (left) */
flags |= LEFT_JUSTIFY;
continue;
default:
break;
}
break;
}
/* field Width */
if (isdigit_l((unsigned char)*fmt, loc)) {
GET_NUMBER(width, loc);
/* Do we have enough space to put number with
* required width ?
*/
if ((unsigned int)width >= maxsize - (dst - s))
goto e2big_error;
}
/* Left precision */
if (*fmt == '#') {
if (!isdigit_l((unsigned char)*++fmt, loc))
goto format_error;
GET_NUMBER(left_prec, loc);
if ((unsigned int)left_prec >= maxsize - (dst - s))
goto e2big_error;
}
/* Right precision */
if (*fmt == '.') {
if (!isdigit_l((unsigned char)*++fmt, loc))
goto format_error;
GET_NUMBER(right_prec, loc);
if ((unsigned int)right_prec >= maxsize - (dst - s) -
left_prec)
goto e2big_error;
}
/* Conversion Characters */
switch (*fmt++) {
case 'i': /* use international currency format */
flags |= USE_INTL_CURRENCY;
break;
case 'n': /* use national currency format */
flags &= ~(USE_INTL_CURRENCY);
break;
default: /* required character is missing or
premature EOS */
goto format_error;
}
if (currency_symbol != NULL)
free(currency_symbol);
if (flags & USE_INTL_CURRENCY) {
currency_symbol = strdup(lc->int_curr_symbol);
if (currency_symbol != NULL &&
strlen(currency_symbol) > 3) {
space_char = currency_symbol[3];
currency_symbol[3] = '\0';
}
} else
currency_symbol = strdup(lc->currency_symbol);
if (currency_symbol == NULL)
goto end_error; /* ENOMEM. */
/* value itself */
value = va_arg(ap, double);
/* detect sign */
if (value < 0) {
flags |= IS_NEGATIVE;
value = -value;
}
/* fill left_prec with amount of padding chars */
if (left_prec >= 0) {
pad_size = __calc_left_pad((flags ^ IS_NEGATIVE),
currency_symbol, lc) -
__calc_left_pad(flags, currency_symbol, lc);
if (pad_size < 0)
pad_size = 0;
}
if (asciivalue != NULL)
free(asciivalue);
asciivalue = __format_grouped_double(value, &flags,
left_prec, right_prec, pad_char, lc, loc);
if (asciivalue == NULL)
goto end_error; /* errno already set */
/* to ENOMEM by malloc() */
/* set some variables for later use */
__setup_vars(flags, &cs_precedes, &sep_by_space,
&sign_posn, &signstr, lc);
/*
* Description of some LC_MONETARY's values:
*
* p_cs_precedes & n_cs_precedes
*
* = 1 - $currency_symbol precedes the value
* for a monetary quantity with a non-negative value
* = 0 - symbol succeeds the value
*
* p_sep_by_space & n_sep_by_space
*
* = 0 - no space separates $currency_symbol
* from the value for a monetary quantity with a
* non-negative value
* = 1 - space separates the symbol from the value
* = 2 - space separates the symbol and the sign string,
* if adjacent; otherwise, a space separates
* the sign string from the value
*
* p_sign_posn & n_sign_posn
*
* = 0 - parentheses enclose the quantity and the
* $currency_symbol
* = 1 - the sign string precedes the quantity and the
* $currency_symbol
* = 2 - the sign string succeeds the quantity and the
* $currency_symbol
* = 3 - the sign string precedes the $currency_symbol
* = 4 - the sign string succeeds the $currency_symbol
*
*/
tmpptr = dst;
while (pad_size-- > 0)
PRINT(' ');
if (sign_posn == 0 && (flags & IS_NEGATIVE))
PRINT('(');
if (cs_precedes == 1) {
if (sign_posn == 1 || sign_posn == 3) {
PRINTS(signstr);
if (sep_by_space == 2)
PRINT(' ');
}
if (!(flags & SUPPRESS_CURR_SYMBOL)) {
PRINTS(currency_symbol);
if (sign_posn == 4) {
if (sep_by_space == 2)
PRINT(space_char);
PRINTS(signstr);
if (sep_by_space == 1)
PRINT(' ');
} else if (sep_by_space == 1)
PRINT(space_char);
}
} else if (sign_posn == 1) {
PRINTS(signstr);
if (sep_by_space == 2)
PRINT(' ');
}
PRINTS(asciivalue);
if (cs_precedes == 0) {
if (sign_posn == 3) {
if (sep_by_space == 1)
PRINT(' ');
PRINTS(signstr);
}
if (!(flags & SUPPRESS_CURR_SYMBOL)) {
if ((sign_posn == 3 && sep_by_space == 2)
|| (sep_by_space == 1
&& (sign_posn == 0
|| sign_posn == 1
|| sign_posn == 2
|| sign_posn == 4)))
PRINT(space_char);
PRINTS(currency_symbol);
if (sign_posn == 4) {
if (sep_by_space == 2)
PRINT(' ');
PRINTS(signstr);
}
}
}
if (sign_posn == 2) {
if (sep_by_space == 2)
PRINT(' ');
PRINTS(signstr);
}
if (sign_posn == 0) {
if (flags & IS_NEGATIVE)
PRINT(')');
else if (left_prec >= 0)
PRINT(' ');
}
if (dst - tmpptr < width) {
if (flags & LEFT_JUSTIFY) {
while (dst - tmpptr < width)
PRINT(' ');
} else {
pad_size = dst - tmpptr;
memmove(tmpptr + width - pad_size, tmpptr,
pad_size);
memset(tmpptr, ' ', width - pad_size);
dst += width - pad_size;
}
}
}
PRINT('\0');
free(asciivalue);
free(currency_symbol);
return (dst - s - 1); /* return size of put data except trailing '\0' */
e2big_error:
errno = E2BIG;
goto end_error;
format_error:
errno = EINVAL;
end_error:
sverrno = errno;
if (asciivalue != NULL)
free(asciivalue);
if (currency_symbol != NULL)
free(currency_symbol);
errno = sverrno;
return (-1);
}
static void
__setup_vars(int flags, char *cs_precedes, char *sep_by_space,
char *sign_posn, char **signstr, struct lconv *lc)
{
if ((flags & IS_NEGATIVE) && (flags & USE_INTL_CURRENCY)) {
*cs_precedes = lc->int_n_cs_precedes;
*sep_by_space = lc->int_n_sep_by_space;
*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_n_sign_posn;
*signstr = (lc->negative_sign[0] == '\0') ? "-"
: lc->negative_sign;
} else if (flags & USE_INTL_CURRENCY) {
*cs_precedes = lc->int_p_cs_precedes;
*sep_by_space = lc->int_p_sep_by_space;
*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->int_p_sign_posn;
*signstr = lc->positive_sign;
} else if (flags & IS_NEGATIVE) {
*cs_precedes = lc->n_cs_precedes;
*sep_by_space = lc->n_sep_by_space;
*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->n_sign_posn;
*signstr = (lc->negative_sign[0] == '\0') ? "-"
: lc->negative_sign;
} else {
*cs_precedes = lc->p_cs_precedes;
*sep_by_space = lc->p_sep_by_space;
*sign_posn = (flags & PARENTH_POSN) ? 0 : lc->p_sign_posn;
*signstr = lc->positive_sign;
}
/* Set default values for unspecified information. */
if (*cs_precedes != 0)
*cs_precedes = 1;
if (*sep_by_space == CHAR_MAX)
*sep_by_space = 0;
if (*sign_posn == CHAR_MAX)
*sign_posn = 0;
}
static int
__calc_left_pad(int flags, char *cur_symb, struct lconv *lc)
{
char cs_precedes, sep_by_space, sign_posn, *signstr;
int left_chars = 0;
__setup_vars(flags, &cs_precedes, &sep_by_space, &sign_posn,
&signstr, lc);
if (cs_precedes != 0) {
left_chars += strlen(cur_symb);
if (sep_by_space != 0)
left_chars++;
}
switch (sign_posn) {
case 0:
if (flags & IS_NEGATIVE)
left_chars++;
break;
case 1:
left_chars += strlen(signstr);
break;
case 3:
case 4:
if (cs_precedes != 0)
left_chars += strlen(signstr);
}
return (left_chars);
}
static int
get_groups(int size, char *grouping)
{
int chars = 0;
if (*grouping == CHAR_MAX || *grouping <= 0) /* no grouping ? */
return (0);
while (size > (int)*grouping) {
chars++;
size -= (int)*grouping++;
/* no more grouping ? */
if (*grouping == CHAR_MAX)
break;
/* rest grouping with same value ? */
if (*grouping == 0) {
chars += (size - 1) / *(grouping - 1);
break;
}
}
return (chars);
}
/* convert double to locale-encoded string */
static char *
__format_grouped_double(double value, int *flags,
int left_prec, int right_prec, int pad_char, struct lconv *lc, locale_t loc)
{
char *rslt;
char *avalue;
int avalue_size;
size_t bufsize;
char *bufend;
int padded;
char *grouping;
const char *decimal_point;
const char *thousands_sep;
size_t decimal_point_size;
size_t thousands_sep_size;
int groups = 0;
grouping = lc->mon_grouping;
decimal_point = lc->mon_decimal_point;
if (*decimal_point == '\0')
decimal_point = lc->decimal_point;
thousands_sep = lc->mon_thousands_sep;
if (*thousands_sep == '\0')
thousands_sep = lc->thousands_sep;
decimal_point_size = strlen(decimal_point);
thousands_sep_size = strlen(thousands_sep);
/* fill left_prec with default value */
if (left_prec == -1)
left_prec = 0;
/* fill right_prec with default value */
if (right_prec == -1) {
if (*flags & USE_INTL_CURRENCY)
right_prec = lc->int_frac_digits;
else
right_prec = lc->frac_digits;
if (right_prec == CHAR_MAX) /* POSIX locale ? */
right_prec = 2;
}
if (*flags & NEED_GROUPING)
left_prec += get_groups(left_prec, grouping);
/* convert to string */
avalue_size = asprintf_l(&avalue, loc, "%*.*f",
left_prec + right_prec + 1, right_prec, value);
if (avalue_size < 0)
return (NULL);
/* make sure that we've enough space for result string */
bufsize = avalue_size * (1 + thousands_sep_size) + decimal_point_size +
1;
rslt = calloc(1, bufsize);
if (rslt == NULL) {
free(avalue);
return (NULL);
}
bufend = rslt + bufsize - 1; /* reserve space for trailing '\0' */
/* skip spaces at beginning */
padded = 0;
while (avalue[padded] == ' ') {
padded++;
avalue_size--;
}
if (right_prec > 0) {
bufend -= right_prec;
memcpy(bufend, avalue + avalue_size + padded - right_prec,
right_prec);
bufend -= decimal_point_size;
memcpy(bufend, decimal_point, decimal_point_size);
avalue_size -= (right_prec + 1);
}
if ((*flags & NEED_GROUPING) &&
thousands_sep_size > 0 &&
*grouping != CHAR_MAX &&
*grouping > 0) {
while (avalue_size > (int)*grouping) {
GRPCPY(*grouping);
GRPSEP;
grouping++;
/* no more grouping ? */
if (*grouping == CHAR_MAX)
break;
/* rest grouping with same value ? */
if (*grouping == 0) {
grouping--;
while (avalue_size > *grouping) {
GRPCPY(*grouping);
GRPSEP;
}
}
}
if (avalue_size != 0)
GRPCPY(avalue_size);
padded -= groups;
} else {
bufend -= avalue_size;
memcpy(bufend, avalue + padded, avalue_size);
/* decrease assumed $decimal_point */
if (right_prec == 0)
padded -= decimal_point_size;
}
/* do padding with pad_char */
if (padded > 0) {
bufend -= padded;
memset(bufend, pad_char, padded);
}
bufsize = rslt + bufsize - bufend;
memmove(rslt, bufend, bufsize);
free(avalue);
return (rslt);
}
ssize_t
strfmon(char * __restrict s, size_t maxsize, const char * __restrict format,
...)
{
ssize_t ret;
va_list ap;
va_start(ap, format);
ret = vstrfmon_l(s, maxsize, __get_locale(), format, ap);
va_end(ap);
return (ret);
}
ssize_t
strfmon_l(char * __restrict s, size_t maxsize, locale_t loc,
const char * __restrict format, ...)
{
ssize_t ret;
va_list ap;
va_start(ap, format);
ret = vstrfmon_l(s, maxsize, loc, format, ap);
va_end(ap);
return (ret);
}
diff --git a/lib/libc/stdlib/strtoimax.c b/lib/libc/stdlib/strtoimax.c
index 5309b7d4305c..401eebe8ce2c 100644
--- a/lib/libc/stdlib/strtoimax.c
+++ b/lib/libc/stdlib/strtoimax.c
@@ -1,160 +1,159 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "from @(#)strtol.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <inttypes.h>
#include "xlocale_private.h"
/*
* Convert a string to an intmax_t integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
intmax_t
strtoimax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
locale_t locale)
{
const char *s;
uintmax_t acc;
char c;
uintmax_t cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
s = nptr;
do {
c = *s++;
} while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X') &&
((s[1] >= '0' && s[1] <= '9') ||
(s[1] >= 'A' && s[1] <= 'F') ||
(s[1] >= 'a' && s[1] <= 'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B') &&
(s[1] >= '0' && s[1] <= '1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for intmax_t is
* [-9223372036854775808..9223372036854775807] and the input base
* is 10, cutoff will be set to 922337203685477580 and cutlim to
* either 7 (neg==0) or 8 (neg==1), meaning that if we have
* accumulated a value > 922337203685477580, or equal but the
* next digit is > 7 (or 8), the number is too big, and we will
* return a range error.
*
* Set 'any' if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? (uintmax_t)-(INTMAX_MIN + INTMAX_MAX) + INTMAX_MAX
: INTMAX_MAX;
cutlim = cutoff % base;
cutoff /= base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? INTMAX_MIN : INTMAX_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
intmax_t
strtoimax(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtoimax_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/stdlib/strtol.c b/lib/libc/stdlib/strtol.c
index 1ca95918ef12..26ecd4264e3f 100644
--- a/lib/libc/stdlib/strtol.c
+++ b/lib/libc/stdlib/strtol.c
@@ -1,159 +1,158 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include "xlocale_private.h"
/*
* Convert a string to a long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
long
strtol_l(const char * __restrict nptr, char ** __restrict endptr, int base,
locale_t locale)
{
const char *s;
unsigned long acc;
char c;
unsigned long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0x for hex and 0 for octal, else
* assume decimal; if base is already 16, allow 0x.
*/
s = nptr;
do {
c = *s++;
} while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X') &&
((s[1] >= '0' && s[1] <= '9') ||
(s[1] >= 'A' && s[1] <= 'F') ||
(s[1] >= 'a' && s[1] <= 'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B') &&
(s[1] >= '0' && s[1] <= '1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for longs is
* [-2147483648..2147483647] and the input base is 10,
* cutoff will be set to 214748364 and cutlim to either
* 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
* a value > 214748364, or equal but the next digit is > 7 (or 8),
* the number is too big, and we will return a range error.
*
* Set 'any' if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
: LONG_MAX;
cutlim = cutoff % base;
cutoff /= base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LONG_MIN : LONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
long
strtol(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtol_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/stdlib/strtold.c b/lib/libc/stdlib/strtold.c
index 2f7cabbdd88b..fa05f7a63889 100644
--- a/lib/libc/stdlib/strtold.c
+++ b/lib/libc/stdlib/strtold.c
@@ -1,40 +1,39 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2011 The FreeBSD Foundation
*
* This software was developed by David Chisnall under sponsorship from the
* FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include "xlocale_private.h"
long double
strtold(const char * __restrict nptr, char ** __restrict endptr)
{
return strtold_l(nptr, endptr, __get_locale());
}
diff --git a/lib/libc/stdlib/strtoll.c b/lib/libc/stdlib/strtoll.c
index 6845776c5f03..bddc795a28a2 100644
--- a/lib/libc/stdlib/strtoll.c
+++ b/lib/libc/stdlib/strtoll.c
@@ -1,161 +1,160 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include "xlocale_private.h"
/*
* Convert a string to a long long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
long long
strtoll_l(const char * __restrict nptr, char ** __restrict endptr, int base,
locale_t locale)
{
const char *s;
unsigned long long acc;
char c;
unsigned long long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* Skip white space and pick up leading +/- sign if any.
* If base is 0, allow 0b for binary, 0x for hex, and 0 for
* octal, else assume decimal; if base is already 2, allow
* 0b; if base is already 16, allow 0x.
*/
s = nptr;
do {
c = *s++;
} while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X') &&
((s[1] >= '0' && s[1] <= '9') ||
(s[1] >= 'A' && s[1] <= 'F') ||
(s[1] >= 'a' && s[1] <= 'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B') &&
(s[1] >= '0' && s[1] <= '1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
/*
* Compute the cutoff value between legal numbers and illegal
* numbers. That is the largest legal value, divided by the
* base. An input number that is greater than this value, if
* followed by a legal input character, is too big. One that
* is equal to this value may be valid or not; the limit
* between valid and invalid numbers is then based on the last
* digit. For instance, if the range for quads is
* [-9223372036854775808..9223372036854775807] and the input base
* is 10, cutoff will be set to 922337203685477580 and cutlim to
* either 7 (neg==0) or 8 (neg==1), meaning that if we have
* accumulated a value > 922337203685477580, or equal but the
* next digit is > 7 (or 8), the number is too big, and we will
* return a range error.
*
* Set 'any' if any `digits' consumed; make it negative to indicate
* overflow.
*/
cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
: LLONG_MAX;
cutlim = cutoff % base;
cutoff /= base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = neg ? LLONG_MIN : LLONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
long long
strtoll(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtoll_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c
index a25c43f6a330..0d0715bf39c1 100644
--- a/lib/libc/stdlib/strtonum.c
+++ b/lib/libc/stdlib/strtonum.c
@@ -1,66 +1,65 @@
/*-
* Copyright (c) 2004 Ted Unangst and Todd Miller
* All rights reserved.
*
* 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.
*
* $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#define INVALID 1
#define TOOSMALL 2
#define TOOLARGE 3
long long
strtonum(const char *numstr, long long minval, long long maxval,
const char **errstrp)
{
long long ll = 0;
int error = 0;
char *ep;
struct errval {
const char *errstr;
int err;
} ev[4] = {
{ NULL, 0 },
{ "invalid", EINVAL },
{ "too small", ERANGE },
{ "too large", ERANGE },
};
ev[0].err = errno;
errno = 0;
if (minval > maxval) {
error = INVALID;
} else {
ll = strtoll(numstr, &ep, 10);
if (errno == EINVAL || numstr == ep || *ep != '\0')
error = INVALID;
else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
error = TOOSMALL;
else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
error = TOOLARGE;
}
if (errstrp != NULL)
*errstrp = ev[error].errstr;
errno = ev[error].err;
if (error)
ll = 0;
return (ll);
}
diff --git a/lib/libc/stdlib/strtoq.c b/lib/libc/stdlib/strtoq.c
index e83af1c7652a..dfdc5d4ec7ff 100644
--- a/lib/libc/stdlib/strtoq.c
+++ b/lib/libc/stdlib/strtoq.c
@@ -1,48 +1,47 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtoq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdlib.h>
/*
* Convert a string to a quad integer.
*/
quad_t
strtoq(const char *nptr, char **endptr, int base)
{
return strtoll(nptr, endptr, base);
}
diff --git a/lib/libc/stdlib/strtoul.c b/lib/libc/stdlib/strtoul.c
index c0dbd0c9fdac..2e605dd1e477 100644
--- a/lib/libc/stdlib/strtoul.c
+++ b/lib/libc/stdlib/strtoul.c
@@ -1,137 +1,136 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <limits.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include "xlocale_private.h"
/*
* Convert a string to an unsigned long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
unsigned long
strtoul_l(const char * __restrict nptr, char ** __restrict endptr, int base, locale_t locale)
{
const char *s;
unsigned long acc;
char c;
unsigned long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtol for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X') &&
((s[1] >= '0' && s[1] <= '9') ||
(s[1] >= 'A' && s[1] <= 'F') ||
(s[1] >= 'a' && s[1] <= 'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B') &&
(s[1] >= '0' && s[1] <= '1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = ULONG_MAX / base;
cutlim = ULONG_MAX % base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
unsigned long
strtoul(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtoul_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/stdlib/strtoull.c b/lib/libc/stdlib/strtoull.c
index fe44a9e01c05..7872e966d858 100644
--- a/lib/libc/stdlib/strtoull.c
+++ b/lib/libc/stdlib/strtoull.c
@@ -1,138 +1,137 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <limits.h>
#include <errno.h>
#include <ctype.h>
#include <stdlib.h>
#include "xlocale_private.h"
/*
* Convert a string to an unsigned long long integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
unsigned long long
strtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
locale_t locale)
{
const char *s;
unsigned long long acc;
char c;
unsigned long long cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtoq for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X') &&
((s[1] >= '0' && s[1] <= '9') ||
(s[1] >= 'A' && s[1] <= 'F') ||
(s[1] >= 'a' && s[1] <= 'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B') &&
(s[1] >= '0' && s[1] <= '1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = ULLONG_MAX / base;
cutlim = ULLONG_MAX % base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = ULLONG_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
unsigned long long
strtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtoull_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/stdlib/strtoumax.c b/lib/libc/stdlib/strtoumax.c
index 08140be38845..8953523a54bc 100644
--- a/lib/libc/stdlib/strtoumax.c
+++ b/lib/libc/stdlib/strtoumax.c
@@ -1,138 +1,137 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "from @(#)strtoul.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <inttypes.h>
#include "xlocale_private.h"
/*
* Convert a string to a uintmax_t integer.
*
* Assumes that the upper and lower case
* alphabets and digits are each contiguous.
*/
uintmax_t
strtoumax_l(const char * __restrict nptr, char ** __restrict endptr, int base,
locale_t locale)
{
const char *s;
uintmax_t acc;
char c;
uintmax_t cutoff;
int neg, any, cutlim;
FIX_LOCALE(locale);
/*
* See strtoimax for comments as to the logic used.
*/
s = nptr;
do {
c = *s++;
} while (isspace_l((unsigned char)c, locale));
if (c == '-') {
neg = 1;
c = *s++;
} else {
neg = 0;
if (c == '+')
c = *s++;
}
if ((base == 0 || base == 16) &&
c == '0' && (*s == 'x' || *s == 'X') &&
((s[1] >= '0' && s[1] <= '9') ||
(s[1] >= 'A' && s[1] <= 'F') ||
(s[1] >= 'a' && s[1] <= 'f'))) {
c = s[1];
s += 2;
base = 16;
}
if ((base == 0 || base == 2) &&
c == '0' && (*s == 'b' || *s == 'B') &&
(s[1] >= '0' && s[1] <= '1')) {
c = s[1];
s += 2;
base = 2;
}
if (base == 0)
base = c == '0' ? 8 : 10;
acc = any = 0;
if (base < 2 || base > 36)
goto noconv;
cutoff = UINTMAX_MAX / base;
cutlim = UINTMAX_MAX % base;
for ( ; ; c = *s++) {
if (c >= '0' && c <= '9')
c -= '0';
else if (c >= 'A' && c <= 'Z')
c -= 'A' - 10;
else if (c >= 'a' && c <= 'z')
c -= 'a' - 10;
else
break;
if (c >= base)
break;
if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
any = -1;
else {
any = 1;
acc *= base;
acc += c;
}
}
if (any < 0) {
acc = UINTMAX_MAX;
errno = ERANGE;
} else if (!any) {
noconv:
errno = EINVAL;
} else if (neg)
acc = -acc;
if (endptr != NULL)
*endptr = (char *)(any ? s - 1 : nptr);
return (acc);
}
uintmax_t
strtoumax(const char * __restrict nptr, char ** __restrict endptr, int base)
{
return strtoumax_l(nptr, endptr, base, __get_locale());
}
diff --git a/lib/libc/stdlib/strtouq.c b/lib/libc/stdlib/strtouq.c
index 18e917b19b67..51541b5f62e8 100644
--- a/lib/libc/stdlib/strtouq.c
+++ b/lib/libc/stdlib/strtouq.c
@@ -1,48 +1,47 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtouq.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdlib.h>
/*
* Convert a string to an unsigned quad integer.
*/
u_quad_t
strtouq(const char *nptr, char **endptr, int base)
{
return strtoull(nptr, endptr, base);
}
diff --git a/lib/libc/stdlib/system.c b/lib/libc/stdlib/system.c
index 4ad5d605865b..35ef45ec53ec 100644
--- a/lib/libc/stdlib/system.c
+++ b/lib/libc/stdlib/system.c
@@ -1,112 +1,111 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)system.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <unistd.h>
#include <paths.h>
#include <errno.h>
#include "un-namespace.h"
#include "libc_private.h"
#pragma weak system
int
system(const char *command)
{
return (((int (*)(const char *))
__libc_interposing[INTERPOS_system])(command));
}
int
__libc_system(const char *command)
{
pid_t pid, savedpid;
int pstat;
struct sigaction ign, intact, quitact;
sigset_t newsigblock, oldsigblock;
if (!command) /* just checking... */
return(1);
(void)sigemptyset(&newsigblock);
(void)sigaddset(&newsigblock, SIGCHLD);
(void)sigaddset(&newsigblock, SIGINT);
(void)sigaddset(&newsigblock, SIGQUIT);
(void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock);
switch(pid = vfork()) {
/*
* In the child, use unwrapped syscalls. libthr is in
* undefined state after vfork().
*/
case -1: /* error */
(void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
return (-1);
case 0: /* child */
/*
* Restore original signal dispositions and exec the command.
*/
(void)__sys_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
execl(_PATH_BSHELL, "sh", "-c", command, (char *)NULL);
_exit(127);
}
/*
* If we are running means that the child has either completed
* its execve, or has failed.
* Block SIGINT/QUIT because sh -c handles it and wait for
* it to clean up.
*/
memset(&ign, 0, sizeof(ign));
ign.sa_handler = SIG_IGN;
(void)sigemptyset(&ign.sa_mask);
(void)__libc_sigaction(SIGINT, &ign, &intact);
(void)__libc_sigaction(SIGQUIT, &ign, &quitact);
savedpid = pid;
do {
pid = _wait4(savedpid, &pstat, 0, (struct rusage *)0);
} while (pid == -1 && errno == EINTR);
(void)__libc_sigaction(SIGINT, &intact, NULL);
(void)__libc_sigaction(SIGQUIT, &quitact, NULL);
(void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL);
return (pid == -1 ? -1 : pstat);
}
__weak_reference(__libc_system, __system);
__weak_reference(__libc_system, _system);
diff --git a/lib/libc/stdlib/tdelete.c b/lib/libc/stdlib/tdelete.c
index 8b3f34848db0..3b00a6cf0852 100644
--- a/lib/libc/stdlib/tdelete.c
+++ b/lib/libc/stdlib/tdelete.c
@@ -1,206 +1,205 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define _SEARCH_PRIVATE
#include <search.h>
#include <stdbool.h>
#include <stdlib.h>
#include "tsearch_path.h"
/*
* Makes a step to the left along the binary search tree. This step is
* also saved, so it can be replayed while rebalancing.
*/
#define GO_LEFT() do { \
if ((*leaf)->balance == 0 || \
((*leaf)->balance < 0 && (*leaf)->rlink->balance == 0)) { \
/* \
* If we reach a node that is balanced, or has a child \
* in the opposite direction that is balanced, we know \
* that we won't need to perform any rotations above \
* this point. In this case rotations are always \
* capable of keeping the subtree in balance. Make \
* this the root node and reset the path. \
*/ \
rootp = leaf; \
path_init(&path); \
} \
path_taking_left(&path); \
leaf = &(*leaf)->llink; \
} while (0)
/* Makes a step to the right along the binary search tree. */
#define GO_RIGHT() do { \
if ((*leaf)->balance == 0 || \
((*leaf)->balance > 0 && (*leaf)->llink->balance == 0)) { \
rootp = leaf; \
path_init(&path); \
} \
path_taking_right(&path); \
leaf = &(*leaf)->rlink; \
} while (0)
void *
tdelete(const void *restrict key, posix_tnode **restrict rootp,
int (*compar)(const void *, const void *))
{
struct path path;
posix_tnode **leaf, *old, **n, *x, *y, *z, *result;
int cmp;
/* POSIX requires that tdelete() returns NULL if rootp is NULL. */
if (rootp == NULL)
return (NULL);
/*
* Find the leaf that needs to be removed. Return if we cannot
* find an existing entry. Keep track of the path that is taken
* to get to the node, as we will need it to adjust the
* balances.
*/
result = (posix_tnode *)1;
path_init(&path);
leaf = rootp;
for (;;) {
if (*leaf == NULL)
return (NULL);
cmp = compar(key, (*leaf)->key);
if (cmp < 0) {
result = *leaf;
GO_LEFT();
} else if (cmp > 0) {
result = *leaf;
GO_RIGHT();
} else {
break;
}
}
/* Found a matching key in the tree. Remove the node. */
if ((*leaf)->llink == NULL) {
/* Node has no left children. Replace by its right subtree. */
old = *leaf;
*leaf = old->rlink;
free(old);
} else {
/*
* Node has left children. Replace this node's key by
* its predecessor's and remove that node instead.
*/
void **keyp = &(*leaf)->key;
GO_LEFT();
while ((*leaf)->rlink != NULL)
GO_RIGHT();
old = *leaf;
*keyp = old->key;
*leaf = old->llink;
free(old);
}
/*
* Walk along the same path a second time and adjust the
* balances. Though this code looks similar to the rebalancing
* performed in tsearch(), it is not identical. We now also need
* to consider the case of outward imbalance in the right-right
* and left-left case that only exists when deleting. Hence the
* duplication of code.
*/
for (n = rootp; n != leaf;) {
if (path_took_left(&path)) {
x = *n;
if (x->balance < 0) {
y = x->rlink;
if (y->balance > 0) {
/* Right-left case. */
z = y->llink;
x->rlink = z->llink;
z->llink = x;
y->llink = z->rlink;
z->rlink = y;
*n = z;
x->balance = z->balance < 0 ? 1 : 0;
y->balance = z->balance > 0 ? -1 : 0;
z->balance = 0;
} else {
/* Right-right case. */
x->rlink = y->llink;
y->llink = x;
*n = y;
if (y->balance < 0) {
x->balance = 0;
y->balance = 0;
} else {
x->balance = -1;
y->balance = 1;
}
}
} else {
--x->balance;
}
n = &x->llink;
} else {
x = *n;
if (x->balance > 0) {
y = x->llink;
if (y->balance < 0) {
/* Left-right case. */
z = y->rlink;
y->rlink = z->llink;
z->llink = y;
x->llink = z->rlink;
z->rlink = x;
*n = z;
x->balance = z->balance > 0 ? -1 : 0;
y->balance = z->balance < 0 ? 1 : 0;
z->balance = 0;
} else {
/* Left-left case. */
x->llink = y->rlink;
y->rlink = x;
*n = y;
if (y->balance > 0) {
x->balance = 0;
y->balance = 0;
} else {
x->balance = 1;
y->balance = -1;
}
}
} else {
++x->balance;
}
n = &x->rlink;
}
}
/* Return the parent of the old entry. */
return (result);
}
diff --git a/lib/libc/stdlib/tsearch.c b/lib/libc/stdlib/tsearch.c
index 09d6e4d26a87..7826c555c065 100644
--- a/lib/libc/stdlib/tsearch.c
+++ b/lib/libc/stdlib/tsearch.c
@@ -1,195 +1,194 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#define _SEARCH_PRIVATE
#include <search.h>
#include <stdlib.h>
#include "tsearch_path.h"
posix_tnode *
tsearch(const void *key, posix_tnode **rootp,
int (*compar)(const void *, const void *))
{
struct path path;
posix_tnode **leaf, *result, *n, *x, *y, *z;
int cmp;
/* POSIX requires that tsearch() returns NULL if rootp is NULL. */
if (rootp == NULL)
return (NULL);
/*
* Find the leaf where the new key needs to be inserted. Return
* if we've found an existing entry. Keep track of the path that
* is taken to get to the node, as we will need it to adjust the
* balances.
*/
path_init(&path);
leaf = rootp;
while (*leaf != NULL) {
if ((*leaf)->balance != 0) {
/*
* If we reach a node that has a non-zero
* balance on the way, we know that we won't
* need to perform any rotations above this
* point. In this case rotations are always
* capable of keeping the subtree in balance.
* Make this the root node and reset the path.
*/
rootp = leaf;
path_init(&path);
}
cmp = compar(key, (*leaf)->key);
if (cmp < 0) {
path_taking_left(&path);
leaf = &(*leaf)->llink;
} else if (cmp > 0) {
path_taking_right(&path);
leaf = &(*leaf)->rlink;
} else {
return (*leaf);
}
}
/* Did not find a matching key in the tree. Insert a new node. */
result = *leaf = malloc(sizeof(**leaf));
if (result == NULL)
return (NULL);
result->key = (void *)key;
result->llink = NULL;
result->rlink = NULL;
result->balance = 0;
/*
* Walk along the same path a second time and adjust the
* balances. Except for the first node, all of these nodes must
* have a balance of zero, meaning that these nodes will not get
* out of balance.
*/
for (n = *rootp; n != *leaf;) {
if (path_took_left(&path)) {
n->balance += 1;
n = n->llink;
} else {
n->balance -= 1;
n = n->rlink;
}
}
/*
* Adjusting the balances may have pushed the balance of the
* root node out of range. Perform a rotation to bring the
* balance back in range.
*/
x = *rootp;
if (x->balance > 1) {
y = x->llink;
if (y->balance < 0) {
/*
* Left-right case.
*
* x
* / \ z
* y D / \
* / \ --> y x
* A z /| |\
* / \ A B C D
* B C
*/
z = y->rlink;
y->rlink = z->llink;
z->llink = y;
x->llink = z->rlink;
z->rlink = x;
*rootp = z;
x->balance = z->balance > 0 ? -1 : 0;
y->balance = z->balance < 0 ? 1 : 0;
z->balance = 0;
} else {
/*
* Left-left case.
*
* x y
* / \ / \
* y C --> A x
* / \ / \
* A B B C
*/
x->llink = y->rlink;
y->rlink = x;
*rootp = y;
x->balance = 0;
y->balance = 0;
}
} else if (x->balance < -1) {
y = x->rlink;
if (y->balance > 0) {
/*
* Right-left case.
*
* x
* / \ z
* A y / \
* / \ --> x y
* z D /| |\
* / \ A B C D
* B C
*/
posix_tnode *z = y->llink;
x->rlink = z->llink;
z->llink = x;
y->llink = z->rlink;
z->rlink = y;
*rootp = z;
x->balance = z->balance < 0 ? 1 : 0;
y->balance = z->balance > 0 ? -1 : 0;
z->balance = 0;
} else {
/*
* Right-right case.
*
* x y
* / \ / \
* A y --> x C
* / \ / \
* B C A B
*/
x->rlink = y->llink;
y->llink = x;
*rootp = y;
x->balance = 0;
y->balance = 0;
}
}
/* Return the new entry. */
return (result);
}
diff --git a/lib/libc/stdtime/strftime.c b/lib/libc/stdtime/strftime.c
index 674aaa0bb302..2e89a394ea94 100644
--- a/lib/libc/stdtime/strftime.c
+++ b/lib/libc/stdtime/strftime.c
@@ -1,641 +1,640 @@
/*
* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*/
#ifndef lint
#ifndef NOID
static const char elsieid[] = "@(#)strftime.3 8.3";
/*
* Based on the UCB version with the ID appearing below.
* This is ANSIish only when "multibyte character == plain character".
*/
#endif /* !defined NOID */
#endif /* !defined lint */
#include "namespace.h"
#include "private.h"
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)strftime.c 5.4 (Berkeley) 3/14/89";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "tzfile.h"
#include <fcntl.h>
#include <sys/stat.h>
#include <stdio.h>
#include "un-namespace.h"
#include "timelocal.h"
static char * _add(const char *, char *, const char *);
static char * _conv(int, const char *, char *, const char *, locale_t);
static char * _fmt(const char *, const struct tm *, char *, const char *,
int *, locale_t);
static char * _yconv(int, int, int, int, char *, const char *, locale_t);
extern char * tzname[];
#ifndef YEAR_2000_NAME
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
#endif /* !defined YEAR_2000_NAME */
#define IN_NONE 0
#define IN_SOME 1
#define IN_THIS 2
#define IN_ALL 3
#define PAD_DEFAULT 0
#define PAD_LESS 1
#define PAD_SPACE 2
#define PAD_ZERO 3
static const char fmt_padding[][4][5] = {
/* DEFAULT, LESS, SPACE, ZERO */
#define PAD_FMT_MONTHDAY 0
#define PAD_FMT_HMS 0
#define PAD_FMT_CENTURY 0
#define PAD_FMT_SHORTYEAR 0
#define PAD_FMT_MONTH 0
#define PAD_FMT_WEEKOFYEAR 0
#define PAD_FMT_DAYOFMONTH 0
{ "%02d", "%d", "%2d", "%02d" },
#define PAD_FMT_SDAYOFMONTH 1
#define PAD_FMT_SHMS 1
{ "%2d", "%d", "%2d", "%02d" },
#define PAD_FMT_DAYOFYEAR 2
{ "%03d", "%d", "%3d", "%03d" },
#define PAD_FMT_YEAR 3
{ "%04d", "%d", "%4d", "%04d" }
};
size_t
strftime_l(char * __restrict s, size_t maxsize, const char * __restrict format,
const struct tm * __restrict t, locale_t loc)
{
char * p;
int warn;
FIX_LOCALE(loc);
tzset();
warn = IN_NONE;
p = _fmt(((format == NULL) ? "%c" : format), t, s, s + maxsize, &warn, loc);
#ifndef NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
if (warn != IN_NONE && getenv(YEAR_2000_NAME) != NULL) {
(void) fprintf_l(stderr, loc, "\n");
if (format == NULL)
(void) fputs("NULL strftime format ", stderr);
else (void) fprintf_l(stderr, loc, "strftime format \"%s\" ",
format);
(void) fputs("yields only two digits of years in ", stderr);
if (warn == IN_SOME)
(void) fputs("some locales", stderr);
else if (warn == IN_THIS)
(void) fputs("the current locale", stderr);
else (void) fputs("all locales", stderr);
(void) fputs("\n", stderr);
}
#endif /* !defined NO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU */
if (p == s + maxsize)
return (0);
*p = '\0';
return p - s;
}
size_t
strftime(char * __restrict s, size_t maxsize, const char * __restrict format,
const struct tm * __restrict t)
{
return strftime_l(s, maxsize, format, t, __get_locale());
}
static char *
_fmt(const char *format, const struct tm * const t, char *pt,
const char * const ptlim, int *warnp, locale_t loc)
{
int Ealternative, Oalternative, PadIndex;
struct lc_time_T *tptr = __get_current_time_locale(loc);
for ( ; *format; ++format) {
if (*format == '%') {
Ealternative = 0;
Oalternative = 0;
PadIndex = PAD_DEFAULT;
label:
switch (*++format) {
case '\0':
--format;
break;
case 'A':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : tptr->weekday[t->tm_wday],
pt, ptlim);
continue;
case 'a':
pt = _add((t->tm_wday < 0 ||
t->tm_wday >= DAYSPERWEEK) ?
"?" : tptr->wday[t->tm_wday],
pt, ptlim);
continue;
case 'B':
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : (Oalternative ? tptr->alt_month :
tptr->month)[t->tm_mon],
pt, ptlim);
continue;
case 'b':
case 'h':
pt = _add((t->tm_mon < 0 ||
t->tm_mon >= MONSPERYEAR) ?
"?" : tptr->mon[t->tm_mon],
pt, ptlim);
continue;
case 'C':
/*
* %C used to do a...
* _fmt("%a %b %e %X %Y", t);
* ...whereas now POSIX 1003.2 calls for
* something completely different.
* (ado, 1993-05-24)
*/
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 0,
pt, ptlim, loc);
continue;
case 'c':
{
int warn2 = IN_SOME;
pt = _fmt(tptr->c_fmt, t, pt, ptlim, &warn2, loc);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'D':
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp, loc);
continue;
case 'd':
pt = _conv(t->tm_mday,
fmt_padding[PAD_FMT_DAYOFMONTH][PadIndex],
pt, ptlim, loc);
continue;
case 'E':
if (Ealternative || Oalternative)
break;
Ealternative++;
goto label;
case 'O':
/*
* C99 locale modifiers.
* The sequences
* %Ec %EC %Ex %EX %Ey %EY
* %Od %oe %OH %OI %Om %OM
* %OS %Ou %OU %OV %Ow %OW %Oy
* are supposed to provide alternate
* representations.
*
* FreeBSD extension
* %OB
*/
if (Ealternative || Oalternative)
break;
Oalternative++;
goto label;
case 'e':
pt = _conv(t->tm_mday,
fmt_padding[PAD_FMT_SDAYOFMONTH][PadIndex],
pt, ptlim, loc);
continue;
case 'F':
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp, loc);
continue;
case 'H':
pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_HMS][PadIndex],
pt, ptlim, loc);
continue;
case 'I':
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
fmt_padding[PAD_FMT_HMS][PadIndex],
pt, ptlim, loc);
continue;
case 'j':
pt = _conv(t->tm_yday + 1,
fmt_padding[PAD_FMT_DAYOFYEAR][PadIndex],
pt, ptlim, loc);
continue;
case 'k':
/*
* This used to be...
* _conv(t->tm_hour % 12 ?
* t->tm_hour % 12 : 12, 2, ' ');
* ...and has been changed to the below to
* match SunOS 4.1.1 and Arnold Robbins'
* strftime version 3.0. That is, "%k" and
* "%l" have been swapped.
* (ado, 1993-05-24)
*/
pt = _conv(t->tm_hour, fmt_padding[PAD_FMT_SHMS][PadIndex],
pt, ptlim, loc);
continue;
#ifdef KITCHEN_SINK
case 'K':
/*
** After all this time, still unclaimed!
*/
pt = _add("kitchen sink", pt, ptlim);
continue;
#endif /* defined KITCHEN_SINK */
case 'l':
/*
* This used to be...
* _conv(t->tm_hour, 2, ' ');
* ...and has been changed to the below to
* match SunOS 4.1.1 and Arnold Robbin's
* strftime version 3.0. That is, "%k" and
* "%l" have been swapped.
* (ado, 1993-05-24)
*/
pt = _conv((t->tm_hour % 12) ?
(t->tm_hour % 12) : 12,
fmt_padding[PAD_FMT_SHMS][PadIndex],
pt, ptlim, loc);
continue;
case 'M':
pt = _conv(t->tm_min, fmt_padding[PAD_FMT_HMS][PadIndex],
pt, ptlim, loc);
continue;
case 'm':
pt = _conv(t->tm_mon + 1,
fmt_padding[PAD_FMT_MONTH][PadIndex],
pt, ptlim, loc);
continue;
case 'n':
pt = _add("\n", pt, ptlim);
continue;
case 'p':
pt = _add((t->tm_hour >= (HOURSPERDAY / 2)) ?
tptr->pm : tptr->am,
pt, ptlim);
continue;
case 'R':
pt = _fmt("%H:%M", t, pt, ptlim, warnp, loc);
continue;
case 'r':
pt = _fmt(tptr->ampm_fmt, t, pt, ptlim,
warnp, loc);
continue;
case 'S':
pt = _conv(t->tm_sec, fmt_padding[PAD_FMT_HMS][PadIndex],
pt, ptlim, loc);
continue;
case 's':
{
struct tm tm;
char buf[INT_STRLEN_MAXIMUM(
time_t) + 1];
time_t mkt;
tm = *t;
mkt = mktime(&tm);
if (TYPE_SIGNED(time_t))
(void) sprintf_l(buf, loc, "%ld",
(long) mkt);
else (void) sprintf_l(buf, loc, "%lu",
(unsigned long) mkt);
pt = _add(buf, pt, ptlim);
}
continue;
case 'T':
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp, loc);
continue;
case 't':
pt = _add("\t", pt, ptlim);
continue;
case 'U':
pt = _conv((t->tm_yday + DAYSPERWEEK -
t->tm_wday) / DAYSPERWEEK,
fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
pt, ptlim, loc);
continue;
case 'u':
/*
* From Arnold Robbins' strftime version 3.0:
* "ISO 8601: Weekday as a decimal number
* [1 (Monday) - 7]"
* (ado, 1993-05-24)
*/
pt = _conv((t->tm_wday == 0) ?
DAYSPERWEEK : t->tm_wday,
"%d", pt, ptlim, loc);
continue;
case 'V': /* ISO 8601 week number */
case 'G': /* ISO 8601 year (four digits) */
case 'g': /* ISO 8601 year (two digits) */
/*
* From Arnold Robbins' strftime version 3.0: "the week number of the
* year (the first Monday as the first day of week 1) as a decimal number
* (01-53)."
* (ado, 1993-05-24)
*
* From "http://www.ft.uni-erlangen.de/~mskuhn/iso-time.html" by Markus Kuhn:
* "Week 01 of a year is per definition the first week which has the
* Thursday in this year, which is equivalent to the week which contains
* the fourth day of January. In other words, the first week of a new year
* is the week which has the majority of its days in the new year. Week 01
* might also contain days from the previous year and the week before week
* 01 of a year is the last week (52 or 53) of the previous year even if
* it contains days from the new year. A week starts with Monday (day 1)
* and ends with Sunday (day 7). For example, the first week of the year
* 1997 lasts from 1996-12-30 to 1997-01-05..."
* (ado, 1996-01-02)
*/
{
int year;
int base;
int yday;
int wday;
int w;
year = t->tm_year;
base = TM_YEAR_BASE;
yday = t->tm_yday;
wday = t->tm_wday;
for ( ; ; ) {
int len;
int bot;
int top;
len = isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
/*
* What yday (-3 ... 3) does
* the ISO year begin on?
*/
bot = ((yday + 11 - wday) %
DAYSPERWEEK) - 3;
/*
* What yday does the NEXT
* ISO year begin on?
*/
top = bot -
(len % DAYSPERWEEK);
if (top < -3)
top += DAYSPERWEEK;
top += len;
if (yday >= top) {
++base;
w = 1;
break;
}
if (yday >= bot) {
w = 1 + ((yday - bot) /
DAYSPERWEEK);
break;
}
--base;
yday += isleap_sum(year, base) ?
DAYSPERLYEAR :
DAYSPERNYEAR;
}
#ifdef XPG4_1994_04_09
if ((w == 52 &&
t->tm_mon == TM_JANUARY) ||
(w == 1 &&
t->tm_mon == TM_DECEMBER))
w = 53;
#endif /* defined XPG4_1994_04_09 */
if (*format == 'V')
pt = _conv(w, fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
pt, ptlim, loc);
else if (*format == 'g') {
*warnp = IN_ALL;
pt = _yconv(year, base, 0, 1,
pt, ptlim, loc);
} else pt = _yconv(year, base, 1, 1,
pt, ptlim, loc);
}
continue;
case 'v':
/*
* From Arnold Robbins' strftime version 3.0:
* "date as dd-bbb-YYYY"
* (ado, 1993-05-24)
*/
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp, loc);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
(t->tm_wday ?
(t->tm_wday - 1) :
(DAYSPERWEEK - 1))) / DAYSPERWEEK,
fmt_padding[PAD_FMT_WEEKOFYEAR][PadIndex],
pt, ptlim, loc);
continue;
case 'w':
pt = _conv(t->tm_wday, "%d", pt, ptlim, loc);
continue;
case 'X':
pt = _fmt(tptr->X_fmt, t, pt, ptlim, warnp, loc);
continue;
case 'x':
{
int warn2 = IN_SOME;
pt = _fmt(tptr->x_fmt, t, pt, ptlim, &warn2, loc);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'y':
*warnp = IN_ALL;
pt = _yconv(t->tm_year, TM_YEAR_BASE, 0, 1,
pt, ptlim, loc);
continue;
case 'Y':
pt = _yconv(t->tm_year, TM_YEAR_BASE, 1, 1,
pt, ptlim, loc);
continue;
case 'Z':
#ifdef TM_ZONE
if (t->TM_ZONE != NULL)
pt = _add(t->TM_ZONE, pt, ptlim);
else
#endif /* defined TM_ZONE */
if (t->tm_isdst >= 0)
pt = _add(tzname[t->tm_isdst != 0],
pt, ptlim);
/*
* C99 says that %Z must be replaced by the
* empty string if the time zone is not
* determinable.
*/
continue;
case 'z':
{
int diff;
char const * sign;
if (t->tm_isdst < 0)
continue;
#ifdef TM_GMTOFF
diff = t->TM_GMTOFF;
#else /* !defined TM_GMTOFF */
/*
* C99 says that the UTC offset must
* be computed by looking only at
* tm_isdst. This requirement is
* incorrect, since it means the code
* must rely on magic (in this case
* altzone and timezone), and the
* magic might not have the correct
* offset. Doing things correctly is
* tricky and requires disobeying C99;
* see GNU C strftime for details.
* For now, punt and conform to the
* standard, even though it's incorrect.
*
* C99 says that %z must be replaced by the
* empty string if the time zone is not
* determinable, so output nothing if the
* appropriate variables are not available.
*/
if (t->tm_isdst == 0)
#ifdef USG_COMPAT
diff = -timezone;
#else /* !defined USG_COMPAT */
continue;
#endif /* !defined USG_COMPAT */
else
#ifdef ALTZONE
diff = -altzone;
#else /* !defined ALTZONE */
continue;
#endif /* !defined ALTZONE */
#endif /* !defined TM_GMTOFF */
if (diff < 0) {
sign = "-";
diff = -diff;
} else
sign = "+";
pt = _add(sign, pt, ptlim);
diff /= SECSPERMIN;
diff = (diff / MINSPERHOUR) * 100 +
(diff % MINSPERHOUR);
pt = _conv(diff,
fmt_padding[PAD_FMT_YEAR][PadIndex],
pt, ptlim, loc);
}
continue;
case '+':
pt = _fmt(tptr->date_fmt, t, pt, ptlim,
warnp, loc);
continue;
case '-':
if (PadIndex != PAD_DEFAULT)
break;
PadIndex = PAD_LESS;
goto label;
case '_':
if (PadIndex != PAD_DEFAULT)
break;
PadIndex = PAD_SPACE;
goto label;
case '0':
if (PadIndex != PAD_DEFAULT)
break;
PadIndex = PAD_ZERO;
goto label;
case '%':
/*
* X311J/88-090 (4.12.3.5): if conversion char is
* undefined, behavior is undefined. Print out the
* character itself as printf(3) also does.
*/
default:
break;
}
}
if (pt == ptlim)
break;
*pt++ = *format;
}
return (pt);
}
static char *
_conv(const int n, const char * const format, char * const pt,
const char * const ptlim, locale_t loc)
{
char buf[INT_STRLEN_MAXIMUM(int) + 1];
(void) sprintf_l(buf, loc, format, n);
return _add(buf, pt, ptlim);
}
static char *
_add(const char *str, char *pt, const char * const ptlim)
{
while (pt < ptlim && (*pt = *str++) != '\0')
++pt;
return (pt);
}
/*
* POSIX and the C Standard are unclear or inconsistent about
* what %C and %y do if the year is negative or exceeds 9999.
* Use the convention that %C concatenated with %y yields the
* same output as %Y, and that %Y contains at least 4 bytes,
* with more only if necessary.
*/
static char *
_yconv(const int a, const int b, const int convert_top, const int convert_yy,
char *pt, const char * const ptlim, locale_t loc)
{
register int lead;
register int trail;
#define DIVISOR 100
trail = a % DIVISOR + b % DIVISOR;
lead = a / DIVISOR + b / DIVISOR + trail / DIVISOR;
trail %= DIVISOR;
if (trail < 0 && lead > 0) {
trail += DIVISOR;
--lead;
} else if (lead < 0 && trail > 0) {
trail -= DIVISOR;
++lead;
}
if (convert_top) {
if (lead == 0 && trail < 0)
pt = _add("-0", pt, ptlim);
else pt = _conv(lead, "%02d", pt, ptlim, loc);
}
if (convert_yy)
pt = _conv(((trail < 0) ? -trail : trail), "%02d", pt,
ptlim, loc);
return (pt);
}
diff --git a/lib/libc/stdtime/time32.c b/lib/libc/stdtime/time32.c
index 1be9e9dec74c..5fb7c95c22de 100644
--- a/lib/libc/stdtime/time32.c
+++ b/lib/libc/stdtime/time32.c
@@ -1,98 +1,97 @@
/*-
* Copyright (c) 2001 FreeBSD Inc.
* All rights reserved.
*
* These routines are for converting time_t to fixed-bit representations
* for use in protocols or storage. When converting time to a larger
* representation of time_t these routines are expected to assume temporal
* locality and use the 50-year rule to properly set the msb bits. XXX
*
* Redistribution and use under the terms of the COPYRIGHT file at the
* base of the source tree.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <timeconv.h>
/*
* Convert a 32 bit representation of time_t into time_t. XXX needs to
* implement the 50-year rule to handle post-2038 conversions.
*/
time_t
_time32_to_time(__int32_t t32)
{
return((time_t)t32);
}
/*
* Convert time_t to a 32 bit representation. If time_t is 64 bits we can
* simply chop it down. The resulting 32 bit representation can be
* converted back to a temporally local 64 bit time_t using time32_to_time.
*/
__int32_t
_time_to_time32(time_t t)
{
return((__int32_t)t);
}
/*
* Convert a 64 bit representation of time_t into time_t. If time_t is
* represented as 32 bits we can simply chop it and not support times
* past 2038.
*/
time_t
_time64_to_time(__int64_t t64)
{
return((time_t)t64);
}
/*
* Convert time_t to a 64 bit representation. If time_t is represented
* as 32 bits we simply sign-extend and do not support times past 2038.
*/
__int64_t
_time_to_time64(time_t t)
{
return((__int64_t)t);
}
/*
* Convert to/from 'long'. Depending on the sizeof(long) this may or
* may not require using the 50-year rule.
*/
long
_time_to_long(time_t t)
{
if (sizeof(long) == sizeof(__int64_t))
return(_time_to_time64(t));
return((long)t);
}
time_t
_long_to_time(long tlong)
{
if (sizeof(long) == sizeof(__int32_t))
return(_time32_to_time(tlong));
return((time_t)tlong);
}
/*
* Convert to/from 'int'. Depending on the sizeof(int) this may or
* may not require using the 50-year rule.
*/
int
_time_to_int(time_t t)
{
if (sizeof(int) == sizeof(__int64_t))
return(_time_to_time64(t));
return((int)t);
}
time_t
_int_to_time(int tint)
{
if (sizeof(int) == sizeof(__int32_t))
return(_time32_to_time(tint));
return((time_t)tint);
}
diff --git a/lib/libc/stdtime/timelocal.c b/lib/libc/stdtime/timelocal.c
index 93b9868d0319..680270e0f9b1 100644
--- a/lib/libc/stdtime/timelocal.c
+++ b/lib/libc/stdtime/timelocal.c
@@ -1,154 +1,153 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2001 Alexey Zelkin <phantom@FreeBSD.org>
* Copyright (c) 1997 FreeBSD Inc.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stddef.h>
#include "ldpart.h"
#include "timelocal.h"
struct xlocale_time {
struct xlocale_component header;
char *buffer;
struct lc_time_T locale;
};
struct xlocale_time __xlocale_global_time;
#define LCTIME_SIZE (sizeof(struct lc_time_T) / sizeof(char *))
static const struct lc_time_T _C_time_locale = {
{
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
}, {
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
}, {
"Sun", "Mon", "Tue", "Wed",
"Thu", "Fri", "Sat"
}, {
"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"
},
/* X_fmt */
"%H:%M:%S",
/*
* x_fmt
* Since the C language standard calls for
* "date, using locale's date format," anything goes.
* Using just numbers (as here) makes Quakers happier;
* it's also compatible with SVR4.
*/
"%m/%d/%y",
/*
* c_fmt
*/
"%a %b %e %H:%M:%S %Y",
/* am */
"AM",
/* pm */
"PM",
/* date_fmt */
"%a %b %e %H:%M:%S %Z %Y",
/* alt_month
* Standalone months forms for %OB
*/
{
"January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December"
},
/* md_order
* Month / day order in dates
*/
"md",
/* ampm_fmt
* To determine 12-hour clock format time (empty, if N/A)
*/
"%I:%M:%S %p"
};
static void destruct_time(void *v)
{
struct xlocale_time *l = v;
if (l->buffer)
free(l->buffer);
free(l);
}
#include <stdio.h>
struct lc_time_T *
__get_current_time_locale(locale_t loc)
{
return (loc->using_time_locale
? &((struct xlocale_time *)loc->components[XLC_TIME])->locale
: (struct lc_time_T *)&_C_time_locale);
}
static int
time_load_locale(struct xlocale_time *l, int *using_locale, const char *name)
{
struct lc_time_T *time_locale = &l->locale;
return (__part_load_locale(name, using_locale,
&l->buffer, "LC_TIME",
LCTIME_SIZE, LCTIME_SIZE,
(const char **)time_locale));
}
int
__time_load_locale(const char *name)
{
return time_load_locale(&__xlocale_global_time,
&__xlocale_global_locale.using_time_locale, name);
}
void* __time_load(const char* name, locale_t loc)
{
struct xlocale_time *new = calloc(sizeof(struct xlocale_time), 1);
new->header.header.destructor = destruct_time;
if (time_load_locale(new, &loc->using_time_locale, name) == _LDP_ERROR)
{
xlocale_release(new);
return NULL;
}
return new;
}
diff --git a/lib/libc/string/bcmp.c b/lib/libc/string/bcmp.c
index 0a7c6f0948a6..25aebcddbc96 100644
--- a/lib/libc/string/bcmp.c
+++ b/lib/libc/string/bcmp.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bcmp.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <strings.h>
/*
* bcmp -- vax cmpc3 instruction
*/
int
bcmp(const void *b1, const void *b2, size_t length)
{
char *p1, *p2;
if (length == 0)
return (0);
p1 = (char *)b1;
p2 = (char *)b2;
do
if (*p1++ != *p2++)
return (1);
while (--length);
return (0);
}
diff --git a/lib/libc/string/bcopy.c b/lib/libc/string/bcopy.c
index 4328542d2d54..ba49c59383b1 100644
--- a/lib/libc/string/bcopy.c
+++ b/lib/libc/string/bcopy.c
@@ -1,135 +1,134 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)bcopy.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
typedef intptr_t word; /* "word" used for optimal copy speed */
#define wsize sizeof(word)
#define wmask (wsize - 1)
/*
* Copy a block of memory, handling overlap.
* This is the routine that actually implements
* (the portable versions of) bcopy, memcpy, and memmove.
*/
#if defined(MEMCOPY) || defined(MEMMOVE)
#include <string.h>
void *
#ifdef MEMCOPY
memcpy
#else
memmove
#endif
(void *dst0, const void *src0, size_t length)
#else
#include <strings.h>
void
bcopy(const void *src0, void *dst0, size_t length)
#endif
{
char *dst = dst0;
const char *src = src0;
size_t t;
if (length == 0 || dst == src) /* nothing to do */
goto done;
/*
* Macros: loop-t-times; and loop-t-times, t>0
*/
#define TLOOP(s) if (t) TLOOP1(s)
#define TLOOP1(s) do { s; } while (--t)
if ((unsigned long)dst < (unsigned long)src) {
/*
* Copy forward.
*/
t = (uintptr_t)src; /* only need low bits */
if ((t | (uintptr_t)dst) & wmask) {
/*
* Try to align operands. This cannot be done
* unless the low bits match.
*/
if ((t ^ (uintptr_t)dst) & wmask || length < wsize)
t = length;
else
t = wsize - (t & wmask);
length -= t;
TLOOP1(*dst++ = *src++);
}
/*
* Copy whole words, then mop up any trailing bytes.
*/
t = length / wsize;
TLOOP(*(word *)(void *)dst = *(const word *)(const void *)src;
src += wsize; dst += wsize);
t = length & wmask;
TLOOP(*dst++ = *src++);
} else {
/*
* Copy backwards. Otherwise essentially the same.
* Alignment works as before, except that it takes
* (t&wmask) bytes to align, not wsize-(t&wmask).
*/
src += length;
dst += length;
t = (uintptr_t)src;
if ((t | (uintptr_t)dst) & wmask) {
if ((t ^ (uintptr_t)dst) & wmask || length <= wsize)
t = length;
else
t &= wmask;
length -= t;
TLOOP1(*--dst = *--src);
}
t = length / wsize;
TLOOP(src -= wsize; dst -= wsize;
*(word *)(void *)dst = *(const word *)(const void *)src);
t = length & wmask;
TLOOP(*--dst = *--src);
}
done:
#if defined(MEMCOPY) || defined(MEMMOVE)
return (dst0);
#else
return;
#endif
}
diff --git a/lib/libc/string/bzero.c b/lib/libc/string/bzero.c
index fe149def7930..7bc2b3a7008a 100644
--- a/lib/libc/string/bzero.c
+++ b/lib/libc/string/bzero.c
@@ -1,3 +1,2 @@
-#include <sys/cdefs.h>
#define BZERO
#include "memset.c"
diff --git a/lib/libc/string/ffs.c b/lib/libc/string/ffs.c
index b318c33f641b..93a87780dc5c 100644
--- a/lib/libc/string/ffs.c
+++ b/lib/libc/string/ffs.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2023 The FreeBSD Foundation
*
* Portions of this software were developed by Robert Clausecker
* <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)ffs.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <strings.h>
/*
* Find First Set bit
*/
int
ffs(int mask)
{
return (mask == 0 ? 0 : __builtin_ctz(mask) + 1);
}
diff --git a/lib/libc/string/ffsl.c b/lib/libc/string/ffsl.c
index 237e62617315..c3a87a902526 100644
--- a/lib/libc/string/ffsl.c
+++ b/lib/libc/string/ffsl.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2023 The FreeBSD Foundation
*
* Portions of this software were developed by Robert Clausecker
* <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <strings.h>
/*
* Find First Set bit
*/
int
ffsl(long mask)
{
return (mask == 0 ? 0 : __builtin_ctzl(mask) + 1);
}
diff --git a/lib/libc/string/ffsll.c b/lib/libc/string/ffsll.c
index 4fb5ccc4ef7c..5c7abc1f7a23 100644
--- a/lib/libc/string/ffsll.c
+++ b/lib/libc/string/ffsll.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2023 The FreeBSD Foundation
*
* Portions of this software were developed by Robert Clausecker
* <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <strings.h>
/*
* Find First Set bit
*/
int
ffsll(long long mask)
{
return (mask == 0 ? 0 : __builtin_ctzll(mask) + 1);
}
diff --git a/lib/libc/string/fls.c b/lib/libc/string/fls.c
index 554b8dc4b413..ac5fb7738722 100644
--- a/lib/libc/string/fls.c
+++ b/lib/libc/string/fls.c
@@ -1,47 +1,46 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2023 The FreeBSD Foundation
*
* Portions of this software were developed by Robert Clausecker
* <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <strings.h>
/*
* Find Last Set bit
*/
int
fls(int mask)
{
return (mask == 0 ? 0 : CHAR_BIT * sizeof(mask) - __builtin_clz(mask));
}
diff --git a/lib/libc/string/flsl.c b/lib/libc/string/flsl.c
index 6b881bc39b9e..d88c8dfcdc63 100644
--- a/lib/libc/string/flsl.c
+++ b/lib/libc/string/flsl.c
@@ -1,48 +1,47 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2023 The FreeBSD Foundation
*
* Portions of this software were developed by Robert Clausecker
* <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <strings.h>
/*
* Find Last Set bit
*/
int
flsl(long mask)
{
return (mask == 0 ? 0 : CHAR_BIT * sizeof(mask) - __builtin_clzl(mask));
}
diff --git a/lib/libc/string/flsll.c b/lib/libc/string/flsll.c
index 68d6d52bee4b..635ebacddf18 100644
--- a/lib/libc/string/flsll.c
+++ b/lib/libc/string/flsll.c
@@ -1,47 +1,46 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
* Copyright (c) 2023 The FreeBSD Foundation
*
* Portions of this software were developed by Robert Clausecker
* <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <strings.h>
/*
* Find Last Set bit
*/
int
flsll(long long mask)
{
return (mask == 0 ? 0 : CHAR_BIT * sizeof(mask) - __builtin_clzll(mask));
}
diff --git a/lib/libc/string/memccpy.c b/lib/libc/string/memccpy.c
index a81e8936e46a..fd080d4293f4 100644
--- a/lib/libc/string/memccpy.c
+++ b/lib/libc/string/memccpy.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)memccpy.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
void *
memccpy(void *t, const void *f, int c, size_t n)
{
if (n) {
unsigned char *tp = t;
const unsigned char *fp = f;
unsigned char uc = c;
do {
if ((*tp++ = *fp++) == uc)
return (tp);
} while (--n != 0);
}
return (0);
}
diff --git a/lib/libc/string/memchr.c b/lib/libc/string/memchr.c
index 10df015c5b64..367eac5108c1 100644
--- a/lib/libc/string/memchr.c
+++ b/lib/libc/string/memchr.c
@@ -1,57 +1,56 @@
/*-
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2005-2014 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#define SS (sizeof(size_t))
#define ALIGN (sizeof(size_t) - 1)
#define ONES ((size_t)-1 / UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX / 2 + 1))
#define HASZERO(x) (((x)-ONES) & ~(x)&HIGHS)
void *
memchr(const void *src, int c, size_t n)
{
const unsigned char *s = src;
c = (unsigned char)c;
#ifdef __GNUC__
for (; ((uintptr_t)s & ALIGN) && n && *s != c; s++, n--)
;
if (n && *s != c) {
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
size_t k = ONES * c;
for (w = (const void *)s; n >= SS && !HASZERO(*w ^ k);
w++, n -= SS)
;
s = (const void *)w;
}
#endif
for (; n && *s != c; s++, n--)
;
return n ? (void *)s : 0;
}
diff --git a/lib/libc/string/memcmp.c b/lib/libc/string/memcmp.c
index 1a72e376c37a..a3e3fe5604d5 100644
--- a/lib/libc/string/memcmp.c
+++ b/lib/libc/string/memcmp.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)memcmp.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
/*
* Compare memory regions.
*/
int
memcmp(const void *s1, const void *s2, size_t n)
{
if (n != 0) {
const unsigned char *p1 = s1, *p2 = s2;
do {
if (*p1++ != *p2++)
return (*--p1 - *--p2);
} while (--n != 0);
}
return (0);
}
diff --git a/lib/libc/string/memcpy.c b/lib/libc/string/memcpy.c
index 886b7cb2c654..ee1150473aa9 100644
--- a/lib/libc/string/memcpy.c
+++ b/lib/libc/string/memcpy.c
@@ -1,3 +1,2 @@
-#include <sys/cdefs.h>
#define MEMCOPY
#include "bcopy.c"
diff --git a/lib/libc/string/memmem.c b/lib/libc/string/memmem.c
index 11e1540bf1fc..4a244b5964ce 100644
--- a/lib/libc/string/memmem.c
+++ b/lib/libc/string/memmem.c
@@ -1,212 +1,211 @@
/*-
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2005-2014 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/cdefs.h>
#include <stdint.h>
#include <string.h>
static char *
twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1];
for (h += 2, k -= 2; k; k--, hw = hw << 8 | *h++)
if (hw == nw)
return (char *)h - 2;
return hw == nw ? (char *)h - 2 : 0;
}
static char *
threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8;
uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8;
for (h += 3, k -= 3; k; k--, hw = (hw | *h++) << 8)
if (hw == nw)
return (char *)h - 3;
return hw == nw ? (char *)h - 3 : 0;
}
static char *
fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3];
uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3];
for (h += 4, k -= 4; k; k--, hw = hw << 8 | *h++)
if (hw == nw)
return (char *)h - 4;
return hw == nw ? (char *)h - 4 : 0;
}
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define BITOP(a, b, op) \
((a)[(size_t)(b) / (8 * sizeof *(a))] op \
(size_t)1 << ((size_t)(b) % (8 * sizeof *(a))))
/*
* Two Way string search algorithm, with a bad shift table applied to the last
* byte of the window. A bit array marks which entries in the shift table are
* initialized to avoid fully initializing a 1kb/2kb table.
*
* Reference: CROCHEMORE M., PERRIN D., 1991, Two-way string-matching,
* Journal of the ACM 38(3):651-675
*/
static char *
twoway_memmem(const unsigned char *h, const unsigned char *z,
const unsigned char *n, size_t l)
{
size_t i, ip, jp, k, p, ms, p0, mem, mem0;
size_t byteset[32 / sizeof(size_t)] = { 0 };
size_t shift[256];
/* Computing length of needle and fill shift table */
for (i = 0; i < l; i++)
BITOP(byteset, n[i], |=), shift[n[i]] = i + 1;
/* Compute maximal suffix */
ip = -1;
jp = 0;
k = p = 1;
while (jp + k < l) {
if (n[ip + k] == n[jp + k]) {
if (k == p) {
jp += p;
k = 1;
} else
k++;
} else if (n[ip + k] > n[jp + k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
ms = ip;
p0 = p;
/* And with the opposite comparison */
ip = -1;
jp = 0;
k = p = 1;
while (jp + k < l) {
if (n[ip + k] == n[jp + k]) {
if (k == p) {
jp += p;
k = 1;
} else
k++;
} else if (n[ip + k] < n[jp + k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
if (ip + 1 > ms + 1)
ms = ip;
else
p = p0;
/* Periodic needle? */
if (memcmp(n, n + p, ms + 1)) {
mem0 = 0;
p = MAX(ms, l - ms - 1) + 1;
} else
mem0 = l - p;
mem = 0;
/* Search loop */
for (;;) {
/* If remainder of haystack is shorter than needle, done */
if (z - h < l)
return 0;
/* Check last byte first; advance by shift on mismatch */
if (BITOP(byteset, h[l - 1], &)) {
k = l - shift[h[l - 1]];
if (k) {
if (k < mem)
k = mem;
h += k;
mem = 0;
continue;
}
} else {
h += l;
mem = 0;
continue;
}
/* Compare right half */
for (k = MAX(ms + 1, mem); k < l && n[k] == h[k]; k++)
;
if (k < l) {
h += k - ms;
mem = 0;
continue;
}
/* Compare left half */
for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--)
;
if (k <= mem)
return (char *)h;
h += p;
mem = mem0;
}
}
void *
memmem(const void *h0, size_t k, const void *n0, size_t l)
{
const unsigned char *h = h0, *n = n0;
/* Return immediately on empty needle */
if (!l)
return (void *)h;
/* Return immediately when needle is longer than haystack */
if (k < l)
return 0;
/* Use faster algorithms for short needles */
h = memchr(h0, *n, k);
if (!h || l == 1)
return (void *)h;
k -= h - (const unsigned char *)h0;
if (k < l)
return 0;
if (l == 2)
return twobyte_memmem(h, k, n);
if (l == 3)
return threebyte_memmem(h, k, n);
if (l == 4)
return fourbyte_memmem(h, k, n);
return twoway_memmem(h, h + k, n, l);
}
diff --git a/lib/libc/string/memmove.c b/lib/libc/string/memmove.c
index 089a77a892a0..e9bb2c2ed14c 100644
--- a/lib/libc/string/memmove.c
+++ b/lib/libc/string/memmove.c
@@ -1,3 +1,2 @@
-#include <sys/cdefs.h>
#define MEMMOVE
#include "bcopy.c"
diff --git a/lib/libc/string/mempcpy.c b/lib/libc/string/mempcpy.c
index 2c645da97627..619371632922 100644
--- a/lib/libc/string/mempcpy.c
+++ b/lib/libc/string/mempcpy.c
@@ -1,38 +1,37 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 The FreeBSD Foundation
*
* This software was developed by Konstantin Belousov <kib@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <string.h>
void *
mempcpy(void *__restrict dst, const void *__restrict src, size_t len)
{
return ((char *)memcpy(dst, src, len) + len);
}
diff --git a/lib/libc/string/memset.c b/lib/libc/string/memset.c
index eed47014356f..18856f681c57 100644
--- a/lib/libc/string/memset.c
+++ b/lib/libc/string/memset.c
@@ -1,131 +1,130 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Mike Hibler and Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)memset.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
#define wsize sizeof(u_long)
#define wmask (wsize - 1)
#ifdef BZERO
#include <strings.h>
#define RETURN return
#define VAL 0
#define WIDEVAL 0
void
bzero(void *dst0, size_t length)
#else
#include <string.h>
#define RETURN return (dst0)
#define VAL c0
#define WIDEVAL c
void *
memset(void *dst0, int c0, size_t length)
#endif
{
size_t t;
#ifndef BZERO
u_long c;
#endif
u_char *dst;
dst = dst0;
/*
* If not enough words, just fill bytes. A length >= 2 words
* guarantees that at least one of them is `complete' after
* any necessary alignment. For instance:
*
* |-----------|-----------|-----------|
* |00|01|02|03|04|05|06|07|08|09|0A|00|
* ^---------------------^
* dst dst+length-1
*
* but we use a minimum of 3 here since the overhead of the code
* to do word writes is substantial.
*
* TODO: This threshold might not be sensible for 64-bit u_long.
* We should benchmark and revisit this decision.
*/
if (length < 3 * wsize) {
while (length != 0) {
*dst++ = VAL;
--length;
}
RETURN;
}
#ifndef BZERO
if ((c = (u_char)c0) != 0) { /* Fill the word. */
c = (c << 8) | c; /* u_long is 16 bits. */
#if ULONG_MAX > 0xffff
c = (c << 16) | c; /* u_long is 32 bits. */
#endif
#if ULONG_MAX > 0xffffffff
c = (c << 32) | c; /* u_long is 64 bits. */
#endif
}
#endif
/* Align destination by filling in bytes. */
if ((t = (long)dst & wmask) != 0) {
t = wsize - t;
length -= t;
do {
*dst++ = VAL;
} while (--t != 0);
}
/* Fill words. Length was >= 2*words so we know t >= 1 here. */
t = length / wsize;
do {
*(u_long *)(void *)dst = WIDEVAL;
dst += wsize;
} while (--t != 0);
/* Mop up trailing bytes, if any. */
t = length & wmask;
if (t != 0)
do {
*dst++ = VAL;
} while (--t != 0);
RETURN;
}
diff --git a/lib/libc/string/memset_s.c b/lib/libc/string/memset_s.c
index 3c7f76d19d7b..d6da7be8385d 100644
--- a/lib/libc/string/memset_s.c
+++ b/lib/libc/string/memset_s.c
@@ -1,64 +1,63 @@
/*-
* Copyright (c) 2017 Juniper Networks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#include "libc_private.h"
/* ISO/IEC 9899:2011 K.3.7.4.1 */
errno_t
memset_s(void *s, rsize_t smax, int c, rsize_t n)
{
errno_t ret;
rsize_t lim;
unsigned char v;
volatile unsigned char *dst;
ret = EINVAL;
lim = n < smax ? n : smax;
v = (unsigned char)c;
dst = (unsigned char *)s;
if (s == NULL) {
__throw_constraint_handler_s("memset_s : s is NULL", ret);
} else if (smax > RSIZE_MAX) {
__throw_constraint_handler_s("memset_s : smax > RSIZE_MAX",
ret);
} else if (n > RSIZE_MAX) {
__throw_constraint_handler_s("memset_s : n > RSIZE_MAX", ret);
} else {
while (lim > 0)
dst[--lim] = v;
if (n > smax) {
__throw_constraint_handler_s("memset_s : n > smax",
ret);
} else {
ret = 0;
}
}
return (ret);
}
diff --git a/lib/libc/string/stpcpy.c b/lib/libc/string/stpcpy.c
index 02640a68b0ae..37af15ce0538 100644
--- a/lib/libc/string/stpcpy.c
+++ b/lib/libc/string/stpcpy.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1999
* David E. O'Brien
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
char *
stpcpy(char * __restrict to, const char * __restrict from)
{
for (; (*to = *from); ++from, ++to);
return(to);
}
diff --git a/lib/libc/string/stpncpy.c b/lib/libc/string/stpncpy.c
index 46e61c468d99..8c7f14ecf8dd 100644
--- a/lib/libc/string/stpncpy.c
+++ b/lib/libc/string/stpncpy.c
@@ -1,45 +1,44 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <string.h>
char *
stpncpy(char * __restrict dst, const char * __restrict src, size_t n)
{
for (; n--; dst++, src++) {
if (!(*dst = *src)) {
char *ret = dst;
while (n--)
*++dst = '\0';
return (ret);
}
}
return (dst);
}
diff --git a/lib/libc/string/strcasecmp.c b/lib/libc/string/strcasecmp.c
index c959869ad9f0..2147858844f5 100644
--- a/lib/libc/string/strcasecmp.c
+++ b/lib/libc/string/strcasecmp.c
@@ -1,87 +1,86 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1987, 1993
* The Regents of the University of California. All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strcasecmp.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <strings.h>
#include <ctype.h>
#include "xlocale_private.h"
int
strcasecmp_l(const char *s1, const char *s2, locale_t locale)
{
const u_char
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
FIX_LOCALE(locale);
while (tolower_l(*us1, locale) == tolower_l(*us2++, locale))
if (*us1++ == '\0')
return (0);
return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
}
int
strcasecmp(const char *s1, const char *s2)
{
return strcasecmp_l(s1, s2, __get_locale());
}
int
strncasecmp_l(const char *s1, const char *s2, size_t n, locale_t locale)
{
FIX_LOCALE(locale);
if (n != 0) {
const u_char
*us1 = (const u_char *)s1,
*us2 = (const u_char *)s2;
do {
if (tolower_l(*us1, locale) != tolower_l(*us2++, locale))
return (tolower_l(*us1, locale) - tolower_l(*--us2, locale));
if (*us1++ == '\0')
break;
} while (--n != 0);
}
return (0);
}
int
strncasecmp(const char *s1, const char *s2, size_t n)
{
return strncasecmp_l(s1, s2, n, __get_locale());
}
diff --git a/lib/libc/string/strcasestr.c b/lib/libc/string/strcasestr.c
index 591a2d95304b..c1be973f01f4 100644
--- a/lib/libc/string/strcasestr.c
+++ b/lib/libc/string/strcasestr.c
@@ -1,72 +1,71 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <ctype.h>
#include <string.h>
#include "xlocale_private.h"
/*
* Find the first occurrence of find in s, ignore case.
*/
char *
strcasestr_l(const char *s, const char *find, locale_t locale)
{
char c, sc;
size_t len;
FIX_LOCALE(locale);
if ((c = *find++) != 0) {
c = tolower_l((unsigned char)c, locale);
len = strlen(find);
do {
do {
if ((sc = *s++) == 0)
return (NULL);
} while ((char)tolower_l((unsigned char)sc, locale) != c);
} while (strncasecmp_l(s, find, len, locale) != 0);
s--;
}
return ((char *)s);
}
char *
strcasestr(const char *s, const char *find)
{
return strcasestr_l(s, find, __get_locale());
}
diff --git a/lib/libc/string/strcat.c b/lib/libc/string/strcat.c
index 94f851d4a257..53f5743faf93 100644
--- a/lib/libc/string/strcat.c
+++ b/lib/libc/string/strcat.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strcat.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
char *
strcat(char * __restrict s, const char * __restrict append)
{
char *save = s;
for (; *s; ++s);
while ((*s++ = *append++));
return(save);
}
diff --git a/lib/libc/string/strchr.c b/lib/libc/string/strchr.c
index d4e35b07c8c1..8f6f947e9983 100644
--- a/lib/libc/string/strchr.c
+++ b/lib/libc/string/strchr.c
@@ -1,37 +1,36 @@
/*-
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2005-2014 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/cdefs.h>
#include <string.h>
char *__strchrnul(const char *, int);
char *
strchr(const char *s, int c)
{
char *r = __strchrnul(s, c);
return *(unsigned char *)r == (unsigned char)c ? r : NULL;
}
__weak_reference(strchr, index);
diff --git a/lib/libc/string/strchrnul.c b/lib/libc/string/strchrnul.c
index 1841185dc9b6..3a42c0e7c4c5 100644
--- a/lib/libc/string/strchrnul.c
+++ b/lib/libc/string/strchrnul.c
@@ -1,60 +1,59 @@
/*-
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2005-2014 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <stdint.h>
#include <string.h>
#define ALIGN (sizeof(size_t))
#define ONES ((size_t)-1 / UCHAR_MAX)
#define HIGHS (ONES * (UCHAR_MAX / 2 + 1))
#define HASZERO(x) (((x)-ONES) & ~(x)&HIGHS)
char *__strchrnul(const char *, int);
char *
__strchrnul(const char *s, int c)
{
c = (unsigned char)c;
if (!c)
return (char *)s + strlen(s);
#ifdef __GNUC__
typedef size_t __attribute__((__may_alias__)) word;
const word *w;
for (; (uintptr_t)s % ALIGN; s++)
if (!*s || *(unsigned char *)s == c)
return (char *)s;
size_t k = ONES * c;
for (w = (void *)s; !HASZERO(*w) && !HASZERO(*w ^ k); w++)
;
s = (void *)w;
#endif
for (; *s && *(unsigned char *)s != c; s++)
;
return (char *)s;
}
__weak_reference(__strchrnul, strchrnul);
diff --git a/lib/libc/string/strcmp.c b/lib/libc/string/strcmp.c
index 9d590cc5a4f0..ce4437c1fb54 100644
--- a/lib/libc/string/strcmp.c
+++ b/lib/libc/string/strcmp.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strcmp.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
/*
* Compare strings.
*/
int
strcmp(const char *s1, const char *s2)
{
while (*s1 == *s2++)
if (*s1++ == '\0')
return (0);
return (*(const unsigned char *)s1 - *(const unsigned char *)(s2 - 1));
}
diff --git a/lib/libc/string/strcoll.c b/lib/libc/string/strcoll.c
index a682f352320f..77566f0c7cd7 100644
--- a/lib/libc/string/strcoll.c
+++ b/lib/libc/string/strcoll.c
@@ -1,118 +1,117 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <wchar.h>
#include "collate.h"
/*
* In order to properly handle multibyte locales, its easiest to just
* convert to wide characters and then use wcscoll. However if an
* error occurs, we gracefully fall back to simple strcmp. Caller
* should check errno.
*/
int
strcoll_l(const char *s, const char *s2, locale_t locale)
{
int ret;
wchar_t *t1 = NULL, *t2 = NULL;
wchar_t *w1 = NULL, *w2 = NULL;
const char *cs1, *cs2;
mbstate_t mbs1;
mbstate_t mbs2;
size_t sz1, sz2;
memset(&mbs1, 0, sizeof (mbstate_t));
memset(&mbs2, 0, sizeof (mbstate_t));
/*
* The mbsrtowcs_l function can set the src pointer to null upon
* failure, so it should act on a copy to avoid:
* - sending null pointer to strcmp
* - having strcoll/strcoll_l change *s or *s2 to null
*/
cs1 = s;
cs2 = s2;
FIX_LOCALE(locale);
struct xlocale_collate *table =
(struct xlocale_collate*)locale->components[XLC_COLLATE];
if (table->__collate_load_error)
goto error;
sz1 = strlen(s) + 1;
sz2 = strlen(s2) + 1;
/*
* Simple assumption: conversion to wide format is strictly
* reducing, i.e. a single byte (or multibyte character)
* cannot result in multiple wide characters.
*/
if ((t1 = malloc(sz1 * sizeof (wchar_t))) == NULL)
goto error;
w1 = t1;
if ((t2 = malloc(sz2 * sizeof (wchar_t))) == NULL)
goto error;
w2 = t2;
if ((mbsrtowcs_l(w1, &cs1, sz1, &mbs1, locale)) == (size_t)-1)
goto error;
if ((mbsrtowcs_l(w2, &cs2, sz2, &mbs2, locale)) == (size_t)-1)
goto error;
ret = wcscoll_l(w1, w2, locale);
free(t1);
free(t2);
return (ret);
error:
free(t1);
free(t2);
return (strcmp(s, s2));
}
int
strcoll(const char *s, const char *s2)
{
return strcoll_l(s, s2, __get_locale());
}
diff --git a/lib/libc/string/strcpy.c b/lib/libc/string/strcpy.c
index 5b0ca98fb8b5..d6f76d8b1368 100644
--- a/lib/libc/string/strcpy.c
+++ b/lib/libc/string/strcpy.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
#ifdef WEAK_STRCPY
__weak_reference(__strcpy, strcpy);
#endif
char *
#ifdef WEAK_STRCPY
__strcpy
#else
strcpy
#endif
(char * __restrict to, const char * __restrict from)
{
char *save = to;
for (; (*to = *from); ++from, ++to);
return(save);
}
diff --git a/lib/libc/string/strcspn.c b/lib/libc/string/strcspn.c
index 687a309d01d9..88bf68ff0733 100644
--- a/lib/libc/string/strcspn.c
+++ b/lib/libc/string/strcspn.c
@@ -1,72 +1,71 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
#include <string.h>
#define IDX(c) ((u_char)(c) / LONG_BIT)
#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT))
size_t
strcspn(const char *s, const char *charset)
{
/*
* NB: idx and bit are temporaries whose use causes gcc 3.4.2 to
* generate better code. Without them, gcc gets a little confused.
*/
const char *s1;
u_long bit;
u_long tbl[(UCHAR_MAX + 1) / LONG_BIT];
int idx;
if(*s == '\0')
return (0);
#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */
tbl[0] = 1;
tbl[3] = tbl[2] = tbl[1] = 0;
#else
for (tbl[0] = idx = 1; idx < sizeof(tbl) / sizeof(tbl[0]); idx++)
tbl[idx] = 0;
#endif
for (; *charset != '\0'; charset++) {
idx = IDX(*charset);
bit = BIT(*charset);
tbl[idx] |= bit;
}
for(s1 = s; ; s1++) {
idx = IDX(*s1);
bit = BIT(*s1);
if ((tbl[idx] & bit) != 0)
break;
}
return (s1 - s);
}
diff --git a/lib/libc/string/strdup.c b/lib/libc/string/strdup.c
index 3e6849abe12c..849e5d5971f6 100644
--- a/lib/libc/string/strdup.c
+++ b/lib/libc/string/strdup.c
@@ -1,51 +1,50 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
char *
strdup(const char *str)
{
size_t len;
char *copy;
len = strlen(str) + 1;
if ((copy = malloc(len)) == NULL)
return (NULL);
memcpy(copy, str, len);
return (copy);
}
diff --git a/lib/libc/string/strerror.c b/lib/libc/string/strerror.c
index 673ccbf37ef7..d5f8a5193ac1 100644
--- a/lib/libc/string/strerror.c
+++ b/lib/libc/string/strerror.c
@@ -1,144 +1,143 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#if defined(NLS)
#include <nl_types.h>
#endif
#include <limits.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include "errlst.h"
#include "../locale/xlocale_private.h"
#include "libc_private.h"
/*
* Define buffer big enough to contain delimiter (": ", 2 bytes),
* 64-bit signed integer converted to ASCII decimal (19 bytes) with
* optional leading sign (1 byte), and a trailing NUL.
*/
#define EBUFSIZE (2 + 19 + 1 + 1)
/*
* Doing this by hand instead of linking with stdio(3) avoids bloat for
* statically linked binaries.
*/
static void
errstr(int num, const char *uprefix, char *buf, size_t len)
{
char *t;
unsigned int uerr;
char tmp[EBUFSIZE];
t = tmp + sizeof(tmp);
*--t = '\0';
uerr = (num >= 0) ? num : -num;
do {
*--t = "0123456789"[uerr % 10];
} while (uerr /= 10);
if (num < 0)
*--t = '-';
*--t = ' ';
*--t = ':';
strlcpy(buf, uprefix, len);
strlcat(buf, t, len);
}
static int
strerror_rl(int errnum, char *strerrbuf, size_t buflen, locale_t locale)
{
int retval = 0;
#if defined(NLS)
int saved_errno = errno;
nl_catd catd;
catd = __catopen_l("libc", NL_CAT_LOCALE, locale);
#endif
if (errnum < 0 || errnum >= __hidden_sys_nerr) {
errstr(errnum,
#if defined(NLS)
catgets(catd, 1, 0xffff, __uprefix),
#else
__uprefix,
#endif
strerrbuf, buflen);
retval = EINVAL;
} else {
if (strlcpy(strerrbuf,
#if defined(NLS)
catgets(catd, 1, errnum, __hidden_sys_errlist[errnum]),
#else
__hidden_sys_errlist[errnum],
#endif
buflen) >= buflen)
retval = ERANGE;
}
#if defined(NLS)
catclose(catd);
errno = saved_errno;
#endif
return (retval);
}
int
strerror_r(int errnum, char *strerrbuf, size_t buflen)
{
return (strerror_rl(errnum, strerrbuf, buflen, __get_locale()));
}
char *
strerror_l(int num, locale_t locale)
{
static _Thread_local char ebuf[NL_TEXTMAX];
if (strerror_rl(num, ebuf, sizeof(ebuf), locale) != 0)
errno = EINVAL;
return (ebuf);
}
char *
strerror(int num)
{
static char ebuf[NL_TEXTMAX];
if (strerror_rl(num, ebuf, sizeof(ebuf), __get_locale()) != 0)
errno = EINVAL;
return (ebuf);
}
diff --git a/lib/libc/string/strlcat.c b/lib/libc/string/strlcat.c
index e5040019b29b..bdb302def7b0 100644
--- a/lib/libc/string/strlcat.c
+++ b/lib/libc/string/strlcat.c
@@ -1,56 +1,55 @@
/* $OpenBSD: strlcat.c,v 1.15 2015/03/02 21:41:08 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 <sys/cdefs.h>
#include <sys/types.h>
#include <string.h>
/*
* Appends src to string dst of size dsize (unlike strncat, dsize is the
* full size of dst, not space left). At most dsize-1 characters
* will be copied. Always NUL terminates (unless dsize <= strlen(dst)).
* Returns strlen(src) + MIN(dsize, strlen(initial dst)).
* If retval >= dsize, truncation occurred.
*/
size_t
strlcat(char * __restrict dst, const char * __restrict src, size_t dsize)
{
const char *odst = dst;
const char *osrc = src;
size_t n = dsize;
size_t dlen;
/* Find the end of dst and adjust bytes left but don't go past end. */
while (n-- != 0 && *dst != '\0')
dst++;
dlen = dst - odst;
n = dsize - dlen;
if (n-- == 0)
return(dlen + strlen(src));
while (*src != '\0') {
if (n != 0) {
*dst++ = *src;
n--;
}
src++;
}
*dst = '\0';
return(dlen + (src - osrc)); /* count does not include NUL */
}
diff --git a/lib/libc/string/strlcpy.c b/lib/libc/string/strlcpy.c
index 8c7daa858960..58a42e321f6a 100644
--- a/lib/libc/string/strlcpy.c
+++ b/lib/libc/string/strlcpy.c
@@ -1,51 +1,50 @@
/* $OpenBSD: strlcpy.c,v 1.12 2015/01/15 03:54:12 millert Exp $ */
/*
* Copyright (c) 1998, 2015 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 <sys/cdefs.h>
#include <sys/types.h>
#include <string.h>
/*
* Copy string src to buffer dst of size dsize. At most dsize-1
* chars will be copied. Always NUL terminates (unless dsize == 0).
* Returns strlen(src); if retval >= dsize, truncation occurred.
*/
size_t
strlcpy(char * __restrict dst, const char * __restrict src, size_t dsize)
{
const char *osrc = src;
size_t nleft = dsize;
/* Copy as many bytes as will fit. */
if (nleft != 0) {
while (--nleft != 0) {
if ((*dst++ = *src++) == '\0')
break;
}
}
/* Not enough room in dst, add NUL and traverse rest of src. */
if (nleft == 0) {
if (dsize != 0)
*dst = '\0'; /* NUL-terminate dst */
while (*src++)
;
}
return(src - osrc - 1); /* count does not include NUL */
}
diff --git a/lib/libc/string/strlen.c b/lib/libc/string/strlen.c
index d7c744d6aa60..c33819707dce 100644
--- a/lib/libc/string/strlen.c
+++ b/lib/libc/string/strlen.c
@@ -1,122 +1,121 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009, 2010 Xin LI <delphij@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/limits.h>
#include <sys/types.h>
#include <string.h>
/*
* Portable strlen() for 32-bit and 64-bit systems.
*
* The expression:
*
* ((x - 0x01....01) & ~x & 0x80....80)
*
* would evaluate to a non-zero value iff any of the bytes in the
* original word is zero.
*
* The algorithm above is found on "Hacker's Delight" by
* Henry S. Warren, Jr.
*
* Note: this leaves performance on the table and each architecture
* would be best served with a tailor made routine instead, even if
* using the same trick.
*/
/* Magic numbers for the algorithm */
#if LONG_BIT == 32
static const unsigned long mask01 = 0x01010101;
static const unsigned long mask80 = 0x80808080;
#elif LONG_BIT == 64
static const unsigned long mask01 = 0x0101010101010101;
static const unsigned long mask80 = 0x8080808080808080;
#else
#error Unsupported word size
#endif
#define LONGPTR_MASK (sizeof(long) - 1)
/*
* Helper macro to return string length if we caught the zero
* byte.
*/
#define testbyte(x) \
do { \
if (p[x] == '\0') \
return (p - str + x); \
} while (0)
size_t
strlen(const char *str)
{
const char *p;
const unsigned long *lp;
long va, vb;
/*
* Before trying the hard (unaligned byte-by-byte access) way
* to figure out whether there is a nul character, try to see
* if there is a nul character is within this accessible word
* first.
*
* p and (p & ~LONGPTR_MASK) must be equally accessible since
* they always fall in the same memory page, as long as page
* boundaries is integral multiple of word size.
*/
lp = (const unsigned long *)((uintptr_t)str & ~LONGPTR_MASK);
va = (*lp - mask01);
vb = ((~*lp) & mask80);
lp++;
if (va & vb)
/* Check if we have \0 in the first part */
for (p = str; p < (const char *)lp; p++)
if (*p == '\0')
return (p - str);
/* Scan the rest of the string using word sized operation */
for (; ; lp++) {
va = (*lp - mask01);
vb = ((~*lp) & mask80);
if (va & vb) {
p = (const char *)(lp);
testbyte(0);
testbyte(1);
testbyte(2);
testbyte(3);
#if (LONG_BIT >= 64)
testbyte(4);
testbyte(5);
testbyte(6);
testbyte(7);
#endif
}
}
/* NOTREACHED */
return (0);
}
diff --git a/lib/libc/string/strmode.c b/lib/libc/string/strmode.c
index 58b9490bb163..f70da2285b17 100644
--- a/lib/libc/string/strmode.c
+++ b/lib/libc/string/strmode.c
@@ -1,148 +1,147 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strmode.c 8.3 (Berkeley) 8/15/94";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
void
strmode(mode_t mode, char *p)
{
/* print type */
switch (mode & S_IFMT) {
case S_IFDIR: /* directory */
*p++ = 'd';
break;
case S_IFCHR: /* character special */
*p++ = 'c';
break;
case S_IFBLK: /* block special */
*p++ = 'b';
break;
case S_IFREG: /* regular */
*p++ = '-';
break;
case S_IFLNK: /* symbolic link */
*p++ = 'l';
break;
case S_IFSOCK: /* socket */
*p++ = 's';
break;
#ifdef S_IFIFO
case S_IFIFO: /* fifo */
*p++ = 'p';
break;
#endif
#ifdef S_IFWHT
case S_IFWHT: /* whiteout */
*p++ = 'w';
break;
#endif
default: /* unknown */
*p++ = '?';
break;
}
/* usr */
if (mode & S_IRUSR)
*p++ = 'r';
else
*p++ = '-';
if (mode & S_IWUSR)
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXUSR | S_ISUID)) {
case 0:
*p++ = '-';
break;
case S_IXUSR:
*p++ = 'x';
break;
case S_ISUID:
*p++ = 'S';
break;
case S_IXUSR | S_ISUID:
*p++ = 's';
break;
}
/* group */
if (mode & S_IRGRP)
*p++ = 'r';
else
*p++ = '-';
if (mode & S_IWGRP)
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXGRP | S_ISGID)) {
case 0:
*p++ = '-';
break;
case S_IXGRP:
*p++ = 'x';
break;
case S_ISGID:
*p++ = 'S';
break;
case S_IXGRP | S_ISGID:
*p++ = 's';
break;
}
/* other */
if (mode & S_IROTH)
*p++ = 'r';
else
*p++ = '-';
if (mode & S_IWOTH)
*p++ = 'w';
else
*p++ = '-';
switch (mode & (S_IXOTH | S_ISVTX)) {
case 0:
*p++ = '-';
break;
case S_IXOTH:
*p++ = 'x';
break;
case S_ISVTX:
*p++ = 'T';
break;
case S_IXOTH | S_ISVTX:
*p++ = 't';
break;
}
*p++ = ' ';
*p = '\0';
}
diff --git a/lib/libc/string/strncat.c b/lib/libc/string/strncat.c
index 3220f036c458..70dd04f2d727 100644
--- a/lib/libc/string/strncat.c
+++ b/lib/libc/string/strncat.c
@@ -1,62 +1,61 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strncat.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
/*
* Concatenate src on the end of dst. At most strlen(dst)+n+1 bytes
* are written at dst (at most n+1 bytes being appended). Return dst.
*/
char *
strncat(char * __restrict dst, const char * __restrict src, size_t n)
{
if (n != 0) {
char *d = dst;
const char *s = src;
while (*d != 0)
d++;
do {
if ((*d = *s++) == 0)
break;
d++;
} while (--n != 0);
*d = 0;
}
return (dst);
}
diff --git a/lib/libc/string/strncmp.c b/lib/libc/string/strncmp.c
index 111d77b592c2..0993babdae85 100644
--- a/lib/libc/string/strncmp.c
+++ b/lib/libc/string/strncmp.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strncmp.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
int
strncmp(const char *s1, const char *s2, size_t n)
{
if (n == 0)
return (0);
do {
if (*s1 != *s2++)
return (*(const unsigned char *)s1 -
*(const unsigned char *)(s2 - 1));
if (*s1++ == '\0')
break;
} while (--n != 0);
return (0);
}
diff --git a/lib/libc/string/strncpy.c b/lib/libc/string/strncpy.c
index 6a00e1ba5135..75b017401d5a 100644
--- a/lib/libc/string/strncpy.c
+++ b/lib/libc/string/strncpy.c
@@ -1,71 +1,70 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
/*
* Copy src to dst, truncating or null-padding to always copy n bytes.
* Return dst.
*/
#ifdef WEAK_STRNCPY
__weak_reference(__strncpy, strncpy);
#endif
char *
#ifdef WEAK_STRNCPY
__strncpy
#else
strncpy
#endif
(char * __restrict dst, const char * __restrict src, size_t n)
{
if (n != 0) {
char *d = dst;
const char *s = src;
do {
if ((*d++ = *s++) == '\0') {
/* NUL pad the remaining n-1 bytes */
while (--n != 0)
*d++ = '\0';
break;
}
} while (--n != 0);
}
return (dst);
}
diff --git a/lib/libc/string/strndup.c b/lib/libc/string/strndup.c
index a2351bf40722..56034d1732fe 100644
--- a/lib/libc/string/strndup.c
+++ b/lib/libc/string/strndup.c
@@ -1,38 +1,37 @@
/* $OpenBSD: strndup.c,v 1.1 2010/05/18 22:24:55 tedu Exp $ */
/*
* Copyright (c) 2010 Todd C. Miller <Todd.Miller@courtesan.com>
*
* 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 <sys/cdefs.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
char *
strndup(const char *str, size_t maxlen)
{
char *copy;
size_t len;
len = strnlen(str, maxlen);
copy = malloc(len + 1);
if (copy != NULL) {
(void)memcpy(copy, str, len);
copy[len] = '\0';
}
return copy;
}
diff --git a/lib/libc/string/strnlen.c b/lib/libc/string/strnlen.c
index 8fa984551b8e..b44f8ab21947 100644
--- a/lib/libc/string/strnlen.c
+++ b/lib/libc/string/strnlen.c
@@ -1,42 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <string.h>
size_t
strnlen(const char *s, size_t maxlen)
{
size_t len;
for (len = 0; len < maxlen; len++, s++) {
if (!*s)
break;
}
return (len);
}
diff --git a/lib/libc/string/strnstr.c b/lib/libc/string/strnstr.c
index 023b167e9c36..94cc808d7c66 100644
--- a/lib/libc/string/strnstr.c
+++ b/lib/libc/string/strnstr.c
@@ -1,65 +1,64 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2001 Mike Barcroft <mike@FreeBSD.org>
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
/*
* Find the first occurrence of find in s, where the search is limited to the
* first slen characters of s.
*/
char *
strnstr(const char *s, const char *find, size_t slen)
{
char c, sc;
size_t len;
if ((c = *find++) != '\0') {
len = strlen(find);
do {
do {
if (slen-- < 1 || (sc = *s++) == '\0')
return (NULL);
} while (sc != c);
if (len > slen)
return (NULL);
} while (strncmp(s, find, len) != 0);
s--;
}
return ((char *)s);
}
diff --git a/lib/libc/string/strpbrk.c b/lib/libc/string/strpbrk.c
index 80ac5ebc4bde..31cf96eb6b63 100644
--- a/lib/libc/string/strpbrk.c
+++ b/lib/libc/string/strpbrk.c
@@ -1,53 +1,52 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strpbrk.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
/*
* Find the first occurrence in s1 of a character in s2 (excluding NUL).
*/
char *
strpbrk(const char *s1, const char *s2)
{
const char *scanp;
int c, sc;
while ((c = *s1++) != 0) {
for (scanp = s2; (sc = *scanp++) != '\0';)
if (sc == c)
return ((char *)(s1 - 1));
}
return (NULL);
}
diff --git a/lib/libc/string/strrchr.c b/lib/libc/string/strrchr.c
index cfe6f9270bce..150380d40244 100644
--- a/lib/libc/string/strrchr.c
+++ b/lib/libc/string/strrchr.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)rindex.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stddef.h>
#include <string.h>
char *
strrchr(const char *p, int ch)
{
char *save;
char c;
c = ch;
for (save = NULL;; ++p) {
if (*p == c)
save = (char *)p;
if (*p == '\0')
return (save);
}
/* NOTREACHED */
}
__weak_reference(strrchr, rindex);
diff --git a/lib/libc/string/strsep.c b/lib/libc/string/strsep.c
index a3d64c92ff53..cde0680f393a 100644
--- a/lib/libc/string/strsep.c
+++ b/lib/libc/string/strsep.c
@@ -1,75 +1,74 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <string.h>
#include <stdio.h>
/*
* Get next token from string *stringp, where tokens are possibly-empty
* strings separated by characters from delim.
*
* Writes NULs into the string at *stringp to end tokens.
* delim need not remain constant from call to call.
* On return, *stringp points past the last NUL written (if there might
* be further tokens), or is NULL (if there are definitely no more tokens).
*
* If *stringp is NULL, strsep returns NULL.
*/
char *
strsep(char **stringp, const char *delim)
{
char *s;
const char *spanp;
int c, sc;
char *tok;
if ((s = *stringp) == NULL)
return (NULL);
for (tok = s;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = 0;
*stringp = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
diff --git a/lib/libc/string/strsignal.c b/lib/libc/string/strsignal.c
index 5abe7b37ed99..2f209d03c5f9 100644
--- a/lib/libc/string/strsignal.c
+++ b/lib/libc/string/strsignal.c
@@ -1,152 +1,151 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strerror.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include "namespace.h"
#if defined(NLS)
#include <nl_types.h>
#endif
#include <limits.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include "reentrant.h"
#include "un-namespace.h"
#define UPREFIX "Unknown signal"
static char sig_ebuf[NL_TEXTMAX];
static char sig_ebuf_err[NL_TEXTMAX];
static once_t sig_init_once = ONCE_INITIALIZER;
static thread_key_t sig_key;
static int sig_keycreated = 0;
static void
sig_keycreate(void)
{
sig_keycreated = (thr_keycreate(&sig_key, free) == 0);
}
static char *
sig_tlsalloc(void)
{
char *ebuf = NULL;
if (thr_main() != 0)
ebuf = sig_ebuf;
else {
if (thr_once(&sig_init_once, sig_keycreate) != 0 ||
!sig_keycreated)
goto thr_err;
if ((ebuf = thr_getspecific(sig_key)) == NULL) {
if ((ebuf = malloc(sizeof(sig_ebuf))) == NULL)
goto thr_err;
if (thr_setspecific(sig_key, ebuf) != 0) {
free(ebuf);
ebuf = NULL;
goto thr_err;
}
}
}
thr_err:
if (ebuf == NULL)
ebuf = sig_ebuf_err;
return (ebuf);
}
/* XXX: negative 'num' ? (REGR) */
char *
strsignal(int num)
{
char *ebuf;
char tmp[20];
size_t n;
int signum;
char *t, *p;
#if defined(NLS)
int saved_errno = errno;
nl_catd catd;
catd = catopen("libc", NL_CAT_LOCALE);
#endif
ebuf = sig_tlsalloc();
if (num > 0 && num < sys_nsig) {
n = strlcpy(ebuf,
#if defined(NLS)
catgets(catd, 2, num, sys_siglist[num]),
#else
sys_siglist[num],
#endif
sizeof(sig_ebuf));
} else {
n = strlcpy(ebuf,
#if defined(NLS)
catgets(catd, 2, 0xffff, UPREFIX),
#else
UPREFIX,
#endif
sizeof(sig_ebuf));
signum = num;
if (num < 0)
signum = -signum;
t = tmp;
do {
*t++ = "0123456789"[signum % 10];
} while (signum /= 10);
if (num < 0)
*t++ = '-';
p = (ebuf + n);
*p++ = ':';
*p++ = ' ';
for (;;) {
*p++ = *--t;
if (t <= tmp)
break;
}
*p = '\0';
}
#if defined(NLS)
catclose(catd);
errno = saved_errno;
#endif
return (ebuf);
}
diff --git a/lib/libc/string/strspn.c b/lib/libc/string/strspn.c
index a9df4da92cbe..5f046cf4e66b 100644
--- a/lib/libc/string/strspn.c
+++ b/lib/libc/string/strspn.c
@@ -1,71 +1,70 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 David Schultz <das@FreeBSD.ORG>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <limits.h>
#include <string.h>
#define IDX(c) ((u_char)(c) / LONG_BIT)
#define BIT(c) ((u_long)1 << ((u_char)(c) % LONG_BIT))
size_t
strspn(const char *s, const char *charset)
{
/*
* NB: idx and bit are temporaries whose use causes gcc 3.4.2 to
* generate better code. Without them, gcc gets a little confused.
*/
const char *s1;
u_long bit;
u_long tbl[(UCHAR_MAX + 1) / LONG_BIT];
int idx;
if(*s == '\0')
return (0);
#if LONG_BIT == 64 /* always better to unroll on 64-bit architectures */
tbl[3] = tbl[2] = tbl[1] = tbl[0] = 0;
#else
for (idx = 0; idx < sizeof(tbl) / sizeof(tbl[0]); idx++)
tbl[idx] = 0;
#endif
for (; *charset != '\0'; charset++) {
idx = IDX(*charset);
bit = BIT(*charset);
tbl[idx] |= bit;
}
for(s1 = s; ; s1++) {
idx = IDX(*s1);
bit = BIT(*s1);
if ((tbl[idx] & bit) == 0)
break;
}
return (s1 - s);
}
diff --git a/lib/libc/string/strstr.c b/lib/libc/string/strstr.c
index f3658805996b..90f8bc701e0f 100644
--- a/lib/libc/string/strstr.c
+++ b/lib/libc/string/strstr.c
@@ -1,220 +1,219 @@
/*-
* SPDX-License-Identifier: MIT
*
* Copyright (c) 2005-2014 Rich Felker, et al.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
-#include <sys/cdefs.h>
#include <stdint.h>
#include <string.h>
static char *
twobyte_strstr(const unsigned char *h, const unsigned char *n)
{
uint16_t nw = n[0] << 8 | n[1], hw = h[0] << 8 | h[1];
for (h++; *h && hw != nw; hw = hw << 8 | *++h)
;
return *h ? (char *)h - 1 : 0;
}
static char *
threebyte_strstr(const unsigned char *h, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8;
uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8;
for (h += 2; *h && hw != nw; hw = (hw | *++h) << 8)
;
return *h ? (char *)h - 2 : 0;
}
static char *
fourbyte_strstr(const unsigned char *h, const unsigned char *n)
{
uint32_t nw = (uint32_t)n[0] << 24 | n[1] << 16 | n[2] << 8 | n[3];
uint32_t hw = (uint32_t)h[0] << 24 | h[1] << 16 | h[2] << 8 | h[3];
for (h += 3; *h && hw != nw; hw = hw << 8 | *++h)
;
return *h ? (char *)h - 3 : 0;
}
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define BITOP(a, b, op) \
((a)[(size_t)(b) / (8 * sizeof *(a))] op \
(size_t)1 << ((size_t)(b) % (8 * sizeof *(a))))
/*
* Two Way string search algorithm, with a bad shift table applied to the last
* byte of the window. A bit array marks which entries in the shift table are
* initialized to avoid fully initializing a 1kb/2kb table.
*
* Reference: CROCHEMORE M., PERRIN D., 1991, Two-way string-matching,
* Journal of the ACM 38(3):651-675
*/
static char *
twoway_strstr(const unsigned char *h, const unsigned char *n)
{
const unsigned char *z;
size_t l, ip, jp, k, p, ms, p0, mem, mem0;
size_t byteset[32 / sizeof(size_t)] = { 0 };
size_t shift[256];
/* Computing length of needle and fill shift table */
for (l = 0; n[l] && h[l]; l++)
BITOP(byteset, n[l], |=), shift[n[l]] = l + 1;
if (n[l])
return 0; /* hit the end of h */
/* Compute maximal suffix */
ip = -1;
jp = 0;
k = p = 1;
while (jp + k < l) {
if (n[ip + k] == n[jp + k]) {
if (k == p) {
jp += p;
k = 1;
} else
k++;
} else if (n[ip + k] > n[jp + k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
ms = ip;
p0 = p;
/* And with the opposite comparison */
ip = -1;
jp = 0;
k = p = 1;
while (jp + k < l) {
if (n[ip + k] == n[jp + k]) {
if (k == p) {
jp += p;
k = 1;
} else
k++;
} else if (n[ip + k] < n[jp + k]) {
jp += k;
k = 1;
p = jp - ip;
} else {
ip = jp++;
k = p = 1;
}
}
if (ip + 1 > ms + 1)
ms = ip;
else
p = p0;
/* Periodic needle? */
if (memcmp(n, n + p, ms + 1)) {
mem0 = 0;
p = MAX(ms, l - ms - 1) + 1;
} else
mem0 = l - p;
mem = 0;
/* Initialize incremental end-of-haystack pointer */
z = h;
/* Search loop */
for (;;) {
/* Update incremental end-of-haystack pointer */
if (z - h < l) {
/* Fast estimate for MAX(l,63) */
size_t grow = l | 63;
const unsigned char *z2 = memchr(z, 0, grow);
if (z2) {
z = z2;
if (z - h < l)
return 0;
} else
z += grow;
}
/* Check last byte first; advance by shift on mismatch */
if (BITOP(byteset, h[l - 1], &)) {
k = l - shift[h[l - 1]];
if (k) {
if (k < mem)
k = mem;
h += k;
mem = 0;
continue;
}
} else {
h += l;
mem = 0;
continue;
}
/* Compare right half */
for (k = MAX(ms + 1, mem); n[k] && n[k] == h[k]; k++)
;
if (n[k]) {
h += k - ms;
mem = 0;
continue;
}
/* Compare left half */
for (k = ms + 1; k > mem && n[k - 1] == h[k - 1]; k--)
;
if (k <= mem)
return (char *)h;
h += p;
mem = mem0;
}
}
char *
strstr(const char *h, const char *n)
{
/* Return immediately on empty needle */
if (!n[0])
return (char *)h;
/* Use faster algorithms for short needles */
h = strchr(h, *n);
if (!h || !n[1])
return (char *)h;
if (!h[1])
return 0;
if (!n[2])
return twobyte_strstr((void *)h, (void *)n);
if (!h[2])
return 0;
if (!n[3])
return threebyte_strstr((void *)h, (void *)n);
if (!h[3])
return 0;
if (!n[4])
return fourbyte_strstr((void *)h, (void *)n);
return twoway_strstr((void *)h, (void *)n);
}
diff --git a/lib/libc/string/strtok.c b/lib/libc/string/strtok.c
index 1ff7a3aa45fc..7266578e58ed 100644
--- a/lib/libc/string/strtok.c
+++ b/lib/libc/string/strtok.c
@@ -1,136 +1,135 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1998 Softweyr LLC. All rights reserved.
*
* strtok_r, from Berkeley strtok
* Oct 13, 1998 by Wes Peters <wes@softweyr.com>
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notices, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notices, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
* REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strtok.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <stddef.h>
#ifdef DEBUG_STRTOK
#include <stdio.h>
#endif
#include <string.h>
char *__strtok_r(char *, const char *, char **);
__weak_reference(__strtok_r, strtok_r);
char *
__strtok_r(char *s, const char *delim, char **last)
{
char *spanp, *tok;
int c, sc;
if (s == NULL && (s = *last) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
if (c == sc)
goto cont;
}
if (c == 0) { /* no non-delimiter characters */
*last = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0)
s = NULL;
else
s[-1] = '\0';
*last = s;
return (tok);
}
} while (sc != 0);
}
/* NOTREACHED */
}
char *
strtok(char *s, const char *delim)
{
static char *last;
return (__strtok_r(s, delim, &last));
}
#ifdef DEBUG_STRTOK
/*
* Test the tokenizer.
*/
int
main(void)
{
char blah[80], test[80];
char *brkb, *brkt, *phrase, *sep, *word;
sep = "\\/:;=-";
phrase = "foo";
printf("String tokenizer test:\n");
strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
for (word = strtok(test, sep); word; word = strtok(NULL, sep))
printf("Next word is \"%s\".\n", word);
strcpy(test, "This;is.a:test:of=the/string\\tokenizer-function.");
for (word = strtok_r(test, sep, &brkt); word;
word = strtok_r(NULL, sep, &brkt)) {
strcpy(blah, "blah:blat:blab:blag");
for (phrase = strtok_r(blah, sep, &brkb); phrase;
phrase = strtok_r(NULL, sep, &brkb))
printf("So far we're at %s:%s\n", word, phrase);
}
return (0);
}
#endif /* DEBUG_STRTOK */
diff --git a/lib/libc/string/strxfrm.c b/lib/libc/string/strxfrm.c
index d9f3d0a7b6d5..e327aaf1c2ff 100644
--- a/lib/libc/string/strxfrm.c
+++ b/lib/libc/string/strxfrm.c
@@ -1,103 +1,102 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <wchar.h>
#include "collate.h"
size_t
strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t loc);
size_t
strxfrm(char * __restrict dest, const char * __restrict src, size_t len)
{
return strxfrm_l(dest, src, len, __get_locale());
}
size_t
strxfrm_l(char * __restrict dest, const char * __restrict src, size_t len, locale_t locale)
{
size_t slen;
size_t xlen;
wchar_t *wcs = NULL;
FIX_LOCALE(locale);
struct xlocale_collate *table =
(struct xlocale_collate*)locale->components[XLC_COLLATE];
if (!*src) {
if (len > 0)
*dest = '\0';
return (0);
}
/*
* The conversion from multibyte to wide character strings is
* strictly reducing (one byte of an mbs cannot expand to more
* than one wide character.)
*/
slen = strlen(src);
if (table->__collate_load_error)
goto error;
if ((wcs = malloc((slen + 1) * sizeof (wchar_t))) == NULL)
goto error;
if (mbstowcs_l(wcs, src, slen + 1, locale) == (size_t)-1)
goto error;
if ((xlen = _collate_sxfrm(table, wcs, dest, len)) == (size_t)-1)
goto error;
free(wcs);
if (len > xlen) {
dest[xlen] = 0;
} else if (len) {
dest[len-1] = 0;
}
return (xlen);
error:
/* errno should be set to ENOMEM if malloc failed */
free(wcs);
strlcpy(dest, src, len);
return (slen);
}
diff --git a/lib/libc/string/swab.c b/lib/libc/string/swab.c
index c239808291f0..c7790f84f959 100644
--- a/lib/libc/string/swab.c
+++ b/lib/libc/string/swab.c
@@ -1,62 +1,61 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Jeffrey Mogul.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)swab.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <unistd.h>
void
swab(const void * __restrict from, void * __restrict to, ssize_t len)
{
unsigned char temp;
size_t n;
const unsigned char *fp;
unsigned char *tp;
if (len <= 0)
return;
n = (size_t)len >> 1;
fp = (const unsigned char *)from;
tp = (unsigned char *)to;
#define STEP temp = *fp++,*tp++ = *fp++,*tp++ = temp
/* round to multiple of 8 */
for (; n & 0x7; --n)
STEP;
for (n >>= 3; n > 0; --n) {
STEP; STEP; STEP; STEP;
STEP; STEP; STEP; STEP;
}
}
diff --git a/lib/libc/string/timingsafe_bcmp.c b/lib/libc/string/timingsafe_bcmp.c
index 145b02b74b09..c3a595a18695 100644
--- a/lib/libc/string/timingsafe_bcmp.c
+++ b/lib/libc/string/timingsafe_bcmp.c
@@ -1,34 +1,33 @@
/* $OpenBSD: timingsafe_bcmp.c,v 1.3 2015/08/31 02:53:57 guenther Exp $ */
/*
* Copyright (c) 2010 Damien Miller. All rights reserved.
*
* 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 <sys/cdefs.h>
#include <string.h>
int __timingsafe_bcmp(const void *, const void *, size_t);
int
__timingsafe_bcmp(const void *b1, const void *b2, size_t n)
{
const unsigned char *p1 = b1, *p2 = b2;
int ret = 0;
for (; n > 0; n--)
ret |= *p1++ ^ *p2++;
return (ret != 0);
}
__weak_reference(__timingsafe_bcmp, timingsafe_bcmp);
diff --git a/lib/libc/string/timingsafe_memcmp.c b/lib/libc/string/timingsafe_memcmp.c
index 446a8a6cb2c3..97a146e06a2b 100644
--- a/lib/libc/string/timingsafe_memcmp.c
+++ b/lib/libc/string/timingsafe_memcmp.c
@@ -1,51 +1,50 @@
/* $OpenBSD: timingsafe_memcmp.c,v 1.2 2015/08/31 02:53:57 guenther Exp $ */
/*
* Copyright (c) 2014 Google Inc.
*
* 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 <sys/cdefs.h>
#include <limits.h>
#include <string.h>
int __timingsafe_memcmp(const void *, const void *, size_t);
int
__timingsafe_memcmp(const void *b1, const void *b2, size_t len)
{
const unsigned char *p1 = b1, *p2 = b2;
size_t i;
int res = 0, done = 0;
for (i = 0; i < len; i++) {
/* lt is -1 if p1[i] < p2[i]; else 0. */
int lt = (p1[i] - p2[i]) >> CHAR_BIT;
/* gt is -1 if p1[i] > p2[i]; else 0. */
int gt = (p2[i] - p1[i]) >> CHAR_BIT;
/* cmp is 1 if p1[i] > p2[i]; -1 if p1[i] < p2[i]; else 0. */
int cmp = lt - gt;
/* set res = cmp if !done. */
res |= cmp & ~done;
/* set done if p1[i] != p2[i]. */
done |= lt | gt;
}
return (res);
}
__weak_reference(__timingsafe_memcmp, timingsafe_memcmp);
diff --git a/lib/libc/string/wcpcpy.c b/lib/libc/string/wcpcpy.c
index 22c623bef320..bcdf05606e21 100644
--- a/lib/libc/string/wcpcpy.c
+++ b/lib/libc/string/wcpcpy.c
@@ -1,46 +1,45 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1999
* David E. O'Brien
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strcpy.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
-#include <sys/cdefs.h>
#include <wchar.h>
wchar_t *
wcpcpy(wchar_t * __restrict to, const wchar_t * __restrict from)
{
for (; (*to = *from); ++from, ++to);
return(to);
}
diff --git a/lib/libc/string/wcpncpy.c b/lib/libc/string/wcpncpy.c
index 4249f8bd24aa..72c060842e26 100644
--- a/lib/libc/string/wcpncpy.c
+++ b/lib/libc/string/wcpncpy.c
@@ -1,45 +1,44 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
wchar_t *
wcpncpy(wchar_t * __restrict dst, const wchar_t * __restrict src, size_t n)
{
for (; n--; dst++, src++) {
if (!(*dst = *src)) {
wchar_t *ret = dst;
while (n--)
*++dst = L'\0';
return (ret);
}
}
return (dst);
}
diff --git a/lib/libc/string/wcscasecmp.c b/lib/libc/string/wcscasecmp.c
index 50949ff38744..0132966fe0cf 100644
--- a/lib/libc/string/wcscasecmp.c
+++ b/lib/libc/string/wcscasecmp.c
@@ -1,45 +1,44 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include <wctype.h>
int
wcscasecmp(const wchar_t *s1, const wchar_t *s2)
{
wchar_t c1, c2;
for (; *s1; s1++, s2++) {
c1 = towlower(*s1);
c2 = towlower(*s2);
if (c1 != c2)
return ((int)c1 - c2);
}
return (-*s2);
}
diff --git a/lib/libc/string/wcschr.c b/lib/libc/string/wcschr.c
index 24c150ad17b4..356f8025c317 100644
--- a/lib/libc/string/wcschr.c
+++ b/lib/libc/string/wcschr.c
@@ -1,41 +1,40 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
wchar_t *
wcschr(const wchar_t *s, wchar_t c)
{
while (*s != c && *s != L'\0')
s++;
if (*s == c)
return ((wchar_t *)s);
return (NULL);
}
diff --git a/lib/libc/string/wcscoll.c b/lib/libc/string/wcscoll.c
index b7720c4069d1..e9394a83f60c 100644
--- a/lib/libc/string/wcscoll.c
+++ b/lib/libc/string/wcscoll.c
@@ -1,227 +1,226 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2017 Nexenta Systems, Inc.
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "collate.h"
int
wcscoll_l(const wchar_t *ws1, const wchar_t *ws2, locale_t locale)
{
int len1, len2, pri1, pri2;
wchar_t *tr1 = NULL, *tr2 = NULL;
int direc, pass;
int ret = wcscmp(ws1, ws2);
FIX_LOCALE(locale);
struct xlocale_collate *table =
(struct xlocale_collate*)locale->components[XLC_COLLATE];
if (table->__collate_load_error || ret == 0)
return (ret);
if (*ws1 == 0 && *ws2 != 0)
return (-1);
if (*ws1 != 0 && *ws2 == 0)
return (1);
/*
* Once upon a time we had code to try to optimize this, but
* it turns out that you really can't make many assumptions
* safely. You absolutely have to run this pass by pass,
* because some passes will be ignored for a given character,
* while others will not. Simpler locales will benefit from
* having fewer passes, and most comparisons should resolve
* during the primary pass anyway.
*
* Note that we do one final extra pass at the end to pick
* up UNDEFINED elements. There is special handling for them.
*/
for (pass = 0; pass <= table->info->directive_count; pass++) {
const int32_t *st1 = NULL;
const int32_t *st2 = NULL;
const wchar_t *w1 = ws1;
const wchar_t *w2 = ws2;
/* special pass for UNDEFINED */
if (pass == table->info->directive_count) {
direc = DIRECTIVE_FORWARD;
} else {
direc = table->info->directive[pass];
}
if (direc & DIRECTIVE_BACKWARD) {
wchar_t *bp, *fp, c;
free(tr1);
if ((tr1 = wcsdup(w1)) == NULL)
goto end;
bp = tr1;
fp = tr1 + wcslen(tr1) - 1;
while (bp < fp) {
c = *bp;
*bp++ = *fp;
*fp-- = c;
}
free(tr2);
if ((tr2 = wcsdup(w2)) == NULL)
goto end;
bp = tr2;
fp = tr2 + wcslen(tr2) - 1;
while (bp < fp) {
c = *bp;
*bp++ = *fp;
*fp-- = c;
}
w1 = tr1;
w2 = tr2;
}
if (direc & DIRECTIVE_POSITION) {
int check1, check2;
while (*w1 && *w2) {
pri1 = pri2 = 0;
check1 = check2 = 1;
while ((pri1 == pri2) && (check1 || check2)) {
if (check1) {
_collate_lookup(table, w1, &len1,
&pri1, pass, &st1);
if (pri1 < 0) {
errno = EINVAL;
goto end;
}
if (!pri1) {
pri1 = COLLATE_MAX_PRIORITY;
st1 = NULL;
}
check1 = (st1 != NULL);
}
if (check2) {
_collate_lookup(table, w2, &len2,
&pri2, pass, &st2);
if (pri2 < 0) {
errno = EINVAL;
goto end;
}
if (!pri2) {
pri2 = COLLATE_MAX_PRIORITY;
st2 = NULL;
}
check2 = (st2 != NULL);
}
}
if (pri1 != pri2) {
ret = pri1 - pri2;
goto end;
}
w1 += len1;
w2 += len2;
}
if (!*w1) {
if (*w2) {
ret = -(int)*w2;
goto end;
}
} else {
ret = *w1;
goto end;
}
} else {
int vpri1 = 0, vpri2 = 0;
while (*w1 || *w2 || st1 || st2) {
pri1 = 1;
while (*w1 || st1) {
_collate_lookup(table, w1, &len1, &pri1,
pass, &st1);
w1 += len1;
if (pri1 > 0) {
vpri1++;
break;
}
if (pri1 < 0) {
errno = EINVAL;
goto end;
}
st1 = NULL;
}
pri2 = 1;
while (*w2 || st2) {
_collate_lookup(table, w2, &len2, &pri2,
pass, &st2);
w2 += len2;
if (pri2 > 0) {
vpri2++;
break;
}
if (pri2 < 0) {
errno = EINVAL;
goto end;
}
st2 = NULL;
}
if ((!pri1 || !pri2) && (vpri1 == vpri2))
break;
if (pri1 != pri2) {
ret = pri1 - pri2;
goto end;
}
}
if (vpri1 && !vpri2) {
ret = 1;
goto end;
}
if (!vpri1 && vpri2) {
ret = -1;
goto end;
}
}
}
ret = 0;
end:
free(tr1);
free(tr2);
return (ret);
}
int
wcscoll(const wchar_t *ws1, const wchar_t *ws2)
{
return wcscoll_l(ws1, ws2, __get_locale());
}
diff --git a/lib/libc/string/wcsdup.c b/lib/libc/string/wcsdup.c
index 9aa088d3315f..517acfa7ec49 100644
--- a/lib/libc/string/wcsdup.c
+++ b/lib/libc/string/wcsdup.c
@@ -1,43 +1,42 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2005 Tim J. Robbins.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <wchar.h>
wchar_t *
wcsdup(const wchar_t *s)
{
wchar_t *copy;
size_t len;
len = wcslen(s) + 1;
if ((copy = malloc(len * sizeof(wchar_t))) == NULL)
return (NULL);
return (wmemcpy(copy, s, len));
}
diff --git a/lib/libc/string/wcsncasecmp.c b/lib/libc/string/wcsncasecmp.c
index 1b6772152f4a..0cd9f16796fa 100644
--- a/lib/libc/string/wcsncasecmp.c
+++ b/lib/libc/string/wcsncasecmp.c
@@ -1,49 +1,48 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include <wctype.h>
int
wcsncasecmp(const wchar_t *s1, const wchar_t *s2, size_t n)
{
wchar_t c1, c2;
if (n == 0)
return (0);
for (; *s1; s1++, s2++) {
c1 = towlower(*s1);
c2 = towlower(*s2);
if (c1 != c2)
return ((int)c1 - c2);
if (--n == 0)
return (0);
}
return (-*s2);
}
diff --git a/lib/libc/string/wcsncpy.c b/lib/libc/string/wcsncpy.c
index 16e3eb899b84..5aa74b4bac4a 100644
--- a/lib/libc/string/wcsncpy.c
+++ b/lib/libc/string/wcsncpy.c
@@ -1,64 +1,63 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strncpy.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#endif
-#include <sys/cdefs.h>
#include <wchar.h>
/*
* Copy src to dst, truncating or null-padding to always copy n bytes.
* Return dst.
*/
wchar_t *
wcsncpy(wchar_t * __restrict dst, const wchar_t * __restrict src, size_t n)
{
if (n != 0) {
wchar_t *d = dst;
const wchar_t *s = src;
do {
if ((*d++ = *s++) == L'\0') {
/* NUL pad the remaining n-1 bytes */
while (--n != 0)
*d++ = L'\0';
break;
}
} while (--n != 0);
}
return (dst);
}
diff --git a/lib/libc/string/wcsnlen.c b/lib/libc/string/wcsnlen.c
index 3c500855eb1f..1dfc2d5ef913 100644
--- a/lib/libc/string/wcsnlen.c
+++ b/lib/libc/string/wcsnlen.c
@@ -1,42 +1,41 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
size_t
wcsnlen(const wchar_t *s, size_t maxlen)
{
size_t len;
for (len = 0; len < maxlen; len++, s++) {
if (!*s)
break;
}
return (len);
}
diff --git a/lib/libc/string/wcsrchr.c b/lib/libc/string/wcsrchr.c
index 60f56551aaac..1679d808be2b 100644
--- a/lib/libc/string/wcsrchr.c
+++ b/lib/libc/string/wcsrchr.c
@@ -1,47 +1,46 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
wchar_t *
wcsrchr(const wchar_t *s, wchar_t c)
{
const wchar_t *last;
last = NULL;
for (;;) {
if (*s == c)
last = s;
if (*s == L'\0')
break;
s++;
}
return ((wchar_t *)last);
}
diff --git a/lib/libc/string/wcsstr.c b/lib/libc/string/wcsstr.c
index ff8739f1c75a..3ed5e578982c 100644
--- a/lib/libc/string/wcsstr.c
+++ b/lib/libc/string/wcsstr.c
@@ -1,63 +1,62 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1990, 1993
* The Regents of the University of California. All rights reserved.
*
* This code is derived from software contributed to Berkeley by
* Chris Torek.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#if 0
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)strstr.c 8.1 (Berkeley) 6/4/93";
#endif /* LIBC_SCCS and not lint */
#endif
-#include <sys/cdefs.h>
#include <wchar.h>
/*
* Find the first occurrence of find in s.
*/
wchar_t *
wcsstr(const wchar_t * __restrict s, const wchar_t * __restrict find)
{
wchar_t c, sc;
size_t len;
if ((c = *find++) != L'\0') {
len = wcslen(find);
do {
do {
if ((sc = *s++) == L'\0')
return (NULL);
} while (sc != c);
} while (wcsncmp(s, find, len) != 0);
s--;
}
return ((wchar_t *)s);
}
diff --git a/lib/libc/string/wcstok.c b/lib/libc/string/wcstok.c
index 65312db85b56..839a650ce316 100644
--- a/lib/libc/string/wcstok.c
+++ b/lib/libc/string/wcstok.c
@@ -1,86 +1,85 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1998 Softweyr LLC. All rights reserved.
*
* strtok_r, from Berkeley strtok
* Oct 13, 1998 by Wes Peters <wes@softweyr.com>
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notices, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notices, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
* REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
wchar_t *
wcstok(wchar_t * __restrict s, const wchar_t * __restrict delim,
wchar_t ** __restrict last)
{
const wchar_t *spanp;
wchar_t *tok;
wchar_t c, sc;
if (s == NULL && (s = *last) == NULL)
return (NULL);
/*
* Skip (span) leading delimiters (s += wcsspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = delim; (sc = *spanp++) != L'\0';) {
if (c == sc)
goto cont;
}
if (c == L'\0') { /* no non-delimiter characters */
*last = NULL;
return (NULL);
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += wcscspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = delim;
do {
if ((sc = *spanp++) == c) {
if (c == L'\0')
s = NULL;
else
s[-1] = L'\0';
*last = s;
return (tok);
}
} while (sc != L'\0');
}
/* NOTREACHED */
}
diff --git a/lib/libc/string/wcswidth.c b/lib/libc/string/wcswidth.c
index 84e9af602801..b6f3abd761eb 100644
--- a/lib/libc/string/wcswidth.c
+++ b/lib/libc/string/wcswidth.c
@@ -1,69 +1,68 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
* (c) UNIX System Laboratories, Inc.
* All or some portions of this file are derived from material licensed
* to the University of California by American Telephone and Telegraph
* Co. or Unix System Laboratories, Inc. and are reproduced herein with
* the permission of UNIX System Laboratories, Inc.
*
* This code is derived from software contributed to Berkeley by
* Paul Borman at Krystal Technologies.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include "xlocale_private.h"
int
wcswidth_l(const wchar_t *pwcs, size_t n, locale_t locale)
{
wchar_t wc;
int len, l;
FIX_LOCALE(locale);
len = 0;
while (n-- > 0 && (wc = *pwcs++) != L'\0') {
if ((l = wcwidth_l(wc, locale)) < 0)
return (-1);
len += l;
}
return (len);
}
int
wcswidth(const wchar_t *pwcs, size_t n)
{
return wcswidth_l(pwcs, n, __get_locale());
}
diff --git a/lib/libc/string/wcsxfrm.c b/lib/libc/string/wcsxfrm.c
index 6e4d7534828b..8c6c542c9255 100644
--- a/lib/libc/string/wcsxfrm.c
+++ b/lib/libc/string/wcsxfrm.c
@@ -1,85 +1,84 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright 2010 Nexenta Systems, Inc. All rights reserved.
* Copyright (c) 1995 Alex Tatmanjants <alex@elvisti.kiev.ua>
* at Electronni Visti IA, Kiev, Ukraine.
* All rights reserved.
*
* Copyright (c) 2011 The FreeBSD Foundation
*
* Portions of this software were developed by David Chisnall
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include "collate.h"
size_t
wcsxfrm_l(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len, locale_t locale)
{
size_t slen;
FIX_LOCALE(locale);
struct xlocale_collate *table =
(struct xlocale_collate*)locale->components[XLC_COLLATE];
if (*src == L'\0') {
if (len != 0)
*dest = L'\0';
return (0);
}
if ((table->__collate_load_error) ||
((slen = _collate_wxfrm(table, src, dest, len)) == (size_t)-1)) {
goto error;
}
/* Add null termination at the correct location. */
if (len > slen) {
dest[slen] = 0;
} else if (len) {
dest[len-1] = 0;
}
return (slen);
error:
slen = wcslen(src);
if (slen < len)
(void) wcscpy(dest, src);
else if (len > 0) {
(void) wcsncpy(dest, src, len - 1);
dest[len - 1] = L'\0';
}
return (slen);
}
size_t
wcsxfrm(wchar_t * __restrict dest, const wchar_t * __restrict src, size_t len)
{
return wcsxfrm_l(dest, src, len, __get_locale());
}
diff --git a/lib/libc/string/wmempcpy.c b/lib/libc/string/wmempcpy.c
index a21621de3977..6551787abf65 100644
--- a/lib/libc/string/wmempcpy.c
+++ b/lib/libc/string/wmempcpy.c
@@ -1,39 +1,38 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2021 The FreeBSD Foundation
*
* This software was developed by Konstantin Belousov <kib@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <string.h>
#include <wchar.h>
wchar_t *
wmempcpy(wchar_t *__restrict dst, const wchar_t *__restrict src, size_t len)
{
return (wmemcpy(dst, src, len) + len);
}
diff --git a/lib/libc/sys/POSIX2x_Fork.c b/lib/libc/sys/POSIX2x_Fork.c
index 4745f1be42b5..766bd4000036 100644
--- a/lib/libc/sys/POSIX2x_Fork.c
+++ b/lib/libc/sys/POSIX2x_Fork.c
@@ -1,42 +1,41 @@
/*
* Copyright (c) 2021 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <unistd.h>
#include "libc_private.h"
#pragma weak _Fork
pid_t
_Fork(void)
{
return (__sys_fork());
}
diff --git a/lib/libc/sys/__error.c b/lib/libc/sys/__error.c
index d37527052585..7f2bf5713b1d 100644
--- a/lib/libc/sys/__error.c
+++ b/lib/libc/sys/__error.c
@@ -1,58 +1,57 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1997 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "libc_private.h"
extern int errno;
static int *
__error_unthreaded(void)
{
return (&errno);
}
static int *(*__error_selector)(void) = __error_unthreaded;
void
__set_error_selector(int *(*arg)(void))
{
__error_selector = arg;
}
int *
__error(void)
{
return (__error_selector());
}
diff --git a/lib/libc/sys/__vdso_gettimeofday.c b/lib/libc/sys/__vdso_gettimeofday.c
index f256849562dd..273eeb58d195 100644
--- a/lib/libc/sys/__vdso_gettimeofday.c
+++ b/lib/libc/sys/__vdso_gettimeofday.c
@@ -1,197 +1,196 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/elf.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <errno.h>
#include <stdbool.h>
#include <strings.h>
#include <time.h>
#include <machine/atomic.h>
#include "libc_private.h"
static int
tc_delta(const struct vdso_timehands *th, u_int *delta)
{
int error;
u_int tc;
error = __vdso_gettc(th, &tc);
if (error == 0)
*delta = (tc - th->th_offset_count) & th->th_counter_mask;
return (error);
}
/*
* Calculate the absolute or boot-relative time from the
* machine-specific fast timecounter and the published timehands
* structure read from the shared page.
*
* The lockless reading scheme is similar to the one used to read the
* in-kernel timehands, see sys/kern/kern_tc.c:binuptime(). This code
* is based on the kernel implementation.
*/
static int
binuptime(struct bintime *bt, struct vdso_timekeep *tk, bool abs)
{
struct vdso_timehands *th;
uint32_t curr, gen;
uint64_t scale, x;
u_int delta, scale_bits;
int error;
do {
if (!tk->tk_enabled)
return (ENOSYS);
curr = atomic_load_acq_32(&tk->tk_current);
th = &tk->tk_th[curr];
gen = atomic_load_acq_32(&th->th_gen);
*bt = th->th_offset;
error = tc_delta(th, &delta);
if (error == EAGAIN)
continue;
if (error != 0)
return (error);
scale = th->th_scale;
#ifdef _LP64
scale_bits = flsl(scale);
#else
scale_bits = flsll(scale);
#endif
if (__predict_false(scale_bits + fls(delta) > 63)) {
x = (scale >> 32) * delta;
scale &= 0xffffffff;
bt->sec += x >> 32;
bintime_addx(bt, x << 32);
}
bintime_addx(bt, scale * delta);
if (abs)
bintime_add(bt, &th->th_boottime);
/*
* Ensure that the load of th_offset is completed
* before the load of th_gen.
*/
atomic_thread_fence_acq();
} while (curr != tk->tk_current || gen == 0 || gen != th->th_gen);
return (0);
}
static int
getnanouptime(struct bintime *bt, struct vdso_timekeep *tk)
{
struct vdso_timehands *th;
uint32_t curr, gen;
do {
if (!tk->tk_enabled)
return (ENOSYS);
curr = atomic_load_acq_32(&tk->tk_current);
th = &tk->tk_th[curr];
gen = atomic_load_acq_32(&th->th_gen);
*bt = th->th_offset;
/*
* Ensure that the load of th_offset is completed
* before the load of th_gen.
*/
atomic_thread_fence_acq();
} while (curr != tk->tk_current || gen == 0 || gen != th->th_gen);
return (0);
}
static struct vdso_timekeep *tk;
#pragma weak __vdso_gettimeofday
int
__vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
{
struct bintime bt;
int error;
if (tz != NULL)
return (ENOSYS);
if (tk == NULL) {
error = __vdso_gettimekeep(&tk);
if (error != 0 || tk == NULL)
return (ENOSYS);
}
if (tk->tk_ver != VDSO_TK_VER_CURR)
return (ENOSYS);
error = binuptime(&bt, tk, true);
if (error != 0)
return (error);
bintime2timeval(&bt, tv);
return (0);
}
#pragma weak __vdso_clock_gettime
int
__vdso_clock_gettime(clockid_t clock_id, struct timespec *ts)
{
struct bintime bt;
int error;
if (tk == NULL) {
error = _elf_aux_info(AT_TIMEKEEP, &tk, sizeof(tk));
if (error != 0 || tk == NULL)
return (ENOSYS);
}
if (tk->tk_ver != VDSO_TK_VER_CURR)
return (ENOSYS);
switch (clock_id) {
case CLOCK_REALTIME:
case CLOCK_REALTIME_PRECISE:
case CLOCK_REALTIME_FAST:
case CLOCK_SECOND:
error = binuptime(&bt, tk, true);
break;
case CLOCK_MONOTONIC:
case CLOCK_MONOTONIC_PRECISE:
case CLOCK_UPTIME:
case CLOCK_UPTIME_PRECISE:
error = binuptime(&bt, tk, false);
break;
case CLOCK_MONOTONIC_FAST:
case CLOCK_UPTIME_FAST:
error = getnanouptime(&bt, tk);
break;
default:
error = ENOSYS;
break;
}
if (error != 0)
return (error);
bintime2timespec(&bt, ts);
if (clock_id == CLOCK_SECOND)
ts->tv_nsec = 0;
return (0);
}
diff --git a/lib/libc/sys/accept.c b/lib/libc/sys/accept.c
index 417fb344a91e..81f227c1caab 100644
--- a/lib/libc/sys/accept.c
+++ b/lib/libc/sys/accept.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include "libc_private.h"
__weak_reference(__sys_accept, __accept);
#pragma weak accept
int
accept(int s, struct sockaddr *addr, socklen_t *addrlen)
{
return (((int (*)(int, struct sockaddr *, socklen_t *))
__libc_interposing[INTERPOS_accept])(s, addr, addrlen));
}
diff --git a/lib/libc/sys/accept4.c b/lib/libc/sys/accept4.c
index 56cc06efdfe6..01fdce342e42 100644
--- a/lib/libc/sys/accept4.c
+++ b/lib/libc/sys/accept4.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include "libc_private.h"
__weak_reference(__sys_accept4, __accept4);
#pragma weak accept4
int
accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags)
{
return (((int (*)(int, struct sockaddr *, socklen_t *, int))
__libc_interposing[INTERPOS_accept4])(s, addr, addrlen, flags));
}
diff --git a/lib/libc/sys/aio_suspend.c b/lib/libc/sys/aio_suspend.c
index fc9a0d906c92..3324bcc8de2f 100644
--- a/lib/libc/sys/aio_suspend.c
+++ b/lib/libc/sys/aio_suspend.c
@@ -1,48 +1,47 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/aio.h>
#include "libc_private.h"
__weak_reference(__sys_aio_suspend, __aio_suspend);
#pragma weak aio_suspend
int
aio_suspend(const struct aiocb * const iocbs[], int niocb,
const struct timespec *timeout)
{
return (((int (*)(const struct aiocb * const[], int,
const struct timespec *))
__libc_interposing[INTERPOS_aio_suspend])(iocbs, niocb, timeout));
}
diff --git a/lib/libc/sys/brk.c b/lib/libc/sys/brk.c
index 51bbcbdfcaef..b3e6abdac981 100644
--- a/lib/libc/sys/brk.c
+++ b/lib/libc/sys/brk.c
@@ -1,105 +1,104 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 Mark Johnston <markj@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
void *__sys_break(char *nsize);
static uintptr_t curbrk, minbrk;
static int curbrk_initted;
static int
initbrk(void)
{
void *newbrk;
if (!curbrk_initted) {
newbrk = __sys_break(NULL);
if (newbrk == (void *)-1)
return (-1);
curbrk = minbrk = (uintptr_t)newbrk;
curbrk_initted = 1;
}
return (0);
}
static void *
mvbrk(void *addr)
{
uintptr_t oldbrk;
if ((uintptr_t)addr < minbrk) {
/* Emulate legacy error handling in the syscall. */
errno = EINVAL;
return ((void *)-1);
}
if (__sys_break(addr) == (void *)-1)
return ((void *)-1);
oldbrk = curbrk;
curbrk = (uintptr_t)addr;
return ((void *)oldbrk);
}
int
brk(const void *addr)
{
if (initbrk() == -1)
return (-1);
if ((uintptr_t)addr < minbrk)
addr = (void *)minbrk;
return (mvbrk(__DECONST(void *, addr)) == (void *)-1 ? -1 : 0);
}
int
_brk(const void *addr)
{
if (initbrk() == -1)
return (-1);
return (mvbrk(__DECONST(void *, addr)) == (void *)-1 ? -1 : 0);
}
void *
sbrk(intptr_t incr)
{
if (initbrk() == -1)
return ((void *)-1);
if ((incr > 0 && curbrk + incr < curbrk) ||
(incr < 0 && curbrk + incr > curbrk)) {
/* Emulate legacy error handling in the syscall. */
errno = EINVAL;
return ((void *)-1);
}
return (mvbrk((void *)(curbrk + incr)));
}
diff --git a/lib/libc/sys/clock_gettime.c b/lib/libc/sys/clock_gettime.c
index 7894dbf4ef5a..069e70beaa1b 100644
--- a/lib/libc/sys/clock_gettime.c
+++ b/lib/libc/sys/clock_gettime.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <errno.h>
#include <time.h>
#include "libc_private.h"
int __clock_gettime(clockid_t, struct timespec *ts);
__weak_reference(__clock_gettime, clock_gettime);
int
__clock_gettime(clockid_t clock_id, struct timespec *ts)
{
int error;
if (__vdso_clock_gettime != NULL && __vdso_gettc != NULL)
error = __vdso_clock_gettime(clock_id, ts);
else
error = ENOSYS;
if (error == ENOSYS) {
error = __sys_clock_gettime(clock_id, ts);
} else if (error != 0) {
errno = error;
error = -1;
}
return (error);
}
diff --git a/lib/libc/sys/clock_nanosleep.c b/lib/libc/sys/clock_nanosleep.c
index 9989f1a995f5..a9d811f11b04 100644
--- a/lib/libc/sys/clock_nanosleep.c
+++ b/lib/libc/sys/clock_nanosleep.c
@@ -1,50 +1,49 @@
/*
* Copyright (c) 2017 Eric van Gyzen
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <time.h>
#include "libc_private.h"
__weak_reference(__sys_clock_nanosleep, __clock_nanosleep);
#pragma weak clock_nanosleep
int
clock_nanosleep(clockid_t clock_id, int flags, const struct timespec *rqtp,
struct timespec *rmtp)
{
return (((int (*)(clockid_t, int, const struct timespec *,
struct timespec *))
__libc_interposing[INTERPOS_clock_nanosleep])(clock_id, flags,
rqtp, rmtp));
}
diff --git a/lib/libc/sys/close.c b/lib/libc/sys/close.c
index 0fb319b77102..e4d81614b056 100644
--- a/lib/libc/sys/close.c
+++ b/lib/libc/sys/close.c
@@ -1,46 +1,45 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(__sys_close, __close);
#pragma weak close
int
close(int fd)
{
return (((int (*)(int))__libc_interposing[INTERPOS_close])(fd));
}
diff --git a/lib/libc/sys/closefrom.c b/lib/libc/sys/closefrom.c
index 2eb8536e6968..292702fad38c 100644
--- a/lib/libc/sys/closefrom.c
+++ b/lib/libc/sys/closefrom.c
@@ -1,46 +1,45 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2020 Kyle Evans <kevans@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "libc_private.h"
#define CLOSE_RANGE_OSREL 1300091
void
closefrom(int lowfd)
{
if (__getosreldate() >= CLOSE_RANGE_OSREL)
__sys_close_range(MAX(0, lowfd), ~0U, 0);
else
/* Fallback to closefrom(2) on older kernels. */
syscall(SYS_freebsd12_closefrom, lowfd);
}
diff --git a/lib/libc/sys/compat-stub.c b/lib/libc/sys/compat-stub.c
index b1dd906dc8a0..d23eaf3f89b8 100644
--- a/lib/libc/sys/compat-stub.c
+++ b/lib/libc/sys/compat-stub.c
@@ -1,56 +1,55 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 SRI International
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory (Department of Computer Science and
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
* DARPA SSITH research programme.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/errno.h>
/*
* XXX: Ideally we'd use a common function rather than generating one
* for each compat symbol, but the bfd linker in base rejects that.
* This should be revisited once we're using only modern linkers.
*/
#define __compat_nosys(symbol, version) \
int __compat_enosys ## symbol(void); \
int \
__compat_enosys ## symbol(void) \
{ \
\
return (ENOSYS); \
} \
__sym_compat(symbol, __compat_enosys ## symbol, version)
__compat_nosys(netbsd_lchown, FBSD_1.0);
__compat_nosys(netbsd_msync, FBSD_1.0);
__compat_nosys(numa_getaffinity, FBSD_1.4);
__compat_nosys(numa_setaffinity, FBSD_1.4);
diff --git a/lib/libc/sys/connect.c b/lib/libc/sys/connect.c
index 10277dfadc64..dd70908496a7 100644
--- a/lib/libc/sys/connect.c
+++ b/lib/libc/sys/connect.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include "libc_private.h"
__weak_reference(__sys_connect, __connect);
#pragma weak connect
int
connect(int s, const struct sockaddr *addr, socklen_t addrlen)
{
return (((int (*)(int, const struct sockaddr *, socklen_t))
__libc_interposing[INTERPOS_connect])(s, addr, addrlen));
}
diff --git a/lib/libc/sys/fcntl.c b/lib/libc/sys/fcntl.c
index ff231981d079..ad3734dfbf14 100644
--- a/lib/libc/sys/fcntl.c
+++ b/lib/libc/sys/fcntl.c
@@ -1,55 +1,54 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2008 Isilon Inc http://www.isilon.com/
* Authors: Doug Rabson <dfr@rabson.org>
* Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
*
* Copyright (c) 2014-2015 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <fcntl.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include "libc_private.h"
#pragma weak fcntl
int
fcntl(int fd, int cmd, ...)
{
va_list args;
long arg;
va_start(args, cmd);
arg = va_arg(args, long);
va_end(args);
return (((int (*)(int, int, ...))
__libc_interposing[INTERPOS_fcntl])(fd, cmd, arg));
}
diff --git a/lib/libc/sys/fdatasync.c b/lib/libc/sys/fdatasync.c
index b56d5aa533d4..e400d1bcefb5 100644
--- a/lib/libc/sys/fdatasync.c
+++ b/lib/libc/sys/fdatasync.c
@@ -1,43 +1,42 @@
/*
* Copyright (c) 2016 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "libc_private.h"
int
fdatasync(int fd)
{
return (((int (*)(int))__libc_interposing[INTERPOS_fdatasync])(fd));
}
diff --git a/lib/libc/sys/fork.c b/lib/libc/sys/fork.c
index c45e5c93f226..ecd8ecdf5730 100644
--- a/lib/libc/sys/fork.c
+++ b/lib/libc/sys/fork.c
@@ -1,45 +1,44 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(__sys_fork, __fork);
#pragma weak fork
pid_t
fork(void)
{
return (((pid_t (*)(void))__libc_interposing[INTERPOS_fork])());
}
diff --git a/lib/libc/sys/fsync.c b/lib/libc/sys/fsync.c
index ae9554f468f6..32302eb96492 100644
--- a/lib/libc/sys/fsync.c
+++ b/lib/libc/sys/fsync.c
@@ -1,45 +1,44 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(__sys_fsync, __fsync);
int
fsync(int fd)
{
return (((int (*)(int))__libc_interposing[INTERPOS_fsync])(fd));
}
diff --git a/lib/libc/sys/getdents.c b/lib/libc/sys/getdents.c
index 673b7d62d1ee..df8993a7b0f9 100644
--- a/lib/libc/sys/getdents.c
+++ b/lib/libc/sys/getdents.c
@@ -1,39 +1,38 @@
/*-
* Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/syscall.h>
#include <dirent.h>
#include "libc_private.h"
ssize_t
getdents(int fd, char *buf, size_t nbytes)
{
return (__sys_getdirentries(fd, buf, nbytes, NULL));
}
diff --git a/lib/libc/sys/gettimeofday.c b/lib/libc/sys/gettimeofday.c
index 8a09098d0ef5..bc7990aa0457 100644
--- a/lib/libc/sys/gettimeofday.c
+++ b/lib/libc/sys/gettimeofday.c
@@ -1,52 +1,51 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/syscall.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <errno.h>
#include "libc_private.h"
int __gettimeofday(struct timeval *tv, struct timezone *tz);
__weak_reference(__gettimeofday, gettimeofday);
int
__gettimeofday(struct timeval *tv, struct timezone *tz)
{
int error;
error = __vdso_gettimeofday(tv, tz);
if (error == ENOSYS) {
error = __sys_gettimeofday(tv, tz);
} else if (error != 0) {
errno = error;
error = -1;
}
return (error);
}
diff --git a/lib/libc/sys/interposing_table.c b/lib/libc/sys/interposing_table.c
index d5517a83b14a..e497319e8d27 100644
--- a/lib/libc/sys/interposing_table.c
+++ b/lib/libc/sys/interposing_table.c
@@ -1,91 +1,90 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include "libc_private.h"
#define SLOT(a, b) \
[INTERPOS_##a] = (interpos_func_t)b
interpos_func_t __libc_interposing[INTERPOS_MAX] = {
SLOT(accept, __sys_accept),
SLOT(accept4, __sys_accept4),
SLOT(aio_suspend, __sys_aio_suspend),
SLOT(close, __sys_close),
SLOT(connect, __sys_connect),
SLOT(fcntl, __sys_fcntl),
SLOT(fsync, __sys_fsync),
SLOT(fork, __sys_fork),
SLOT(msync, __sys_msync),
SLOT(nanosleep, __sys_nanosleep),
SLOT(openat, __sys_openat),
SLOT(poll, __sys_poll),
SLOT(pselect, __sys_pselect),
SLOT(read, __sys_read),
SLOT(readv, __sys_readv),
SLOT(recvfrom, __sys_recvfrom),
SLOT(recvmsg, __sys_recvmsg),
SLOT(select, __sys_select),
SLOT(sendmsg, __sys_sendmsg),
SLOT(sendto, __sys_sendto),
SLOT(setcontext, __sys_setcontext),
SLOT(sigaction, __sys_sigaction),
SLOT(sigprocmask, __sys_sigprocmask),
SLOT(sigsuspend, __sys_sigsuspend),
SLOT(sigwait, __libc_sigwait),
SLOT(sigtimedwait, __sys_sigtimedwait),
SLOT(sigwaitinfo, __sys_sigwaitinfo),
SLOT(swapcontext, __sys_swapcontext),
SLOT(system, __libc_system),
SLOT(tcdrain, __libc_tcdrain),
SLOT(wait4, __sys_wait4),
SLOT(write, __sys_write),
SLOT(writev, __sys_writev),
SLOT(_pthread_mutex_init_calloc_cb, _pthread_mutex_init_calloc_cb_stub),
SLOT(spinlock, __libc_spinlock_stub),
SLOT(spinunlock, __libc_spinunlock_stub),
SLOT(kevent, __sys_kevent),
SLOT(wait6, __sys_wait6),
SLOT(ppoll, __sys_ppoll),
SLOT(map_stacks_exec, __libc_map_stacks_exec),
SLOT(fdatasync, __sys_fdatasync),
SLOT(clock_nanosleep, __sys_clock_nanosleep),
SLOT(distribute_static_tls, __libc_distribute_static_tls),
SLOT(pdfork, __sys_pdfork),
};
#undef SLOT
interpos_func_t *
__libc_interposing_slot(int interposno)
{
return (&__libc_interposing[interposno]);
}
diff --git a/lib/libc/sys/kevent.c b/lib/libc/sys/kevent.c
index ef2440721bb4..4987dbc9a967 100644
--- a/lib/libc/sys/kevent.c
+++ b/lib/libc/sys/kevent.c
@@ -1,50 +1,49 @@
/*
* Copyright (c) 2015 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include "libc_private.h"
__weak_reference(__sys_kevent, __kevent);
#pragma weak kevent
int
kevent(int kq, const struct kevent *changelist, int nchanges,
struct kevent *eventlist, int nevents, const struct timespec *timeout)
{
return (((int (*)(int, const struct kevent *, int,
struct kevent *, int, const struct timespec *))
__libc_interposing[INTERPOS_kevent])(kq, changelist, nchanges,
eventlist, nevents, timeout));
}
diff --git a/lib/libc/sys/lstat.c b/lib/libc/sys/lstat.c
index b335946d2f3c..3a6421120434 100644
--- a/lib/libc/sys/lstat.c
+++ b/lib/libc/sys/lstat.c
@@ -1,41 +1,40 @@
/*-
* Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org> All rights reserved.
* Copyright (c) 2017 M. Warner Losh <imp@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/fcntl.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <unistd.h>
#include "libc_private.h"
int
lstat(const char *path, struct stat *sb)
{
return (__sys_fstatat(AT_FDCWD, path, sb, AT_SYMLINK_NOFOLLOW));
}
diff --git a/lib/libc/sys/mknod.c b/lib/libc/sys/mknod.c
index 8e8fa9faaebf..fd224058b5fb 100644
--- a/lib/libc/sys/mknod.c
+++ b/lib/libc/sys/mknod.c
@@ -1,43 +1,42 @@
/*-
* Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/fcntl.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <unistd.h>
#include "libc_private.h"
int __sys_mknodat(int, const char *, mode_t, dev_t);
int
mknod(const char *path, mode_t mode, dev_t dev)
{
return (__sys_mknodat(AT_FDCWD, path, mode, dev));
}
diff --git a/lib/libc/sys/msync.c b/lib/libc/sys/msync.c
index 96b0e778d115..587687e636a5 100644
--- a/lib/libc/sys/msync.c
+++ b/lib/libc/sys/msync.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include "libc_private.h"
__weak_reference(__sys_msync, __msync);
#pragma weak msync
int
msync(void *addr, size_t len, int flags)
{
return (((int (*)(void *, size_t, int))
__libc_interposing[INTERPOS_msync])(addr, len, flags));
}
diff --git a/lib/libc/sys/nanosleep.c b/lib/libc/sys/nanosleep.c
index 076ee33e44ea..22ebd4868fd4 100644
--- a/lib/libc/sys/nanosleep.c
+++ b/lib/libc/sys/nanosleep.c
@@ -1,46 +1,45 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <time.h>
#include "libc_private.h"
__weak_reference(__sys_nanosleep, __nanosleep);
#pragma weak nanosleep
int
nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
{
return (((int (*)(const struct timespec *, struct timespec *))
__libc_interposing[INTERPOS_nanosleep])(rqtp, rmtp));
}
diff --git a/lib/libc/sys/open.c b/lib/libc/sys/open.c
index 020134d5693b..25e72d1a03d7 100644
--- a/lib/libc/sys/open.c
+++ b/lib/libc/sys/open.c
@@ -1,56 +1,55 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <stdarg.h>
#include "libc_private.h"
__weak_reference(__sys_open, __open);
#pragma weak open
int
open(const char *path, int flags, ...)
{
va_list ap;
int mode;
if ((flags & O_CREAT) != 0) {
va_start(ap, flags);
mode = va_arg(ap, int);
va_end(ap);
} else {
mode = 0;
}
return (((int (*)(int, const char *, int, ...))
__libc_interposing[INTERPOS_openat])(AT_FDCWD, path, flags, mode));
}
diff --git a/lib/libc/sys/openat.c b/lib/libc/sys/openat.c
index 9edf7d493bfd..8ed95e938a38 100644
--- a/lib/libc/sys/openat.c
+++ b/lib/libc/sys/openat.c
@@ -1,59 +1,58 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <stdarg.h>
#include "libc_private.h"
__weak_reference(__sys_openat, __openat);
__sym_compat(openat, __impl_openat, FBSD_1.1);
__weak_reference(openat, __impl_openat);
__sym_default(openat, openat, FBSD_1.2);
#pragma weak openat
int
openat(int fd, const char *path, int flags, ...)
{
va_list ap;
int mode;
if ((flags & O_CREAT) != 0) {
va_start(ap, flags);
mode = va_arg(ap, int);
va_end(ap);
} else {
mode = 0;
}
return (((int (*)(int, const char *, int, ...))
__libc_interposing[INTERPOS_openat])(fd, path, flags, mode));
}
diff --git a/lib/libc/sys/pdfork.c b/lib/libc/sys/pdfork.c
index 14867a2f20a5..e2a5eca848ea 100644
--- a/lib/libc/sys/pdfork.c
+++ b/lib/libc/sys/pdfork.c
@@ -1,43 +1,42 @@
/*
* Copyright (c) 2021 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/procdesc.h>
#include "libc_private.h"
#pragma weak pdfork
pid_t
pdfork(int *fdp, int flags)
{
return (((pid_t (*)(int *, int))__libc_interposing[
INTERPOS_pdfork])(fdp, flags));
}
diff --git a/lib/libc/sys/pipe.c b/lib/libc/sys/pipe.c
index 1c45ab0c8a19..370895166ad0 100644
--- a/lib/libc/sys/pipe.c
+++ b/lib/libc/sys/pipe.c
@@ -1,45 +1,44 @@
/*-
* Copyright (c) 2016 SRI International
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
* ("CTSRD"), as part of the DARPA CRASH research programme.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <unistd.h>
__weak_reference(__sys_pipe, pipe);
__weak_reference(__sys_pipe, _pipe);
extern int __sys_pipe2(int fildes[2], int flags);
int
__sys_pipe(int fildes[2])
{
return (__sys_pipe2(fildes, 0));
}
diff --git a/lib/libc/sys/poll.c b/lib/libc/sys/poll.c
index f03320dc9319..69c44731d18b 100644
--- a/lib/libc/sys/poll.c
+++ b/lib/libc/sys/poll.c
@@ -1,46 +1,45 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/poll.h>
#include "libc_private.h"
__weak_reference(__sys_poll, __poll);
#pragma weak poll
int
poll(struct pollfd pfd[], nfds_t nfds, int timeout)
{
return (((int (*)(struct pollfd *, nfds_t, int))
__libc_interposing[INTERPOS_poll])(pfd, nfds, timeout));
}
diff --git a/lib/libc/sys/ppoll.c b/lib/libc/sys/ppoll.c
index 8f886b8c5108..ea998b6dadb5 100644
--- a/lib/libc/sys/ppoll.c
+++ b/lib/libc/sys/ppoll.c
@@ -1,48 +1,47 @@
/*
* Copyright (c) 2015 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/poll.h>
#include "libc_private.h"
__weak_reference(__sys_ppoll, __ppoll);
#pragma weak ppoll
int
ppoll(struct pollfd pfd[], nfds_t nfds, const struct timespec *__restrict
timeout, const sigset_t *__restrict newsigmask)
{
return (((int (*)(struct pollfd *, nfds_t, const struct timespec *,
const sigset_t *)) __libc_interposing[INTERPOS_ppoll])(pfd, nfds,
timeout, newsigmask));
}
diff --git a/lib/libc/sys/pselect.c b/lib/libc/sys/pselect.c
index 2ea717ef1d65..562c304fc594 100644
--- a/lib/libc/sys/pselect.c
+++ b/lib/libc/sys/pselect.c
@@ -1,48 +1,47 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/select.h>
#include "libc_private.h"
__weak_reference(__sys_pselect, __pselect);
#pragma weak pselect
int
pselect(int n, fd_set *rs, fd_set *ws, fd_set *es, const struct timespec *t,
const sigset_t *s)
{
return (((int (*)(int, fd_set *, fd_set *, fd_set *,
const struct timespec *, const sigset_t *))
__libc_interposing[INTERPOS_pselect])(n, rs, ws, es, t, s));
}
diff --git a/lib/libc/sys/ptrace.c b/lib/libc/sys/ptrace.c
index 55ad50e025aa..65f2ee80d8ea 100644
--- a/lib/libc/sys/ptrace.c
+++ b/lib/libc/sys/ptrace.c
@@ -1,46 +1,45 @@
/*
* Copyright (c) 2016 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/ptrace.h>
#include <errno.h>
#include "libc_private.h"
__weak_reference(_ptrace, ptrace);
int
_ptrace(int request, pid_t pid, caddr_t addr, int data)
{
errno = 0;
return (__sys_ptrace(request, pid, addr, data));
}
diff --git a/lib/libc/sys/read.c b/lib/libc/sys/read.c
index abc37431194d..266763257dd8 100644
--- a/lib/libc/sys/read.c
+++ b/lib/libc/sys/read.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(__sys_read, __read);
#pragma weak read
ssize_t
read(int fd, void *buf, size_t nbytes)
{
return (((ssize_t (*)(int, void *, size_t))
__libc_interposing[INTERPOS_read])(fd, buf, nbytes));
}
diff --git a/lib/libc/sys/readv.c b/lib/libc/sys/readv.c
index 21bfc25c5d84..05c14b5dd030 100644
--- a/lib/libc/sys/readv.c
+++ b/lib/libc/sys/readv.c
@@ -1,48 +1,47 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/uio.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(__sys_readv, __readv);
#pragma weak readv
ssize_t
readv(int fd, const struct iovec *iov, int iovcnt)
{
return (((ssize_t (*)(int, const struct iovec *, int))
__libc_interposing[INTERPOS_readv])(fd, iov, iovcnt));
}
diff --git a/lib/libc/sys/recvfrom.c b/lib/libc/sys/recvfrom.c
index 5f5f95640932..dd5df99b8898 100644
--- a/lib/libc/sys/recvfrom.c
+++ b/lib/libc/sys/recvfrom.c
@@ -1,50 +1,49 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include "libc_private.h"
__weak_reference(__sys_recvfrom, __recvfrom);
#pragma weak recvfrom
ssize_t
recvfrom(int s, void *buf, size_t len, int flags,
struct sockaddr * __restrict from, socklen_t * __restrict fromlen)
{
return (((ssize_t (*)(int, void *, size_t, int,
struct sockaddr *, socklen_t *))
__libc_interposing[INTERPOS_recvfrom])(s, buf, len, flags,
from, fromlen));
}
diff --git a/lib/libc/sys/recvmsg.c b/lib/libc/sys/recvmsg.c
index 44b38aeab2d4..db471f3fd5d3 100644
--- a/lib/libc/sys/recvmsg.c
+++ b/lib/libc/sys/recvmsg.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include "libc_private.h"
__weak_reference(__sys_recvmsg, __recvmsg);
#pragma weak recvmsg
ssize_t
recvmsg(int s, struct msghdr *msg, int flags)
{
return (((int (*)(int, struct msghdr *, int))
__libc_interposing[INTERPOS_recvmsg])(s, msg, flags));
}
diff --git a/lib/libc/sys/select.c b/lib/libc/sys/select.c
index a43e04bd5009..a03079964d1c 100644
--- a/lib/libc/sys/select.c
+++ b/lib/libc/sys/select.c
@@ -1,46 +1,45 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/select.h>
#include "libc_private.h"
__weak_reference(__sys_select, __select);
#pragma weak select
int
select(int n, fd_set *rs, fd_set *ws, fd_set *es, struct timeval *t)
{
return (((int (*)(int, fd_set *, fd_set *, fd_set *, struct timeval *))
__libc_interposing[INTERPOS_select])(n, rs, ws, es, t));
}
diff --git a/lib/libc/sys/sendmsg.c b/lib/libc/sys/sendmsg.c
index f78fbaa258a5..b4f442e02bcb 100644
--- a/lib/libc/sys/sendmsg.c
+++ b/lib/libc/sys/sendmsg.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include "libc_private.h"
__weak_reference(__sys_sendmsg, __sendmsg);
#pragma weak sendmsg
ssize_t
sendmsg(int s, const struct msghdr *msg, int flags)
{
return (((int (*)(int, const struct msghdr *, int))
__libc_interposing[INTERPOS_sendmsg])(s, msg, flags));
}
diff --git a/lib/libc/sys/sendto.c b/lib/libc/sys/sendto.c
index d27d8638e750..2dbf466360cd 100644
--- a/lib/libc/sys/sendto.c
+++ b/lib/libc/sys/sendto.c
@@ -1,50 +1,49 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/socket.h>
#include "libc_private.h"
__weak_reference(__sys_sendto, __sendto);
#pragma weak sendto
ssize_t
sendto(int s, const void *msg, size_t len, int flags,
const struct sockaddr *to, socklen_t tolen)
{
return (((ssize_t (*)(int, const void *, size_t, int,
const struct sockaddr *, socklen_t))
__libc_interposing[INTERPOS_sendto])(s, msg, len, flags,
to, tolen));
}
diff --git a/lib/libc/sys/setcontext.c b/lib/libc/sys/setcontext.c
index ffdd7ebbf890..918377d61e66 100644
--- a/lib/libc/sys/setcontext.c
+++ b/lib/libc/sys/setcontext.c
@@ -1,49 +1,48 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <ucontext.h>
#include "libc_private.h"
__weak_reference(__sys_setcontext, __setcontext);
__sym_compat(setcontext, __impl_setcontext, FBSD_1.0);
__weak_reference(setcontext, __impl_setcontext);
__sym_default(setcontext, setcontext, FBSD_1.2);
#pragma weak setcontext
int
setcontext(const ucontext_t *uc)
{
return (((int (*)(const ucontext_t *))
__libc_interposing[INTERPOS_setcontext])(uc));
}
diff --git a/lib/libc/sys/shm_open.c b/lib/libc/sys/shm_open.c
index 200103442d04..b2c1532133bf 100644
--- a/lib/libc/sys/shm_open.c
+++ b/lib/libc/sys/shm_open.c
@@ -1,167 +1,166 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/filio.h>
#include <sys/mman.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(shm_open, _shm_open);
__weak_reference(shm_open, __sys_shm_open);
#define MEMFD_NAME_PREFIX "memfd:"
int
shm_open(const char *path, int flags, mode_t mode)
{
return (__sys_shm_open2(path, flags | O_CLOEXEC, mode, 0, NULL));
}
int
shm_create_largepage(const char *path, int flags, int psind, int alloc_policy,
mode_t mode)
{
struct shm_largepage_conf slc;
int error, fd, saved_errno;
fd = __sys_shm_open2(path, flags | O_CREAT, mode, SHM_LARGEPAGE, NULL);
if (fd == -1)
return (-1);
memset(&slc, 0, sizeof(slc));
slc.psind = psind;
slc.alloc_policy = alloc_policy;
error = ioctl(fd, FIOSSHMLPGCNF, &slc);
if (error == -1) {
saved_errno = errno;
close(fd);
errno = saved_errno;
return (-1);
}
return (fd);
}
/*
* The path argument is passed to the kernel, but the kernel doesn't currently
* do anything with it. Linux exposes it in linprocfs for debugging purposes
* only, but our kernel currently will not do the same.
*/
int
memfd_create(const char *name, unsigned int flags)
{
char memfd_name[NAME_MAX + 1];
size_t namelen, *pgs, pgsize;
struct shm_largepage_conf slc;
int error, fd, npgs, oflags, pgidx, saved_errno, shmflags;
if (name == NULL) {
errno = EBADF;
return (-1);
}
namelen = strlen(name);
if (namelen + sizeof(MEMFD_NAME_PREFIX) - 1 > NAME_MAX) {
errno = EINVAL;
return (-1);
}
if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB |
MFD_HUGE_MASK)) != 0) {
errno = EINVAL;
return (-1);
}
/* Size specified but no HUGETLB. */
if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) {
errno = EINVAL;
return (-1);
}
/* We've already validated that we're sufficiently sized. */
snprintf(memfd_name, NAME_MAX + 1, "%s%s", MEMFD_NAME_PREFIX, name);
oflags = O_RDWR;
shmflags = 0;
if ((flags & MFD_CLOEXEC) != 0)
oflags |= O_CLOEXEC;
if ((flags & MFD_ALLOW_SEALING) != 0)
shmflags |= SHM_ALLOW_SEALING;
if ((flags & MFD_HUGETLB) != 0)
shmflags |= SHM_LARGEPAGE;
else
shmflags |= SHM_GROW_ON_WRITE;
fd = __sys_shm_open2(SHM_ANON, oflags, 0, shmflags, memfd_name);
if (fd == -1 || (flags & MFD_HUGETLB) == 0)
return (fd);
pgs = NULL;
npgs = getpagesizes(NULL, 0);
if (npgs == -1)
goto clean;
pgs = calloc(npgs, sizeof(size_t));
if (pgs == NULL)
goto clean;
error = getpagesizes(pgs, npgs);
if (error == -1)
goto clean;
pgsize = (size_t)1 << ((flags & MFD_HUGE_MASK) >> MFD_HUGE_SHIFT);
for (pgidx = 0; pgidx < npgs; pgidx++) {
if (pgsize == pgs[pgidx])
break;
}
if (pgidx == npgs) {
errno = EOPNOTSUPP;
goto clean;
}
free(pgs);
pgs = NULL;
memset(&slc, 0, sizeof(slc));
slc.psind = pgidx;
slc.alloc_policy = SHM_LARGEPAGE_ALLOC_DEFAULT;
error = ioctl(fd, FIOSSHMLPGCNF, &slc);
if (error == -1)
goto clean;
return (fd);
clean:
saved_errno = errno;
close(fd);
free(pgs);
errno = saved_errno;
return (-1);
}
diff --git a/lib/libc/sys/sigaction.c b/lib/libc/sys/sigaction.c
index 7352f0a84989..27f003e0eb48 100644
--- a/lib/libc/sys/sigaction.c
+++ b/lib/libc/sys/sigaction.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <signal.h>
#include "libc_private.h"
__weak_reference(__sys_sigaction, __sigaction);
__weak_reference(sigaction, __libc_sigaction);
#pragma weak sigaction
int
sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
{
return (((int (*)(int, const struct sigaction *, struct sigaction *))
__libc_interposing[INTERPOS_sigaction])(sig, act, oact));
}
diff --git a/lib/libc/sys/sigprocmask.c b/lib/libc/sys/sigprocmask.c
index c807d42fb2de..441cd2590c1f 100644
--- a/lib/libc/sys/sigprocmask.c
+++ b/lib/libc/sys/sigprocmask.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <signal.h>
#include "libc_private.h"
__weak_reference(__sys_sigprocmask, __sigprocmask);
__weak_reference(sigprocmask, __libc_sigprocmask);
#pragma weak sigprocmask
int
sigprocmask(int how, const sigset_t *set, sigset_t *oset)
{
return (((int (*)(int, const sigset_t *, sigset_t *))
__libc_interposing[INTERPOS_sigprocmask])(how, set, oset));
}
diff --git a/lib/libc/sys/sigsuspend.c b/lib/libc/sys/sigsuspend.c
index 46d5dc0edf49..1de1e5e4089d 100644
--- a/lib/libc/sys/sigsuspend.c
+++ b/lib/libc/sys/sigsuspend.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <signal.h>
#include "libc_private.h"
__weak_reference(__sys_sigsuspend, __sigsuspend);
__weak_reference(sigsuspend, __libc_sigsuspend);
#pragma weak sigsuspend
int
sigsuspend(const sigset_t *set)
{
return (((int (*)(const sigset_t *))
__libc_interposing[INTERPOS_sigsuspend])(set));
}
diff --git a/lib/libc/sys/sigtimedwait.c b/lib/libc/sys/sigtimedwait.c
index 898f723987e2..945a98e191ca 100644
--- a/lib/libc/sys/sigtimedwait.c
+++ b/lib/libc/sys/sigtimedwait.c
@@ -1,48 +1,47 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <signal.h>
#include "libc_private.h"
__weak_reference(__sys_sigtimedwait, __sigtimedwait);
#pragma weak sigtimedwait
int
sigtimedwait(const sigset_t * __restrict set, siginfo_t * __restrict info,
const struct timespec * __restrict t)
{
return (((int (*)(const sigset_t *, siginfo_t *,
const struct timespec *))
__libc_interposing[INTERPOS_sigtimedwait])(set, info, t));
}
diff --git a/lib/libc/sys/sigwait.c b/lib/libc/sys/sigwait.c
index 2e1551b972ca..3ca16fb24102 100644
--- a/lib/libc/sys/sigwait.c
+++ b/lib/libc/sys/sigwait.c
@@ -1,54 +1,53 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2010 davidxu@freebsd.org
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <signal.h>
#include "libc_private.h"
__weak_reference(__libc_sigwait, __sigwait);
#pragma weak sigwait
int
sigwait(const sigset_t *set, int *sig)
{
return (((int (*)(const sigset_t *, int *))
__libc_interposing[INTERPOS_sigwait])(set, sig));
}
int
__libc_sigwait(const sigset_t *set, int *sig)
{
int ret;
/* POSIX does not allow EINTR to be returned */
do {
ret = __sys_sigwait(set, sig);
} while (ret == EINTR);
return (ret);
}
diff --git a/lib/libc/sys/sigwaitinfo.c b/lib/libc/sys/sigwaitinfo.c
index 4caa52f3398d..06df1f67d0ef 100644
--- a/lib/libc/sys/sigwaitinfo.c
+++ b/lib/libc/sys/sigwaitinfo.c
@@ -1,46 +1,45 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <signal.h>
#include "libc_private.h"
__weak_reference(__sys_sigwaitinfo, __sigwaitinfo);
#pragma weak sigwaitinfo
int
sigwaitinfo(const sigset_t * __restrict set, siginfo_t * __restrict info)
{
return (((int (*)(const sigset_t *, siginfo_t *))
__libc_interposing[INTERPOS_sigwaitinfo])(set, info));
}
diff --git a/lib/libc/sys/stat.c b/lib/libc/sys/stat.c
index 88a4e784adff..262c265d09c9 100644
--- a/lib/libc/sys/stat.c
+++ b/lib/libc/sys/stat.c
@@ -1,41 +1,40 @@
/*-
* Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org> All rights reserved.
* Copyright (c) 2017 M. Warner Losh <imp@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <sys/param.h>
#include <sys/fcntl.h>
#include <sys/syscall.h>
#include <sys/stat.h>
#include <unistd.h>
#include "libc_private.h"
int
stat(const char *path, struct stat *sb)
{
return (__sys_fstatat(AT_FDCWD, path, sb, 0));
}
diff --git a/lib/libc/sys/swapcontext.c b/lib/libc/sys/swapcontext.c
index 1427468e50df..ea1942a31d5e 100644
--- a/lib/libc/sys/swapcontext.c
+++ b/lib/libc/sys/swapcontext.c
@@ -1,51 +1,50 @@
/*
* Copyright (c) 2001 Daniel M. Eischen <deischen@freebsd.org>
* Copyright (c) 2014 The FreeBSD Foundation.
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Neither the name of the author nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/signal.h>
#include <sys/ucontext.h>
#include <errno.h>
#include <stddef.h>
#include "libc_private.h"
__weak_reference(__sys_swapcontext, __swapcontext);
__sym_compat(swapcontext, __impl_swapcontext, FBSD_1.0);
__weak_reference(swapcontext, __impl_swapcontext);
__sym_default(swapcontext, swapcontext, FBSD_1.2);
#pragma weak swapcontext
int
swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
{
return (((int (*)(ucontext_t *, const ucontext_t *))
__libc_interposing[INTERPOS_swapcontext])(oucp, ucp));
}
diff --git a/lib/libc/sys/trivial-vdso_tc.c b/lib/libc/sys/trivial-vdso_tc.c
index 0a9d9fa46173..4a626b7f6cae 100644
--- a/lib/libc/sys/trivial-vdso_tc.c
+++ b/lib/libc/sys/trivial-vdso_tc.c
@@ -1,46 +1,45 @@
/*-
* Copyright (c) 2013 Konstantin Belousov <kib@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <errno.h>
#pragma weak __vdso_gettc
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
return (ENOSYS);
}
#pragma weak __vdso_gettimekeep
int
__vdso_gettimekeep(struct vdso_timekeep **tk)
{
return (ENOSYS);
}
diff --git a/lib/libc/sys/vadvise.c b/lib/libc/sys/vadvise.c
index 09251394253e..44e26a69f9c1 100644
--- a/lib/libc/sys/vadvise.c
+++ b/lib/libc/sys/vadvise.c
@@ -1,44 +1,43 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 SRI International
* All rights reserved.
*
* This software was developed by SRI International and the University of
* Cambridge Computer Laboratory (Department of Computer Science and
* Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the
* DARPA SSITH research programme.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/errno.h>
int vadvise(int);
int
vadvise(int arg __unused)
{
return (EINVAL);
}
diff --git a/lib/libc/sys/wait4.c b/lib/libc/sys/wait4.c
index 9efabec529d7..2650b8932869 100644
--- a/lib/libc/sys/wait4.c
+++ b/lib/libc/sys/wait4.c
@@ -1,46 +1,45 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "libc_private.h"
__weak_reference(__sys_wait4, __wait4);
#pragma weak wait4
pid_t
wait4(pid_t pid, int *status, int options, struct rusage *ru)
{
return (((pid_t (*)(pid_t, int *, int, struct rusage *))
__libc_interposing[INTERPOS_wait4])(pid, status, options, ru));
}
diff --git a/lib/libc/sys/wait6.c b/lib/libc/sys/wait6.c
index 1bba04200e69..f2610813ee2b 100644
--- a/lib/libc/sys/wait6.c
+++ b/lib/libc/sys/wait6.c
@@ -1,49 +1,48 @@
/*
* Copyright (c) 2015 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include "libc_private.h"
__weak_reference(__sys_wait6, __wait6);
#pragma weak wait6
pid_t
wait6(idtype_t idtype, id_t id, int *status, int options, struct __wrusage *ru,
siginfo_t *infop)
{
return (((pid_t (*)(idtype_t, id_t, int *, int, struct __wrusage *,
siginfo_t *))__libc_interposing[INTERPOS_wait6])(idtype, id,
status, options, ru, infop));
}
diff --git a/lib/libc/sys/write.c b/lib/libc/sys/write.c
index 461975cd72fb..b974dd055a84 100644
--- a/lib/libc/sys/write.c
+++ b/lib/libc/sys/write.c
@@ -1,47 +1,46 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(__sys_write, __write);
#pragma weak write
ssize_t
write(int fd, const void *buf, size_t nbytes)
{
return (((ssize_t (*)(int, const void *, size_t))
__libc_interposing[INTERPOS_write])(fd, buf, nbytes));
}
diff --git a/lib/libc/sys/writev.c b/lib/libc/sys/writev.c
index 4d91d4dec95a..a56d9389ddcc 100644
--- a/lib/libc/sys/writev.c
+++ b/lib/libc/sys/writev.c
@@ -1,48 +1,47 @@
/*
* Copyright (c) 2014 The FreeBSD Foundation.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice(s), this list of conditions and the following disclaimer as
* the first lines of this file unmodified other than the possible
* addition of one or more copyright notices.
* 2. Redistributions in binary form must reproduce the above copyright
* notice(s), this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <sys/uio.h>
#include <unistd.h>
#include "libc_private.h"
__weak_reference(__sys_writev, __writev);
#pragma weak writev
ssize_t
writev(int fd, const struct iovec *iov, int iovcnt)
{
return (((ssize_t (*)(int, const struct iovec *, int))
__libc_interposing[INTERPOS_writev])(fd, iov, iovcnt));
}
diff --git a/lib/libc/tests/gen/arc4random_test.c b/lib/libc/tests/gen/arc4random_test.c
index c3ec207077d3..e96ebdc6c6ca 100644
--- a/lib/libc/tests/gen/arc4random_test.c
+++ b/lib/libc/tests/gen/arc4random_test.c
@@ -1,87 +1,86 @@
/*-
* Copyright (c) 2011 David Schultz
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
/*
* BUFSIZE is the number of bytes of rc4 output to compare. The probability
* that this test fails spuriously is 2**(-BUFSIZE * 8).
*/
#define BUFSIZE 8
/*
* Test whether arc4random_buf() returns the same sequence of bytes in both
* parent and child processes. (Hint: It shouldn't.)
*/
ATF_TC_WITHOUT_HEAD(test_arc4random);
ATF_TC_BODY(test_arc4random, tc)
{
struct shared_page {
char parentbuf[BUFSIZE];
char childbuf[BUFSIZE];
} *page;
pid_t pid;
char c;
page = mmap(NULL, sizeof(struct shared_page), PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0);
ATF_REQUIRE_MSG(page != MAP_FAILED, "mmap failed; errno=%d", errno);
arc4random_buf(&c, 1);
pid = fork();
ATF_REQUIRE(0 <= pid);
if (pid == 0) {
/* child */
arc4random_buf(page->childbuf, BUFSIZE);
exit(0);
} else {
/* parent */
int status;
arc4random_buf(page->parentbuf, BUFSIZE);
wait(&status);
}
ATF_CHECK_MSG(memcmp(page->parentbuf, page->childbuf, BUFSIZE) != 0,
"sequences are the same");
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, test_arc4random);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/dir2_test.c b/lib/libc/tests/gen/dir2_test.c
index 5c9604856f11..4ec5a1759d06 100644
--- a/lib/libc/tests/gen/dir2_test.c
+++ b/lib/libc/tests/gen/dir2_test.c
@@ -1,187 +1,186 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2017 Spectra Logic Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test cases for operations on DIR objects:
* opendir, readdir, seekdir, telldir, closedir, etc
*/
-#include <sys/cdefs.h>
#include <dirent.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <atf-c.h>
ATF_TC(telldir_after_seekdir);
ATF_TC_HEAD(telldir_after_seekdir, tc)
{
atf_tc_set_md_var(tc, "descr", "Calling telldir(3) after seekdir(3) "
"should return the argument passed to seekdir.");
}
ATF_TC_BODY(telldir_after_seekdir, tc)
{
const int NUMFILES = 1000;
char template[] = "dXXXXXX";
char *tmpdir;
int i, dirfd;
DIR *dirp;
struct dirent *de;
long beginning, middle, end, td;
/* Create a temporary directory */
tmpdir = mkdtemp(template);
ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp failed");
dirfd = open(tmpdir, O_RDONLY | O_DIRECTORY);
ATF_REQUIRE(dirfd > 0);
/*
* Fill it with files. Must be > 128 to ensure that the directory
* can't fit within a single page
*/
for (i = 0; i < NUMFILES; i = i+1) {
int fd;
char filename[16];
snprintf(filename, sizeof(filename), "%d", i);
fd = openat(dirfd, filename, O_WRONLY | O_CREAT, 0600);
ATF_REQUIRE(fd > 0);
close(fd);
}
/* Get some directory bookmarks in various locations */
dirp = fdopendir(dirfd);
ATF_REQUIRE_MSG(dirfd >= 0, "fdopendir failed");
beginning = telldir(dirp);
for (i = 0; i < NUMFILES / 2; i = i+1) {
de = readdir(dirp);
ATF_REQUIRE_MSG(de != NULL, "readdir failed");
}
middle = telldir(dirp);
for (; i < NUMFILES - 1; i = i+1) {
de = readdir(dirp);
ATF_REQUIRE_MSG(de != NULL, "readdir failed");
}
end = telldir(dirp);
/*
* Seekdir to each bookmark, check the telldir after seekdir condition,
* and check that the bookmark is valid by reading another directory
* entry.
*/
seekdir(dirp, beginning);
td = telldir(dirp);
ATF_CHECK_EQ(beginning, td);
ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
seekdir(dirp, middle);
td = telldir(dirp);
ATF_CHECK_EQ(middle, td);
ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
seekdir(dirp, end);
td = telldir(dirp);
ATF_CHECK_EQ(end, td);
ATF_REQUIRE_MSG(NULL != readdir(dirp), "invalid directory index");
closedir(dirp);
}
ATF_TC(telldir_at_end_of_block);
ATF_TC_HEAD(telldir_at_end_of_block, tc)
{
atf_tc_set_md_var(tc, "descr", "Calling telldir(3) after readdir(3) read the last entry in the block should return a valid location");
}
ATF_TC_BODY(telldir_at_end_of_block, tc)
{
/* For UFS and ZFS, blocks roll over at 128 directory entries. */
const int NUMFILES = 129;
char template[] = "dXXXXXX";
char *tmpdir;
int i, dirfd;
DIR *dirp;
struct dirent *de;
long td;
char last_filename[16];
/* Create a temporary directory */
tmpdir = mkdtemp(template);
ATF_REQUIRE_MSG(tmpdir != NULL, "mkdtemp failed");
dirfd = open(tmpdir, O_RDONLY | O_DIRECTORY);
ATF_REQUIRE(dirfd > 0);
/*
* Fill it with files. Must be > 128 to ensure that the directory
* can't fit within a single page. The "-2" accounts for "." and ".."
*/
for (i = 0; i < NUMFILES - 2; i = i+1) {
int fd;
char filename[16];
snprintf(filename, sizeof(filename), "%d", i);
fd = openat(dirfd, filename, O_WRONLY | O_CREAT, 0600);
ATF_REQUIRE(fd > 0);
close(fd);
}
/* Read all entries within the first page */
dirp = fdopendir(dirfd);
ATF_REQUIRE_MSG(dirfd >= 0, "fdopendir failed");
for (i = 0; i < NUMFILES - 1; i = i + 1)
ATF_REQUIRE_MSG(readdir(dirp) != NULL, "readdir failed");
/* Call telldir at the end of a page */
td = telldir(dirp);
/* Read the last entry */
de = readdir(dirp);
ATF_REQUIRE_MSG(de != NULL, "readdir failed");
strlcpy(last_filename, de->d_name, sizeof(last_filename));
/* Seek back to the bookmark. readdir() should return the last entry */
seekdir(dirp, td);
de = readdir(dirp);
ATF_REQUIRE_STREQ_MSG(last_filename, de->d_name,
"seekdir went to the wrong directory position");
closedir(dirp);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, telldir_after_seekdir);
ATF_TP_ADD_TC(tp, telldir_at_end_of_block);
return atf_no_error();
}
diff --git a/lib/libc/tests/gen/dlopen_empty_test.c b/lib/libc/tests/gen/dlopen_empty_test.c
index 1b48fd9d8d33..6fb3bf8d8343 100644
--- a/lib/libc/tests/gen/dlopen_empty_test.c
+++ b/lib/libc/tests/gen/dlopen_empty_test.c
@@ -1,95 +1,94 @@
/*-
* Copyright (c) 2016 Maksym Sobolyev
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/stat.h>
#include <dlfcn.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <atf-c.h>
static const char *funname;
static char *soname;
static void
sigsegv_handler(int sig __unused)
{
unlink(soname);
free(soname);
atf_tc_fail("got SIGSEGV in the %s(3)", funname);
}
ATF_TC(dlopen_empty_test);
ATF_TC_HEAD(dlopen_empty_test, tc)
{
atf_tc_set_md_var(tc, "descr", "Tests the dlopen() of an empty file "
"returns an error");
}
ATF_TC_BODY(dlopen_empty_test, tc)
{
char tempname[] = "/tmp/temp.XXXXXX";
char *fname;
int fd;
void *dlh;
struct sigaction act, oact;
fname = mktemp(tempname);
ATF_REQUIRE_MSG(fname != NULL, "mktemp failed; errno=%d", errno);
asprintf(&soname, "%s.so", fname);
ATF_REQUIRE_MSG(soname != NULL, "asprintf failed; errno=%d", ENOMEM);
fd = open(soname, O_WRONLY | O_CREAT | O_TRUNC, DEFFILEMODE);
ATF_REQUIRE_MSG(fd != -1, "open(\"%s\") failed; errno=%d", soname, errno);
close(fd);
act.sa_handler = sigsegv_handler;
act.sa_flags = 0;
sigemptyset(&act.sa_mask);
ATF_CHECK_MSG(sigaction(SIGSEGV, &act, &oact) != -1,
"sigaction() failed");
funname = "dlopen";
dlh = dlopen(soname, RTLD_LAZY);
if (dlh != NULL) {
funname = "dlclose";
dlclose(dlh);
}
ATF_REQUIRE_MSG(dlh == NULL, "dlopen(\"%s\") did not fail", soname);
unlink(soname);
free(soname);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, dlopen_empty_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/fmtcheck_test.c b/lib/libc/tests/gen/fmtcheck_test.c
index 0df30cee96f0..27a12217e81e 100644
--- a/lib/libc/tests/gen/fmtcheck_test.c
+++ b/lib/libc/tests/gen/fmtcheck_test.c
@@ -1,103 +1,102 @@
/* $NetBSD: tfmtcheck.c,v 1.3 2008/04/28 20:23:04 martin Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code was contributed to The NetBSD Foundation by Allen Briggs.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <atf-c.h>
struct test_fmt {
char *fmt1;
char *fmt2;
int correct;
} test_fmts[] = {
{ "%d", "%d", 1 },
{ "%2d", "%2.2d", 1 },
{ "%x", "%d", 1 },
{ "%u", "%d", 1 },
{ "%03d", "%d", 1 },
{ "%-2d", "%d", 1 },
{ "%d", "%-12.1d", 1 },
{ "%d", "%-01.3d", 1 },
{ "%X", "%-01.3d", 1 },
{ "%D", "%ld", 1 },
{ "%s", "%s", 1 },
{ "%s", "This is a %s test", 1 },
{ "Hi, there. This is a %s test", "%s", 1 },
{ "%d", "%s", 2 },
{ "%e", "%s", 2 },
{ "%r", "%d", 2 },
{ "%*.2d", "%*d", 1 },
{ "%2.*d", "%*d", 2 },
{ "%*d", "%*d", 1 },
{ "%-3", "%d", 2 },
{ "%d %s", "%d", 2 },
{ "%*.*.*d", "%*.*.*d", 2 },
{ "%d", "%d %s", 1 },
{ "%40s", "%20s", 1 },
{ "%x %x %x", "%o %u %d", 1 },
{ "%o %u %d", "%x %x %X", 1 },
{ "%#o %u %#-d", "%x %#x %X", 1 },
{ "%qd", "%llx", 1 },
{ "%%", "%llx", 1 },
{ "%p %30s %#llx %-10.*e", "This number %lu%% and string %s has %qd numbers and %.*g floats", 1 },
};
ATF_TC_WITHOUT_HEAD(fmtcheck_test);
ATF_TC_BODY(fmtcheck_test, tc)
{
int i;
const char *f, *cf, *f1, *f2;
for (i = 0; i < nitems(test_fmts); i++) {
f1 = test_fmts[i].fmt1;
f2 = test_fmts[i].fmt2;
f = fmtcheck(f1, f2);
if (test_fmts[i].correct == 1)
cf = f1;
else
cf = f2;
ATF_CHECK_MSG(f == cf,
"Test %d: (%s) vs. (%s) failed "
"(should have returned %s)", i + 1, f1, f2,
(test_fmts[i].correct == 1) ? "1st" : "2nd");
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, fmtcheck_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/fmtmsg_test.c b/lib/libc/tests/gen/fmtmsg_test.c
index 7ab6a335c8e2..30a5156cdcc8 100644
--- a/lib/libc/tests/gen/fmtmsg_test.c
+++ b/lib/libc/tests/gen/fmtmsg_test.c
@@ -1,250 +1,249 @@
/*-
* Copyright (c) 2012 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <fmtmsg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
static char *run_test(long classification, const char *label, int severity,
const char *text, const char *action, const char *tag);
struct testcase {
long classification;
const char *label;
int severity;
const char *text;
const char *action;
const char *tag;
const char *msgverb;
const char *result;
} testcases[] = {
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
NULL,
"BSD:ls: ERROR: illegal option -- z\n"
"TO FIX: refer to manual BSD:ls:001\n"
},
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
"text:severity:action:tag",
"illegal option -- z: ERROR\n"
"TO FIX: refer to manual BSD:ls:001\n"
},
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
"text",
"illegal option -- z\n"
},
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
"severity:text",
"ERROR: illegal option -- z\n"
},
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
"ignore me",
"BSD:ls: ERROR: illegal option -- z\n"
"TO FIX: refer to manual BSD:ls:001\n"
},
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
"tag:severity:text:nothing:action",
"BSD:ls: ERROR: illegal option -- z\n"
"TO FIX: refer to manual BSD:ls:001\n"
},
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
"",
"BSD:ls: ERROR: illegal option -- z\n"
"TO FIX: refer to manual BSD:ls:001\n"
},
{
MM_UTIL | MM_PRINT, MM_NULLLBL, MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
NULL,
"ERROR: illegal option -- z\n"
"TO FIX: refer to manual BSD:ls:001\n"
},
{
MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR,
"illegal option -- z", MM_NULLACT, MM_NULLTAG,
NULL,
"BSD:ls: ERROR: illegal option -- z\n"
},
{
MM_UTIL | MM_NULLMC, "BSD:ls", MM_ERROR,
"illegal option -- z", "refer to manual", "BSD:ls:001",
NULL,
""
},
{
MM_APPL | MM_PRINT, "ABCDEFGHIJ:abcdefghijklmn", MM_INFO,
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"refer to manual", "ABCDEFGHIJ:abcdefghijklmn:001",
NULL,
"ABCDEFGHIJ:abcdefghijklmn: INFO: "
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n"
"TO FIX: refer to manual ABCDEFGHIJ:abcdefghijklmn:001\n"
},
{
MM_OPSYS | MM_PRINT, "TEST:test", MM_HALT,
"failed", "nothing can help me", "NOTHING",
NULL,
"TEST:test: HALT: failed\n"
"TO FIX: nothing can help me NOTHING\n"
},
{
MM_OPSYS | MM_PRINT, "TEST:test", MM_WARNING,
"failed", "nothing can help me", "NOTHING",
NULL,
"TEST:test: WARNING: failed\n"
"TO FIX: nothing can help me NOTHING\n"
},
{
MM_OPSYS | MM_PRINT, "TEST:test", MM_NOSEV,
"failed", "nothing can help me", "NOTHING",
NULL,
"TEST:test: failed\n"
"TO FIX: nothing can help me NOTHING\n"
}
};
static char *
run_test(long classification, const char *label, int severity,
const char *text, const char *action, const char *tag)
{
int pip[2];
pid_t pid, wpid;
char *result, *p;
size_t resultsize;
ssize_t n;
int status;
if (pipe(pip) == -1)
err(2, "pipe");
pid = fork();
if (pid == -1)
err(2, "fork");
if (pid == 0) {
close(pip[0]);
if (pip[1] != STDERR_FILENO &&
dup2(pip[1], STDERR_FILENO) == -1)
_exit(2);
if (fmtmsg(classification, label, severity, text, action, tag)
!= MM_OK)
_exit(1);
else
_exit(0);
}
close(pip[1]);
resultsize = 1024;
result = malloc(resultsize);
p = result;
while ((n = read(pip[0], p, result + resultsize - p - 1)) != 0) {
if (n == -1) {
if (errno == EINTR)
continue;
else
err(2, "read");
}
p += n;
if (result + resultsize == p - 1) {
resultsize *= 2;
result = realloc(result, resultsize);
if (result == NULL)
err(2, "realloc");
}
}
if (memchr(result, '\0', p - result) != NULL) {
free(result);
return (NULL);
}
*p = '\0';
close(pip[0]);
while ((wpid = waitpid(pid, &status, 0)) == -1 && errno == EINTR)
;
if (wpid == -1)
err(2, "waitpid");
if (status != 0) {
free(result);
return (NULL);
}
return (result);
}
ATF_TC_WITHOUT_HEAD(fmtmsg_test);
ATF_TC_BODY(fmtmsg_test, tc)
{
char *result;
struct testcase *t;
int i;
for (i = 0; i < nitems(testcases); i++) {
t = &testcases[i];
if (t->msgverb != NULL)
setenv("MSGVERB", t->msgverb, 1);
else
unsetenv("MSGVERB");
result = run_test(t->classification, t->label, t->severity,
t->text, t->action, t->tag);
ATF_CHECK_MSG(result != NULL, "testcase %d failed", i + 1);
if (result != NULL)
ATF_CHECK_MSG(strcmp(result, t->result) == 0,
"results for testcase %d didn't match; "
"`%s` != `%s`", i + 1, result, t->result);
free(result);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, fmtmsg_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/fnmatch_test.c b/lib/libc/tests/gen/fnmatch_test.c
index abb7308f021b..6cdf5f2a05fa 100644
--- a/lib/libc/tests/gen/fnmatch_test.c
+++ b/lib/libc/tests/gen/fnmatch_test.c
@@ -1,186 +1,185 @@
/*-
* Copyright (c) 2010 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
#include "fnmatch_testcases.h"
static const char *
flags_to_string(int flags)
{
static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME,
FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 };
static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
static char result[sizeof(flagnames) + 3 * sizeof(int) + 2];
char *p;
size_t i, len;
const char *fp;
p = result;
fp = flagnames;
for (i = 0; flagvalues[i] != 0; i++) {
len = strlen(fp);
if (flags & flagvalues[i]) {
if (p != result)
*p++ = '|';
memcpy(p, fp, len);
p += len;
flags &= ~flagvalues[i];
}
fp += len + 1;
}
if (p == result)
memcpy(p, "0", 2);
else if (flags != 0)
sprintf(p, "%d", flags);
else
*p = '\0';
return result;
}
ATF_TC_WITHOUT_HEAD(fnmatch_test);
ATF_TC_BODY(fnmatch_test, tc)
{
size_t i;
int flags, result;
struct testcase *t;
for (i = 0; i < nitems(testcases); i++) {
t = &testcases[i];
flags = t->flags;
do {
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
if (strchr(t->pattern, '\\') == NULL &&
!(flags & FNM_NOESCAPE)) {
flags |= FNM_NOESCAPE;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if (strchr(t->pattern, '\\') != NULL &&
strchr(t->string, '\\') == NULL &&
t->result == FNM_NOMATCH &&
!(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) {
flags |= FNM_NOESCAPE;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if ((t->string[0] != '.' || t->pattern[0] == '.' ||
t->result == FNM_NOMATCH) &&
!(flags & (FNM_PATHNAME | FNM_PERIOD))) {
flags |= FNM_PERIOD;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if ((strchr(t->string, '/') == NULL ||
t->result == FNM_NOMATCH) &&
!(flags & FNM_PATHNAME)) {
flags |= FNM_PATHNAME;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
strstr(t->string, "/.") == NULL) ||
t->result == FNM_NOMATCH) &&
flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) {
flags |= FNM_PERIOD;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
strchr(t->string, '/') == NULL) ||
t->result == FNM_NOMATCH) &&
!(flags & (FNM_PATHNAME | FNM_PERIOD))) {
flags |= FNM_PATHNAME | FNM_PERIOD;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if ((strchr(t->string, '/') == NULL || t->result == 0)
&& !(flags & FNM_LEADING_DIR)) {
flags |= FNM_LEADING_DIR;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if (t->result == 0 && !(flags & FNM_CASEFOLD)) {
flags |= FNM_CASEFOLD;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
if (strchr(t->pattern, '\\') == NULL &&
t->result == 0 &&
!(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) {
flags |= FNM_NOESCAPE | FNM_CASEFOLD;
result = fnmatch(t->pattern, t->string, flags);
if (result != t->result)
break;
flags = t->flags;
}
} while (0);
ATF_CHECK(result == t->result);
if (result == t->result)
printf("fnmatch(\"%s\", \"%s\", %s) == %d\n",
t->pattern, t->string, flags_to_string(flags), result);
else
printf("fnmatch(\"%s\", \"%s\", %s) != %d (was %d)\n",
t->pattern, t->string, flags_to_string(flags),
t->result, result);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, fnmatch_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/fnmatch_testcases.h b/lib/libc/tests/gen/fnmatch_testcases.h
index d205605826cf..196160a4801b 100644
--- a/lib/libc/tests/gen/fnmatch_testcases.h
+++ b/lib/libc/tests/gen/fnmatch_testcases.h
@@ -1,174 +1,173 @@
/*-
* Copyright (c) 2010 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <fnmatch.h>
struct testcase {
const char *pattern;
const char *string;
int flags;
int result;
} testcases[] = {
{ "", "", 0, 0 },
{ "a", "a", 0, 0 },
{ "a", "b", 0, FNM_NOMATCH },
{ "a", "A", 0, FNM_NOMATCH },
{ "*", "a", 0, 0 },
{ "*", "aa", 0, 0 },
{ "*a", "a", 0, 0 },
{ "*a", "b", 0, FNM_NOMATCH },
{ "*a*", "b", 0, FNM_NOMATCH },
{ "*a*b*", "ab", 0, 0 },
{ "*a*b*", "qaqbq", 0, 0 },
{ "*a*bb*", "qaqbqbbq", 0, 0 },
{ "*a*bc*", "qaqbqbcq", 0, 0 },
{ "*a*bb*", "qaqbqbb", 0, 0 },
{ "*a*bc*", "qaqbqbc", 0, 0 },
{ "*a*bb", "qaqbqbb", 0, 0 },
{ "*a*bc", "qaqbqbc", 0, 0 },
{ "*a*bb", "qaqbqbbq", 0, FNM_NOMATCH },
{ "*a*bc", "qaqbqbcq", 0, FNM_NOMATCH },
{ "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH },
{ "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0 },
{ "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0 },
{ ".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH },
{ ".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0 },
{ ".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0 },
{ "*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH },
{ "??????????*", "123456789", 0, FNM_NOMATCH },
{ "*??????????", "123456789", 0, FNM_NOMATCH },
{ "*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0 },
{ "??????????*", "1234567890", 0, 0 },
{ "*??????????", "1234567890", 0, 0 },
{ "*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0 },
{ "??????????*", "12345678901", 0, 0 },
{ "*??????????", "12345678901", 0, 0 },
{ "[x]", "x", 0, 0 },
{ "[*]", "*", 0, 0 },
{ "[?]", "?", 0, 0 },
{ "[", "[", 0, 0 },
{ "[[]", "[", 0, 0 },
{ "[[]", "x", 0, FNM_NOMATCH },
{ "[*]", "", 0, FNM_NOMATCH },
{ "[*]", "x", 0, FNM_NOMATCH },
{ "[?]", "x", 0, FNM_NOMATCH },
{ "*[*]*", "foo*foo", 0, 0 },
{ "*[*]*", "foo", 0, FNM_NOMATCH },
{ "[0-9]", "0", 0, 0 },
{ "[0-9]", "5", 0, 0 },
{ "[0-9]", "9", 0, 0 },
{ "[0-9]", "/", 0, FNM_NOMATCH },
{ "[0-9]", ":", 0, FNM_NOMATCH },
{ "[0-9]", "*", 0, FNM_NOMATCH },
{ "[!0-9]", "0", 0, FNM_NOMATCH },
{ "[!0-9]", "5", 0, FNM_NOMATCH },
{ "[!0-9]", "9", 0, FNM_NOMATCH },
{ "[!0-9]", "/", 0, 0 },
{ "[!0-9]", ":", 0, 0 },
{ "[!0-9]", "*", 0, 0 },
{ "*[0-9]", "a0", 0, 0 },
{ "*[0-9]", "a5", 0, 0 },
{ "*[0-9]", "a9", 0, 0 },
{ "*[0-9]", "a/", 0, FNM_NOMATCH },
{ "*[0-9]", "a:", 0, FNM_NOMATCH },
{ "*[0-9]", "a*", 0, FNM_NOMATCH },
{ "*[!0-9]", "a0", 0, FNM_NOMATCH },
{ "*[!0-9]", "a5", 0, FNM_NOMATCH },
{ "*[!0-9]", "a9", 0, FNM_NOMATCH },
{ "*[!0-9]", "a/", 0, 0 },
{ "*[!0-9]", "a:", 0, 0 },
{ "*[!0-9]", "a*", 0, 0 },
{ "*[0-9]", "a00", 0, 0 },
{ "*[0-9]", "a55", 0, 0 },
{ "*[0-9]", "a99", 0, 0 },
{ "*[0-9]", "a0a0", 0, 0 },
{ "*[0-9]", "a5a5", 0, 0 },
{ "*[0-9]", "a9a9", 0, 0 },
{ "\\*", "*", 0, 0 },
{ "\\?", "?", 0, 0 },
{ "\\[x]", "[x]", 0, 0 },
{ "\\[", "[", 0, 0 },
{ "\\\\", "\\", 0, 0 },
{ "*\\**", "foo*foo", 0, 0 },
{ "*\\**", "foo", 0, FNM_NOMATCH },
{ "*\\\\*", "foo\\foo", 0, 0 },
{ "*\\\\*", "foo", 0, FNM_NOMATCH },
{ "\\(", "(", 0, 0 },
{ "\\a", "a", 0, 0 },
{ "\\*", "a", 0, FNM_NOMATCH },
{ "\\?", "a", 0, FNM_NOMATCH },
{ "\\*", "\\*", 0, FNM_NOMATCH },
{ "\\?", "\\?", 0, FNM_NOMATCH },
{ "\\[x]", "\\[x]", 0, FNM_NOMATCH },
{ "\\[x]", "\\x", 0, FNM_NOMATCH },
{ "\\[", "\\[", 0, FNM_NOMATCH },
{ "\\(", "\\(", 0, FNM_NOMATCH },
{ "\\a", "\\a", 0, FNM_NOMATCH },
{ "\\", "\\", 0, FNM_NOMATCH },
{ "\\", "", 0, FNM_NOMATCH },
{ "\\*", "\\*", FNM_NOESCAPE, 0 },
{ "\\?", "\\?", FNM_NOESCAPE, 0 },
{ "\\", "\\", FNM_NOESCAPE, 0 },
{ "\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH },
{ "\\\\", "\\\\", FNM_NOESCAPE, 0 },
{ "*\\*", "foo\\foo", FNM_NOESCAPE, 0 },
{ "*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH },
{ "*", ".", FNM_PERIOD, FNM_NOMATCH },
{ "?", ".", FNM_PERIOD, FNM_NOMATCH },
{ ".*", ".", 0, 0 },
{ ".*", "..", 0, 0 },
{ ".*", ".a", 0, 0 },
{ "[0-9]", ".", FNM_PERIOD, FNM_NOMATCH },
{ "a*", "a.", 0, 0 },
{ "a/a", "a/a", FNM_PATHNAME, 0 },
{ "a/*", "a/a", FNM_PATHNAME, 0 },
{ "*/a", "a/a", FNM_PATHNAME, 0 },
{ "*/*", "a/a", FNM_PATHNAME, 0 },
{ "a*b/*", "abbb/x", FNM_PATHNAME, 0 },
{ "a*b/*", "abbb/.x", FNM_PATHNAME, 0 },
{ "*", "a/a", FNM_PATHNAME, FNM_NOMATCH },
{ "*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH },
{ "b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH },
{ "b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH },
{ "b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0 },
{ "b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0 },
{ "a", "A", FNM_CASEFOLD, 0 },
{ "A", "a", FNM_CASEFOLD, 0 },
{ "[a]", "A", FNM_CASEFOLD, 0 },
{ "[A]", "a", FNM_CASEFOLD, 0 },
{ "a", "b", FNM_CASEFOLD, FNM_NOMATCH },
{ "a", "a/b", FNM_PATHNAME, FNM_NOMATCH },
{ "*", "a/b", FNM_PATHNAME, FNM_NOMATCH },
{ "*b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
{ "a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
{ "*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
{ "*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
{ "*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0 },
{ "*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH },
{ "*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH },
{ "a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH },
};
diff --git a/lib/libc/tests/gen/ftw_test.c b/lib/libc/tests/gen/ftw_test.c
index d6fe56f6499d..3d2cf3446dee 100644
--- a/lib/libc/tests/gen/ftw_test.c
+++ b/lib/libc/tests/gen/ftw_test.c
@@ -1,125 +1,124 @@
/*-
* Copyright (c) 2012 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Limited test program for nftw() as specified by IEEE Std. 1003.1-2008.
*/
-#include <sys/cdefs.h>
#include <sys/wait.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <ftw.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <spawn.h>
#include <unistd.h>
#include <atf-c.h>
extern char **environ;
static char template[] = "testftw.XXXXXXXXXX";
static char dir[PATH_MAX];
static int ftwflags;
static int
cb(const char *path, const struct stat *st, int type, struct FTW *f)
{
switch (type) {
case FTW_D:
if ((ftwflags & FTW_DEPTH) == 0)
return (0);
break;
case FTW_DP:
if ((ftwflags & FTW_DEPTH) != 0)
return (0);
break;
case FTW_SL:
if ((ftwflags & FTW_PHYS) != 0)
return (0);
break;
}
ATF_CHECK_MSG(false,
"unexpected path=%s type=%d f.level=%d\n",
path, type, f->level);
return (0);
}
ATF_TC_WITHOUT_HEAD(ftw_test);
ATF_TC_BODY(ftw_test, tc)
{
int fd;
ATF_REQUIRE_MSG(mkdtemp(template) != NULL, "mkdtemp failed");
/* XXX: the path needs to be absolute for the 0/FTW_DEPTH testcases */
ATF_REQUIRE_MSG(realpath(template, dir) != NULL,
"realpath failed; errno=%d", errno);
fd = open(dir, O_DIRECTORY|O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed; errno=%d", errno);
ATF_REQUIRE_MSG(mkdirat(fd, "d1", 0777) == 0,
"mkdirat failed; errno=%d", errno);
ATF_REQUIRE_MSG(symlinkat(dir, fd, "d1/looper") == 0,
"symlinkat failed; errno=%d", errno);
printf("ftwflags=FTW_PHYS\n");
ftwflags = FTW_PHYS;
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
"nftw FTW_PHYS failed; errno=%d", errno);
printf("ftwflags=FTW_PHYS|FTW_DEPTH\n");
ftwflags = FTW_PHYS|FTW_DEPTH;
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
"nftw FTW_PHYS|FTW_DEPTH failed; errno=%d", errno);
printf("ftwflags=0\n");
ftwflags = 0;
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
"nftw 0 failed; errno=%d", errno);
printf("ftwflags=FTW_DEPTH\n");
ftwflags = FTW_DEPTH;
ATF_REQUIRE_MSG(nftw(dir, cb, 10, ftwflags) != -1,
"nftw FTW_DEPTH failed; errno=%d", errno);
close(fd);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, ftw_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/getentropy_test.c b/lib/libc/tests/gen/getentropy_test.c
index a79ef0628f97..156d3a94a7de 100644
--- a/lib/libc/tests/gen/getentropy_test.c
+++ b/lib/libc/tests/gen/getentropy_test.c
@@ -1,85 +1,84 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(getentropy_count);
ATF_TC_BODY(getentropy_count, tc)
{
char buf[2];
int ret;
/* getentropy(2) does not modify buf past the requested length */
buf[1] = 0x7C;
ret = getentropy(buf, 1);
ATF_REQUIRE_EQ(ret, 0);
ATF_REQUIRE_EQ(buf[1], 0x7C);
}
ATF_TC_WITHOUT_HEAD(getentropy_fault);
ATF_TC_BODY(getentropy_fault, tc)
{
int ret;
ret = getentropy(NULL, 1);
ATF_REQUIRE_EQ(ret, -1);
ATF_REQUIRE_EQ(errno, EFAULT);
}
ATF_TC_WITHOUT_HEAD(getentropy_sizes);
ATF_TC_BODY(getentropy_sizes, tc)
{
char buf[512];
ATF_REQUIRE_EQ(getentropy(buf, sizeof(buf)), -1);
ATF_REQUIRE_EQ(errno, EIO);
ATF_REQUIRE_EQ(getentropy(buf, 257), -1);
ATF_REQUIRE_EQ(errno, EIO);
/* Smaller sizes always succeed: */
ATF_REQUIRE_EQ(getentropy(buf, 256), 0);
ATF_REQUIRE_EQ(getentropy(buf, 128), 0);
ATF_REQUIRE_EQ(getentropy(buf, 0), 0);
}
ATF_TP_ADD_TCS(tp)
{
signal(SIGSYS, SIG_IGN);
ATF_TP_ADD_TC(tp, getentropy_count);
ATF_TP_ADD_TC(tp, getentropy_fault);
ATF_TP_ADD_TC(tp, getentropy_sizes);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/getmntinfo_test.c b/lib/libc/tests/gen/getmntinfo_test.c
index 2284a6146556..06e1091d8a15 100644
--- a/lib/libc/tests/gen/getmntinfo_test.c
+++ b/lib/libc/tests/gen/getmntinfo_test.c
@@ -1,84 +1,83 @@
/*-
* Copyright (c) 2017 Conrad Meyer <cem@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Limited test program for getmntinfo(3), a non-standard BSDism.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mount.h>
#include <sys/ucred.h>
#include <errno.h>
#include <atf-c.h>
static void
check_mntinfo(struct statfs *mntinfo, int n)
{
int i;
for (i = 0; i < n; i++) {
ATF_REQUIRE_MSG(mntinfo[i].f_version == STATFS_VERSION, "%ju",
(uintmax_t)mntinfo[i].f_version);
ATF_REQUIRE(mntinfo[i].f_namemax <= sizeof(mntinfo[0].f_mntonname));
}
}
ATF_TC_WITHOUT_HEAD(getmntinfo_test);
ATF_TC_BODY(getmntinfo_test, tc)
{
int nmnts;
struct statfs *mntinfo;
/* Test bogus mode */
nmnts = getmntinfo(&mntinfo, 199);
ATF_REQUIRE_MSG(nmnts == 0 && errno == EINVAL,
"getmntinfo() succeeded; errno=%d", errno);
/* Valid modes */
nmnts = getmntinfo(&mntinfo, MNT_NOWAIT);
ATF_REQUIRE_MSG(nmnts != 0, "getmntinfo(MNT_NOWAIT) failed; errno=%d",
errno);
check_mntinfo(mntinfo, nmnts);
memset(mntinfo, 0xdf, sizeof(*mntinfo) * nmnts);
nmnts = getmntinfo(&mntinfo, MNT_WAIT);
ATF_REQUIRE_MSG(nmnts != 0, "getmntinfo(MNT_WAIT) failed; errno=%d",
errno);
check_mntinfo(mntinfo, nmnts);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getmntinfo_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/glob2_test.c b/lib/libc/tests/gen/glob2_test.c
index c18e03cc1025..8f69c36fece7 100644
--- a/lib/libc/tests/gen/glob2_test.c
+++ b/lib/libc/tests/gen/glob2_test.c
@@ -1,112 +1,111 @@
/*
* Copyright (c) 2017 Dell EMC Isilon
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <errno.h>
#include <fcntl.h>
#include <glob.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <atf-c.h>
/*
* Derived from Russ Cox' pathological case test program used for the
* https://research.swtch.com/glob article.
*/
ATF_TC_WITHOUT_HEAD(glob_pathological_test);
ATF_TC_BODY(glob_pathological_test, tc)
{
struct timespec t, t2;
glob_t g;
const char *longname = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
char pattern[1000], *p;
double dt;
unsigned i, j, k, mul;
int fd, rc;
fd = open(longname, O_CREAT | O_RDWR, 0666);
ATF_REQUIRE(fd >= 0);
/*
* Test up to 100 a* groups. Exponential implementations typically go
* bang at i=7 or 8.
*/
for (i = 0; i < 100; i++) {
/*
* Create a*...b pattern with i 'a*' groups.
*/
p = pattern;
for (k = 0; k < i; k++) {
*p++ = 'a';
*p++ = '*';
}
*p++ = 'b';
*p = '\0';
clock_gettime(CLOCK_REALTIME, &t);
for (j = 0; j < mul; j++) {
memset(&g, 0, sizeof g);
rc = glob(pattern, 0, 0, &g);
if (rc == GLOB_NOSPACE || rc == GLOB_ABORTED) {
ATF_REQUIRE_MSG(rc == GLOB_NOMATCH,
"an unexpected error occurred: "
"rc=%d errno=%d", rc, errno);
/* NORETURN */
}
ATF_CHECK_MSG(rc == GLOB_NOMATCH,
"A bogus match occurred: '%s' ~ '%s'", pattern,
g.gl_pathv[0]);
globfree(&g);
}
clock_gettime(CLOCK_REALTIME, &t2);
t2.tv_sec -= t.tv_sec;
t2.tv_nsec -= t.tv_nsec;
dt = t2.tv_sec + (double)t2.tv_nsec/1e9;
dt /= mul;
ATF_CHECK_MSG(dt < 1, "glob(3) took far too long: %d %.9f", i,
dt);
if (dt >= 0.0001)
mul = 1;
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, glob_pathological_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/makecontext_test.c b/lib/libc/tests/gen/makecontext_test.c
index 7c5c5c48ede0..23e3cf85f677 100644
--- a/lib/libc/tests/gen/makecontext_test.c
+++ b/lib/libc/tests/gen/makecontext_test.c
@@ -1,186 +1,185 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 John H. Baldwin <jhb@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#include <ucontext.h>
static char uc_stack[16 * 1024];
static void
check_1(int arg1)
{
ATF_REQUIRE_EQ(arg1, 1);
}
ATF_TC_WITHOUT_HEAD(makecontext_arg1);
ATF_TC_BODY(makecontext_arg1, tc)
{
ucontext_t ctx[2];
ATF_REQUIRE_EQ(getcontext(&ctx[1]), 0);
ctx[1].uc_stack.ss_sp = uc_stack;
ctx[1].uc_stack.ss_size = sizeof(uc_stack);
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], (void (*)(void))check_1, 1, 1);
ATF_REQUIRE_EQ(swapcontext(&ctx[0], &ctx[1]), 0);
}
static void
check_2(int arg1, int arg2)
{
ATF_REQUIRE_EQ(arg1, 1);
ATF_REQUIRE_EQ(arg2, 2);
}
ATF_TC_WITHOUT_HEAD(makecontext_arg2);
ATF_TC_BODY(makecontext_arg2, tc)
{
ucontext_t ctx[2];
ATF_REQUIRE_EQ(getcontext(&ctx[1]), 0);
ctx[1].uc_stack.ss_sp = uc_stack;
ctx[1].uc_stack.ss_size = sizeof(uc_stack);
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], (void (*)(void))check_2, 2, 1, 2);
ATF_REQUIRE_EQ(swapcontext(&ctx[0], &ctx[1]), 0);
}
static void
check_3(int arg1, int arg2, int arg3)
{
ATF_REQUIRE_EQ(arg1, 1);
ATF_REQUIRE_EQ(arg2, 2);
ATF_REQUIRE_EQ(arg3, 3);
}
ATF_TC_WITHOUT_HEAD(makecontext_arg3);
ATF_TC_BODY(makecontext_arg3, tc)
{
ucontext_t ctx[2];
ATF_REQUIRE_EQ(getcontext(&ctx[1]), 0);
ctx[1].uc_stack.ss_sp = uc_stack;
ctx[1].uc_stack.ss_size = sizeof(uc_stack);
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], (void (*)(void))check_3, 3, 1, 2, 3);
ATF_REQUIRE_EQ(swapcontext(&ctx[0], &ctx[1]), 0);
}
static void
check_4(int arg1, int arg2, int arg3, int arg4)
{
ATF_REQUIRE_EQ(arg1, 1);
ATF_REQUIRE_EQ(arg2, 2);
ATF_REQUIRE_EQ(arg3, 3);
ATF_REQUIRE_EQ(arg4, 4);
}
ATF_TC_WITHOUT_HEAD(makecontext_arg4);
ATF_TC_BODY(makecontext_arg4, tc)
{
ucontext_t ctx[2];
ATF_REQUIRE_EQ(getcontext(&ctx[1]), 0);
ctx[1].uc_stack.ss_sp = uc_stack;
ctx[1].uc_stack.ss_size = sizeof(uc_stack);
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], (void (*)(void))check_4, 4, 1, 2, 3, 4);
ATF_REQUIRE_EQ(swapcontext(&ctx[0], &ctx[1]), 0);
}
static void
check_5(int arg1, int arg2, int arg3, int arg4, int arg5)
{
ATF_REQUIRE_EQ(arg1, 1);
ATF_REQUIRE_EQ(arg2, 2);
ATF_REQUIRE_EQ(arg3, 3);
ATF_REQUIRE_EQ(arg4, 4);
ATF_REQUIRE_EQ(arg5, 5);
}
ATF_TC_WITHOUT_HEAD(makecontext_arg5);
ATF_TC_BODY(makecontext_arg5, tc)
{
ucontext_t ctx[2];
ATF_REQUIRE_EQ(getcontext(&ctx[1]), 0);
ctx[1].uc_stack.ss_sp = uc_stack;
ctx[1].uc_stack.ss_size = sizeof(uc_stack);
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], (void (*)(void))check_5, 5, 1, 2, 3, 4, 5);
ATF_REQUIRE_EQ(swapcontext(&ctx[0], &ctx[1]), 0);
}
static void
check_6(int arg1, int arg2, int arg3, int arg4, int arg5, int arg6)
{
ATF_REQUIRE_EQ(arg1, 1);
ATF_REQUIRE_EQ(arg2, 2);
ATF_REQUIRE_EQ(arg3, 3);
ATF_REQUIRE_EQ(arg4, 4);
ATF_REQUIRE_EQ(arg5, 5);
ATF_REQUIRE_EQ(arg6, 6);
}
ATF_TC_WITHOUT_HEAD(makecontext_arg6);
ATF_TC_BODY(makecontext_arg6, tc)
{
ucontext_t ctx[2];
ATF_REQUIRE_EQ(getcontext(&ctx[1]), 0);
ctx[1].uc_stack.ss_sp = uc_stack;
ctx[1].uc_stack.ss_size = sizeof(uc_stack);
ctx[1].uc_link = &ctx[0];
makecontext(&ctx[1], (void (*)(void))check_6, 6, 1, 2, 3, 4, 5, 6);
ATF_REQUIRE_EQ(swapcontext(&ctx[0], &ctx[1]), 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, makecontext_arg1);
ATF_TP_ADD_TC(tp, makecontext_arg2);
ATF_TP_ADD_TC(tp, makecontext_arg3);
ATF_TP_ADD_TC(tp, makecontext_arg4);
ATF_TP_ADD_TC(tp, makecontext_arg5);
ATF_TP_ADD_TC(tp, makecontext_arg6);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/popen_test.c b/lib/libc/tests/gen/popen_test.c
index 89be6d257c34..43eadd380f39 100644
--- a/lib/libc/tests/gen/popen_test.c
+++ b/lib/libc/tests/gen/popen_test.c
@@ -1,249 +1,248 @@
/*-
* Copyright (c) 2013 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Limited test program for popen() as specified by IEEE Std. 1003.1-2008,
* with BSD extensions.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
static volatile sig_atomic_t got_sigpipe;
static void
sigpipe_handler(int sig __unused)
{
got_sigpipe = 1;
}
static void
check_cloexec(FILE *fp, const char *mode)
{
int exp_flags, flags;
flags = fcntl(fileno(fp), F_GETFD);
ATF_CHECK_MSG(flags != -1, "fcntl(F_GETFD) failed; errno=%d", errno);
if (flags == -1)
return;
if (strchr(mode, 'e') != NULL)
exp_flags = FD_CLOEXEC;
else
exp_flags = 0;
ATF_CHECK_MSG((flags & FD_CLOEXEC) == exp_flags,
"bad cloexec flag; %d != %d", flags, exp_flags);
}
ATF_TC_WITHOUT_HEAD(popen_all_modes_test);
ATF_TC_BODY(popen_all_modes_test, tc)
{
FILE *fp;
int i, status;
const char *mode;
const char *allmodes[] = { "r", "w", "r+", "re", "we", "r+e", "re+" };
for (i = 0; i < nitems(allmodes); i++) {
mode = allmodes[i];
fp = popen("exit 7", mode);
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
if (fp == NULL)
continue;
check_cloexec(fp, mode);
status = pclose(fp);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 7,
"bad exit status (no I/O)");
}
}
ATF_TC_WITHOUT_HEAD(popen_rmodes_test);
ATF_TC_BODY(popen_rmodes_test, tc)
{
FILE *fp;
const char *rmodes[] = { "r", "r+", "re", "r+e", "re+" };
const char *mode;
char buf[80];
int i, status;
for (i = 0; i < nitems(rmodes); i++) {
mode = rmodes[i];
fp = popen("exit 9", mode);
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
if (fp == NULL)
continue;
check_cloexec(fp, mode);
bool input_error_1 = !(fgetc(fp) != EOF || !feof(fp) || !ferror(fp));
ATF_CHECK_MSG(!input_error_1, "input error 1");
if (input_error_1)
continue;
status = pclose(fp);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 9,
"bad exit status (input)");
}
for (i = 0; i < nitems(rmodes); i++) {
char *sres;
mode = rmodes[i];
fp = popen("echo hi there", mode);
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
if (fp == NULL)
continue;
check_cloexec(fp, mode);
ATF_CHECK_MSG((sres = fgets(buf, sizeof(buf), fp)) != NULL,
"Input error 2");
if (sres != NULL)
ATF_CHECK_MSG(strcmp(buf, "hi there\n") == 0,
"Bad input 1");
status = pclose(fp);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
"Bad exit status (input)");
}
}
ATF_TC_WITHOUT_HEAD(popen_wmodes_test);
ATF_TC_BODY(popen_wmodes_test, tc)
{
FILE *fp, *fp2;
const char *wmodes[] = { "w", "r+", "we", "r+e", "re+" };
const char *mode;
struct sigaction act, oact;
int i, j, status;
for (i = 0; i < nitems(wmodes); i++) {
mode = wmodes[i];
fp = popen("read x && [ \"$x\" = abcd ]", mode);
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
if (fp == NULL)
continue;
check_cloexec(fp, mode);
ATF_CHECK_MSG(fputs("abcd\n", fp) != EOF,
"Output error 1");
status = pclose(fp);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
"Bad exit status (output)");
}
act.sa_handler = sigpipe_handler;
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
ATF_CHECK_MSG(sigaction(SIGPIPE, &act, &oact) != -1,
"sigaction() failed");
for (i = 0; i < nitems(wmodes); i++) {
mode = wmodes[i];
fp = popen("exit 88", mode);
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
if (fp == NULL)
continue;
check_cloexec(fp, mode);
got_sigpipe = 0;
while (fputs("abcd\n", fp) != EOF)
;
ATF_CHECK_MSG(ferror(fp) && errno == EPIPE, "Expected EPIPE");
ATF_CHECK_MSG(got_sigpipe, "Expected SIGPIPE");
status = pclose(fp);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 88,
"Bad exit status (EPIPE)");
}
ATF_CHECK_MSG(sigaction(SIGPIPE, &oact, NULL) != -1,
"sigaction() failed");
for (i = 0; i < nitems(wmodes); i++) {
for (j = 0; j < nitems(wmodes); j++) {
mode = wmodes[i];
fp = popen("read x", mode);
ATF_CHECK_MSG(fp != NULL,
"popen(, \"%s\") failed", mode);
if (fp == NULL)
continue;
mode = wmodes[j];
fp2 = popen("read x", mode);
ATF_CHECK_MSG(fp2 != NULL,
"popen(, \"%s\") failed", mode);
if (fp2 == NULL) {
pclose(fp);
continue;
}
/* If fp2 inherits fp's pipe, we will deadlock here. */
status = pclose(fp);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
"bad exit status (2 pipes)");
status = pclose(fp2);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 1,
"bad exit status (2 pipes)");
}
}
}
ATF_TC_WITHOUT_HEAD(popen_rwmodes_test);
ATF_TC_BODY(popen_rwmodes_test, tc)
{
const char *rwmodes[] = { "r+", "r+e", "re+" };
FILE *fp;
const char *mode;
char *sres;
char buf[80];
int i, ires, status;
for (i = 0; i < nitems(rwmodes); i++) {
mode = rwmodes[i];
fp = popen("read x && printf '%s\\n' \"Q${x#a}\"", mode);
ATF_CHECK_MSG(fp != NULL, "popen(, \"%s\") failed", mode);
if (fp == NULL)
continue;
check_cloexec(fp, mode);
ATF_CHECK_MSG((ires = fputs("abcd\n", fp)) != EOF,
"Output error 2");
if (ires != EOF) {
sres = fgets(buf, sizeof(buf), fp);
ATF_CHECK_MSG(sres != NULL, "Input error 3");
if (sres != NULL)
ATF_CHECK_MSG(strcmp(buf, "Qbcd\n") == 0,
"Bad input 2");
}
status = pclose(fp);
ATF_CHECK_MSG(WIFEXITED(status) && WEXITSTATUS(status) == 0,
"bad exit status (I/O)");
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, popen_all_modes_test);
ATF_TP_ADD_TC(tp, popen_rmodes_test);
ATF_TP_ADD_TC(tp, popen_wmodes_test);
ATF_TP_ADD_TC(tp, popen_rwmodes_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/posix_spawn_test.c b/lib/libc/tests/gen/posix_spawn_test.c
index dc1381813098..77c3b5a569d9 100644
--- a/lib/libc/tests/gen/posix_spawn_test.c
+++ b/lib/libc/tests/gen/posix_spawn_test.c
@@ -1,137 +1,136 @@
/*-
* Copyright (c) 2011 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for posix_spawn() and posix_spawnp() as specified by
* IEEE Std. 1003.1-2008.
*/
-#include <sys/cdefs.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <spawn.h>
#include <atf-c.h>
char *myenv[2] = { "answer=42", NULL };
ATF_TC_WITHOUT_HEAD(posix_spawn_simple_test);
ATF_TC_BODY(posix_spawn_simple_test, tc)
{
char *myargs[4];
int error, status;
pid_t pid, waitres;
/* Make sure we have no child processes. */
while (waitpid(-1, NULL, 0) != -1)
;
ATF_REQUIRE_MSG(errno == ECHILD, "errno was not ECHILD: %d", errno);
/* Simple test. */
myargs[0] = "sh";
myargs[1] = "-c";
myargs[2] = "exit $answer";
myargs[3] = NULL;
error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, myenv);
ATF_REQUIRE(error == 0);
waitres = waitpid(pid, &status, 0);
ATF_REQUIRE(waitres == pid);
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
}
ATF_TC_WITHOUT_HEAD(posix_spawn_no_such_command_negative_test);
ATF_TC_BODY(posix_spawn_no_such_command_negative_test, tc)
{
char *myargs[4];
int error, status;
pid_t pid, waitres;
/*
* If the executable does not exist, the function shall either fail
* and not create a child process or succeed and create a child
* process that exits with status 127.
*/
myargs[0] = "/var/empty/nonexistent";
myargs[1] = NULL;
error = posix_spawn(&pid, myargs[0], NULL, NULL, myargs, myenv);
if (error == 0) {
waitres = waitpid(pid, &status, 0);
ATF_REQUIRE(waitres == pid);
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 127);
} else {
ATF_REQUIRE(error == ENOENT);
waitres = waitpid(-1, NULL, 0);
ATF_REQUIRE(waitres == -1 && errno == ECHILD);
}
}
ATF_TC_WITHOUT_HEAD(posix_spawnp_enoexec_fallback);
ATF_TC_BODY(posix_spawnp_enoexec_fallback, tc)
{
char buf[FILENAME_MAX];
char *myargs[2];
int error, status;
pid_t pid, waitres;
snprintf(buf, sizeof(buf), "%s/spawnp_enoexec.sh",
atf_tc_get_config_var(tc, "srcdir"));
myargs[0] = buf;
myargs[1] = NULL;
error = posix_spawnp(&pid, myargs[0], NULL, NULL, myargs, myenv);
ATF_REQUIRE(error == 0);
waitres = waitpid(pid, &status, 0);
ATF_REQUIRE(waitres == pid);
ATF_REQUIRE(WIFEXITED(status) && WEXITSTATUS(status) == 42);
}
ATF_TC_WITHOUT_HEAD(posix_spawnp_enoexec_fallback_null_argv0);
ATF_TC_BODY(posix_spawnp_enoexec_fallback_null_argv0, tc)
{
char buf[FILENAME_MAX];
char *myargs[1];
int error;
pid_t pid;
snprintf(buf, sizeof(buf), "%s/spawnp_enoexec.sh",
atf_tc_get_config_var(tc, "srcdir"));
myargs[0] = NULL;
error = posix_spawnp(&pid, buf, NULL, NULL, myargs, myenv);
ATF_REQUIRE(error == EINVAL);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, posix_spawn_simple_test);
ATF_TP_ADD_TC(tp, posix_spawn_no_such_command_negative_test);
ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback);
ATF_TP_ADD_TC(tp, posix_spawnp_enoexec_fallback_null_argv0);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/realpath2_test.c b/lib/libc/tests/gen/realpath2_test.c
index e3bd83448942..f89dd99cbb72 100644
--- a/lib/libc/tests/gen/realpath2_test.c
+++ b/lib/libc/tests/gen/realpath2_test.c
@@ -1,100 +1,99 @@
/*
* Copyright (c) 2017 Jan Kokemüller
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
ATF_TC(realpath_buffer_overflow);
ATF_TC_HEAD(realpath_buffer_overflow, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test for out of bounds read from 'left' array "
"(compile realpath.c with '-fsanitize=address')");
}
ATF_TC_BODY(realpath_buffer_overflow, tc)
{
char path[MAXPATHLEN] = { 0 };
char resb[MAXPATHLEN] = { 0 };
size_t i;
path[0] = 'a';
path[1] = '/';
for (i = 2; i < sizeof(path) - 1; ++i) {
path[i] = 'a';
}
ATF_REQUIRE(realpath(path, resb) == NULL);
}
ATF_TC(realpath_empty_symlink);
ATF_TC_HEAD(realpath_empty_symlink, tc)
{
atf_tc_set_md_var(tc, "descr",
"Test for correct behavior when encountering empty symlinks");
}
ATF_TC_BODY(realpath_empty_symlink, tc)
{
char path[MAXPATHLEN] = { 0 };
char slnk[MAXPATHLEN] = { 0 };
char resb[MAXPATHLEN] = { 0 };
int fd;
(void)strlcat(slnk, "empty_symlink", sizeof(slnk));
ATF_REQUIRE(symlink("", slnk) == 0);
fd = open("aaa", O_RDONLY | O_CREAT, 0600);
ATF_REQUIRE(fd >= 0);
ATF_REQUIRE(close(fd) == 0);
(void)strlcat(path, "empty_symlink", sizeof(path));
(void)strlcat(path, "/aaa", sizeof(path));
ATF_REQUIRE_ERRNO(ENOENT, realpath(path, resb) == NULL);
ATF_REQUIRE(unlink("aaa") == 0);
ATF_REQUIRE(unlink(slnk) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, realpath_buffer_overflow);
ATF_TP_ADD_TC(tp, realpath_empty_symlink);
return atf_no_error();
}
diff --git a/lib/libc/tests/gen/sigsetops_test.c b/lib/libc/tests/gen/sigsetops_test.c
index 498d34bb23a4..a22c4b3f4f59 100644
--- a/lib/libc/tests/gen/sigsetops_test.c
+++ b/lib/libc/tests/gen/sigsetops_test.c
@@ -1,189 +1,188 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <atf-c.h>
/* Return the status of the specified sig's bit. */
static bool
sigbitstatus(const sigset_t *set, int sig)
{
return (set->__bits[_SIG_WORD(sig)] & _SIG_BIT(sig)) != 0;
}
/* Verify that sig is the lone bit set in the sigset. */
static void
siglonebit(const sigset_t *set, int sig)
{
int i;
for (i = 0; i < _SIG_WORDS; ++i) {
if (i != _SIG_WORD(sig))
ATF_REQUIRE_MSG(set->__bits[i] == 0,
"word %d altered to %x", i, set->__bits[i]);
else
ATF_REQUIRE_MSG((set->__bits[i] & ~_SIG_BIT(sig)) == 0,
"word %d has other bits set: %x", i,
set->__bits[i] & ~_SIG_BIT(sig));
}
}
static void
sigcompare(const sigset_t *left, const sigset_t *right)
{
int i;
for (i = 0; i < _SIG_WORDS; ++i) {
ATF_REQUIRE_MSG(left->__bits[i] == right->__bits[i],
"sig comparison failed at %d; left=%x, right=%x",
i, left->__bits[i], right->__bits[i]);
}
}
/*
* Test implementation details of our sigsetops... make sure the correct bits
* are getting set, for the most part, and that duplicate operations don't
* error out.
*/
ATF_TC_WITHOUT_HEAD(posix_sigsetop_test);
ATF_TC_BODY(posix_sigsetop_test, tc)
{
sigset_t set;
int i;
ATF_REQUIRE(sigfillset(&set) == 0);
for (i = 0; i < _SIG_WORDS; ++i) {
ATF_REQUIRE_MSG(set.__bits[i] == ~0U, "sigfillset failed @ %d",
i);
}
ATF_REQUIRE(sigemptyset(&set) == 0);
for (i = 0; i < _SIG_WORDS; ++i) {
ATF_REQUIRE_MSG(set.__bits[i] == 0, "sigemptyset failed @ %d",
i);
}
/* Ensure that sigismember reflects the empty set status. */
for (i = 1; i < NSIG; ++i) {
ATF_REQUIRE(sigismember(&set, i) == 0);
}
ATF_REQUIRE(sigaddset(&set, -1) == -1 && errno == EINVAL);
ATF_REQUIRE(sigaddset(&set, _SIG_MAXSIG + 1) == -1 && errno == EINVAL);
ATF_REQUIRE(sigdelset(&set, -1) == -1 && errno == EINVAL);
ATF_REQUIRE(sigdelset(&set, _SIG_MAXSIG + 1) == -1 && errno == EINVAL);
ATF_REQUIRE(sigaddset(&set, SIGSEGV) == 0);
ATF_REQUIRE(sigismember(&set, SIGSEGV) != 0);
ATF_REQUIRE_MSG(sigbitstatus(&set, SIGSEGV), "sigaddset failure");
siglonebit(&set, SIGSEGV);
/*
* A second addition should succeed without altering the state. This
* should be trivially true.
*/
ATF_REQUIRE(sigaddset(&set, SIGSEGV) == 0);
ATF_REQUIRE_MSG(sigbitstatus(&set, SIGSEGV),
"sigaddset twice changed bit");
ATF_REQUIRE(sigdelset(&set, SIGSEGV) == 0);
ATF_REQUIRE_MSG(!sigbitstatus(&set, SIGSEGV), "sigdelset failure");
ATF_REQUIRE(sigismember(&set, SIGSEGV) == 0);
ATF_REQUIRE(sigdelset(&set, SIGSEGV) == 0);
ATF_REQUIRE_MSG(!sigbitstatus(&set, SIGSEGV),
"sigdelset twice changed bit");
for (i = 0; i < _SIG_WORDS; ++i) {
ATF_REQUIRE_MSG(set.__bits[i] == 0, "set not empty @ %d",
i);
}
for (i = 1; i < NSIG; ++i) {
ATF_REQUIRE(sigismember(&set, i) == 0);
}
}
/*
* Test extended sigset ops for union/intersection and testing of empty set.
*/
ATF_TC_WITHOUT_HEAD(extended_sigsetop_test);
ATF_TC_BODY(extended_sigsetop_test, tc)
{
sigset_t chkset, set1, set2, set3;
sigemptyset(&chkset);
sigemptyset(&set1);
sigemptyset(&set2);
ATF_REQUIRE(sigisemptyset(&chkset) != 0);
sigaddset(&set1, SIGSEGV);
sigaddset(&set2, SIGKILL);
sigaddset(&chkset, SIGSEGV);
ATF_REQUIRE(sigisemptyset(&chkset) == 0);
sigaddset(&chkset, SIGKILL);
ATF_REQUIRE(sigorset(&set3, &set1, &set2) == 0);
ATF_REQUIRE(sigbitstatus(&set3, SIGSEGV));
ATF_REQUIRE(sigbitstatus(&set3, SIGKILL));
/*
* chkset was built with our POSIX-specified set operations that we've
* already tested, so it's a good comparison.
*/
sigcompare(&chkset, &set3);
/*
* Clear chkset; make sure sigisemptyset() still looks ok. sigaddset
* and sigdelset have already been tested to make sure that they're not
* touching other bits.
*/
sigdelset(&chkset, SIGSEGV);
sigdelset(&chkset, SIGKILL);
ATF_REQUIRE(sigisemptyset(&chkset) != 0);
ATF_REQUIRE(sigandset(&set3, &set1, &set2) == 0);
/* Make sure we clobbered these. */
ATF_REQUIRE(!sigbitstatus(&set3, SIGSEGV));
ATF_REQUIRE(!sigbitstatus(&set3, SIGKILL));
ATF_REQUIRE(sigisemptyset(&set3) != 0);
/* Rebuild for sigandset test */
sigemptyset(&set1);
sigemptyset(&set2);
sigaddset(&set1, SIGSEGV);
sigaddset(&set1, SIGKILL);
sigaddset(&set2, SIGSEGV);
ATF_REQUIRE(sigandset(&set3, &set1, &set2) == 0);
ATF_REQUIRE(sigbitstatus(&set3, SIGSEGV));
ATF_REQUIRE(!sigbitstatus(&set3, SIGKILL));
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, posix_sigsetop_test);
ATF_TP_ADD_TC(tp, extended_sigsetop_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/gen/test-fnmatch.c b/lib/libc/tests/gen/test-fnmatch.c
index e7c63b329439..1a6c6ed7efdf 100644
--- a/lib/libc/tests/gen/test-fnmatch.c
+++ b/lib/libc/tests/gen/test-fnmatch.c
@@ -1,100 +1,99 @@
/*-
* Copyright (c) 2010 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "fnmatch_testcases.h"
static int
write_sh_tests(const char *progname, int num)
{
size_t i;
struct testcase *t;
printf("# Generated by %s -s %d, do not edit.\n", progname, num);
printf("# $" "FreeBSD$\n");
printf("failures=\n");
printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n");
if (num == 1) {
printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n");
printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n");
} else if (num == 2) {
printf("# We do not treat a backslash specially in this case,\n");
printf("# but this is not the case in all shells.\n");
printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n");
printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n");
}
for (i = 0; i < nitems(testcases); i++) {
t = &testcases[i];
if (strchr(t->pattern, '\'') != NULL ||
strchr(t->string, '\'') != NULL)
continue;
if (t->flags == 0 && strcmp(t->pattern, "\\") == 0)
continue;
if (num == 1 && t->flags == 0)
printf("test%smatch '%s' '%s'\n",
t->result == FNM_NOMATCH ? "no" : "",
t->pattern, t->string);
if (num == 2 && (t->flags == FNM_NOESCAPE ||
(t->flags == 0 && strchr(t->pattern, '\\') == NULL)))
printf("netest%smatch '%s' '%s'\n",
t->result == FNM_NOMATCH ? "no" : "",
t->pattern, t->string);
}
printf("[ -z \"$failures\" ]\n");
return 0;
}
static void
usage(char *progname)
{
fprintf(stderr, "usage: %s [-s num]\n", progname);
fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n");
}
int
main(int argc, char *argv[])
{
int opt;
while ((opt = getopt(argc, argv, "s:")) != -1) {
switch (opt) {
case 's':
return (write_sh_tests(argv[0], atoi(optarg)));
default:
usage(argv[0]);
exit(1);
}
}
usage(argv[0]);
exit(1);
}
diff --git a/lib/libc/tests/gen/wordexp_test.c b/lib/libc/tests/gen/wordexp_test.c
index ea8dc3d37828..909097fbf51e 100644
--- a/lib/libc/tests/gen/wordexp_test.c
+++ b/lib/libc/tests/gen/wordexp_test.c
@@ -1,358 +1,357 @@
/*-
* Copyright (c) 2003 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wordexp() and wordfree() as specified by
* IEEE Std. 1003.1-2001.
*/
-#include <sys/cdefs.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wordexp.h>
#include <atf-c.h>
static void
chld_handler(int x)
{
int status, serrno;
(void)x;
serrno = errno;
while (waitpid(-1, &status, WNOHANG) > 0)
;
errno = serrno;
}
ATF_TC_WITHOUT_HEAD(simple_test);
ATF_TC_BODY(simple_test, tc)
{
wordexp_t we;
int r;
/* Test that the macros are there. */
(void)(WRDE_APPEND + WRDE_DOOFFS + WRDE_NOCMD + WRDE_REUSE +
WRDE_SHOWERR + WRDE_UNDEF);
(void)(WRDE_BADCHAR + WRDE_BADVAL + WRDE_CMDSUB + WRDE_NOSPACE +
WRDE_SYNTAX);
/* Simple test. */
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);
}
ATF_TC_WITHOUT_HEAD(long_output_test);
ATF_TC_BODY(long_output_test, tc)
{
char longdata[6 * 10000 + 1];
wordexp_t we;
int i, r;
/* Long output. */
for (i = 0; i < 10000; i++)
snprintf(longdata + 6 * i, 7, "%05d ", i);
r = wordexp(longdata, &we, 0);
ATF_REQUIRE(r == 0);
ATF_REQUIRE(we.we_wordc == 10000);
ATF_REQUIRE(we.we_wordv[10000] == NULL);
wordfree(&we);
}
ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS_test);
ATF_TC_BODY(WRDE_DOOFFS_test, tc)
{
wordexp_t we;
int r;
we.we_offs = 3;
r = wordexp("hello world", &we, WRDE_DOOFFS);
ATF_REQUIRE(r == 0);
ATF_REQUIRE(we.we_wordc == 2);
ATF_REQUIRE(we.we_wordv[0] == NULL);
ATF_REQUIRE(we.we_wordv[1] == NULL);
ATF_REQUIRE(we.we_wordv[2] == NULL);
ATF_REQUIRE(strcmp(we.we_wordv[3], "hello") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[4], "world") == 0);
ATF_REQUIRE(we.we_wordv[5] == NULL);
wordfree(&we);
}
ATF_TC_WITHOUT_HEAD(WRDE_REUSE_test);
ATF_TC_BODY(WRDE_REUSE_test, tc)
{
wordexp_t we;
int r;
r = wordexp("hello world", &we, 0);
r = wordexp("hello world", &we, WRDE_REUSE);
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);
}
ATF_TC_WITHOUT_HEAD(WRDE_APPEND_test);
ATF_TC_BODY(WRDE_APPEND_test, tc)
{
wordexp_t we;
int r;
r = wordexp("this is", &we, 0);
ATF_REQUIRE(r == 0);
r = wordexp("a test", &we, WRDE_APPEND);
ATF_REQUIRE(r == 0);
ATF_REQUIRE(we.we_wordc == 4);
ATF_REQUIRE(strcmp(we.we_wordv[0], "this") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[1], "is") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[2], "a") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[3], "test") == 0);
ATF_REQUIRE(we.we_wordv[4] == NULL);
wordfree(&we);
}
ATF_TC_WITHOUT_HEAD(WRDE_DOOFFS__WRDE_APPEND_test);
ATF_TC_BODY(WRDE_DOOFFS__WRDE_APPEND_test, tc)
{
wordexp_t we;
int r;
we.we_offs = 2;
r = wordexp("this is", &we, WRDE_DOOFFS);
ATF_REQUIRE(r == 0);
r = wordexp("a test", &we, WRDE_APPEND|WRDE_DOOFFS);
ATF_REQUIRE(r == 0);
r = wordexp("of wordexp", &we, WRDE_APPEND|WRDE_DOOFFS);
ATF_REQUIRE(r == 0);
ATF_REQUIRE(we.we_wordc == 6);
ATF_REQUIRE(we.we_wordv[0] == NULL);
ATF_REQUIRE(we.we_wordv[1] == NULL);
ATF_REQUIRE(strcmp(we.we_wordv[2], "this") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[3], "is") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[4], "a") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[5], "test") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[6], "of") == 0);
ATF_REQUIRE(strcmp(we.we_wordv[7], "wordexp") == 0);
ATF_REQUIRE(we.we_wordv[8] == NULL);
wordfree(&we);
}
ATF_TC_WITHOUT_HEAD(WRDE_UNDEF_test);
ATF_TC_BODY(WRDE_UNDEF_test, tc)
{
wordexp_t we;
int r;
r = wordexp("${dont_set_me}", &we, WRDE_UNDEF);
ATF_REQUIRE(r == WRDE_BADVAL);
}
ATF_TC_WITHOUT_HEAD(WRDE_NOCMD_test);
ATF_TC_BODY(WRDE_NOCMD_test, tc)
{
wordexp_t we;
int r;
r = wordexp("`date`", &we, WRDE_NOCMD);
ATF_REQUIRE(r == WRDE_CMDSUB);
r = wordexp("\"`date`\"", &we, WRDE_NOCMD);
ATF_REQUIRE(r == WRDE_CMDSUB);
r = wordexp("$(date)", &we, WRDE_NOCMD);
ATF_REQUIRE(r == WRDE_CMDSUB);
r = wordexp("\"$(date)\"", &we, WRDE_NOCMD);
ATF_REQUIRE(r == WRDE_CMDSUB);
r = wordexp("$((3+5))", &we, WRDE_NOCMD);
ATF_REQUIRE(r == 0);
r = wordexp("\\$\\(date\\)", &we, WRDE_NOCMD|WRDE_REUSE);
ATF_REQUIRE(r == 0);
r = wordexp("'`date`'", &we, WRDE_NOCMD|WRDE_REUSE);
ATF_REQUIRE(r == 0);
r = wordexp("'$(date)'", &we, WRDE_NOCMD|WRDE_REUSE);
ATF_REQUIRE(r == 0);
wordfree(&we);
}
ATF_TC_WITHOUT_HEAD(WRDE_BADCHAR_test);
ATF_TC_BODY(WRDE_BADCHAR_test, tc)
{
wordexp_t we;
int r;
r = wordexp("'\n|&;<>(){}'", &we, 0);
ATF_REQUIRE(r == 0);
r = wordexp("\"\n|&;<>(){}\"", &we, WRDE_REUSE);
ATF_REQUIRE(r == 0);
r = wordexp("\\\n\\|\\&\\;\\<\\>\\(\\)\\{\\}", &we, WRDE_REUSE);
ATF_REQUIRE(r == 0);
wordfree(&we);
r = wordexp("test \n test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test | test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test & test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test ; test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test > test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test < test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test ( test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test ) test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test { test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
r = wordexp("test } test", &we, 0);
ATF_REQUIRE(r == WRDE_BADCHAR);
}
ATF_TC_WITHOUT_HEAD(WRDE_SYNTAX_test);
ATF_TC_BODY(WRDE_SYNTAX_test, tc)
{
wordexp_t we;
int r;
r = wordexp("'", &we, 0);
ATF_REQUIRE(r == WRDE_SYNTAX);
r = wordexp("'", &we, WRDE_UNDEF);
ATF_REQUIRE(r == WRDE_SYNTAX);
r = wordexp("'\\'", &we, 0);
ATF_REQUIRE(r == 0);
ATF_REQUIRE(we.we_wordc == 1);
ATF_REQUIRE(strcmp(we.we_wordv[0], "\\") == 0);
ATF_REQUIRE(we.we_wordv[1] == NULL);
wordfree(&we);
/* Two syntax errors that are not detected by the current we_check(). */
r = wordexp("${IFS:+'}", &we, 0);
ATF_REQUIRE(r == WRDE_SYNTAX);
r = wordexp("${IFS:+'}", &we, WRDE_UNDEF);
ATF_REQUIRE(r == WRDE_SYNTAX);
r = wordexp("$(case)", &we, 0);
ATF_REQUIRE(r == WRDE_SYNTAX);
r = wordexp("$(case)", &we, WRDE_UNDEF);
ATF_REQUIRE(r == WRDE_SYNTAX);
}
ATF_TC_WITHOUT_HEAD(with_SIGCHILD_handler_test);
ATF_TC_BODY(with_SIGCHILD_handler_test, tc)
{
struct sigaction sa;
wordexp_t we;
int r;
/* With a SIGCHLD handler that reaps all zombies. */
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = chld_handler;
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)
{
wordexp_t we;
int r;
/*
* With IFS set to a non-default value (without depending on whether
* IFS is inherited or not).
*/
r = setenv("IFS", ":", 1);
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);
r = unsetenv("IFS");
ATF_REQUIRE(r == 0);
}
ATF_TC_WITHOUT_HEAD(with_used_non_default_IFS_test);
ATF_TC_BODY(with_used_non_default_IFS_test, tc)
{
wordexp_t we;
int r;
/*
* With IFS set to a non-default value, and using it.
*/
r = setenv("IFS", ":", 1);
ATF_REQUIRE(r == 0);
r = wordexp("${IFS+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);
r = unsetenv("IFS");
ATF_REQUIRE(r == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, simple_test);
ATF_TP_ADD_TC(tp, long_output_test);
ATF_TP_ADD_TC(tp, WRDE_DOOFFS_test);
ATF_TP_ADD_TC(tp, WRDE_REUSE_test);
ATF_TP_ADD_TC(tp, WRDE_APPEND_test);
ATF_TP_ADD_TC(tp, WRDE_DOOFFS__WRDE_APPEND_test);
ATF_TP_ADD_TC(tp, WRDE_UNDEF_test);
ATF_TP_ADD_TC(tp, WRDE_NOCMD_test);
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_unused_non_default_IFS_test);
ATF_TP_ADD_TC(tp, with_used_non_default_IFS_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/iconv/iconvctl_test.c b/lib/libc/tests/iconv/iconvctl_test.c
index 06c882a6eee6..f534218cf294 100644
--- a/lib/libc/tests/iconv/iconvctl_test.c
+++ b/lib/libc/tests/iconv/iconvctl_test.c
@@ -1,66 +1,65 @@
/*-
* Copyright (c) 2016 Eric van Gyzen
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <iconv.h>
#include <atf-c.h>
static void
test_trivialp(const char *src, const char *dst, int expected)
{
iconv_t ic;
int actual, status;
ic = iconv_open(dst, src);
ATF_REQUIRE(ic != (iconv_t)-1);
status = iconvctl(ic, ICONV_TRIVIALP, &actual);
ATF_REQUIRE(status == 0);
ATF_REQUIRE(actual == expected);
status = iconv_close(ic);
ATF_REQUIRE(status == 0);
}
ATF_TC_WITHOUT_HEAD(iconvctl_trivialp_test);
ATF_TC_BODY(iconvctl_trivialp_test, tc)
{
test_trivialp("ISO-8859-1", "ISO-8859-1", 1);
test_trivialp("ISO-8859-1", "ISO-8859-15", 0);
test_trivialp("ISO-8859-15", "ISO-8859-1", 0);
test_trivialp("ISO-8859-15", "UTF-8", 0);
test_trivialp("UTF-8", "ASCII", 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, iconvctl_trivialp_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/btowc_test.c b/lib/libc/tests/locale/btowc_test.c
index 85be466eac7e..27e6ff533621 100644
--- a/lib/libc/tests/locale/btowc_test.c
+++ b/lib/libc/tests/locale/btowc_test.c
@@ -1,69 +1,68 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for btowc() and wctob() as specified by IEEE Std. 1003.1-2001
* and ISO/IEC 9899:1999.
*
* The function is tested in the "C" and "ja_JP.eucJP" locales.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(btowc_test);
ATF_TC_BODY(btowc_test, tc)
{
int i;
/* C/POSIX locale. */
ATF_REQUIRE(btowc(EOF) == WEOF);
ATF_REQUIRE(wctob(WEOF) == EOF);
for (i = 0; i < UCHAR_MAX; i++)
ATF_REQUIRE(btowc(i) == (wchar_t)i && i == (int)wctob(i));
/* Japanese (EUC) locale. */
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
ATF_REQUIRE(btowc('A') == L'A' && wctob(L'A') == 'A');
ATF_REQUIRE(btowc(0xa3) == WEOF && wctob(0xa3c1) == EOF);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, btowc_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/c16rtomb_test.c b/lib/libc/tests/locale/c16rtomb_test.c
index df9fbcf61711..6812fbbc5164 100644
--- a/lib/libc/tests/locale/c16rtomb_test.c
+++ b/lib/libc/tests/locale/c16rtomb_test.c
@@ -1,164 +1,163 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for c16rtomb() as specified by ISO/IEC 9899:2011.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <uchar.h>
#include <atf-c.h>
static void
require_lc_ctype(const char *locale_name)
{
char *lc_ctype_set;
lc_ctype_set = setlocale(LC_CTYPE, locale_name);
if (lc_ctype_set == NULL)
atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d",
locale_name, errno);
ATF_REQUIRE(strcmp(lc_ctype_set, locale_name) == 0);
}
static mbstate_t s;
static char buf[MB_LEN_MAX + 1];
ATF_TC_WITHOUT_HEAD(c16rtomb_c_locale_test);
ATF_TC_BODY(c16rtomb_c_locale_test, tc)
{
require_lc_ctype("C");
/*
* If the buffer argument is NULL, c16 is implicitly 0,
* c16rtomb() resets its internal state.
*/
ATF_REQUIRE(c16rtomb(NULL, L'\0', NULL) == 1);
ATF_REQUIRE(c16rtomb(NULL, 0xdc00, NULL) == 1);
/* Null wide character. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, 0, &s) == 1);
ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
/* Latin letter A, internal state. */
ATF_REQUIRE(c16rtomb(NULL, L'\0', NULL) == 1);
ATF_REQUIRE(c16rtomb(NULL, L'A', NULL) == 1);
/* Latin letter A. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, L'A', &s) == 1);
ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
/* Unicode character 'Pile of poo'. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, 0xd83d, &s) == 0);
ATF_REQUIRE(c16rtomb(buf, 0xdca9, &s) == (size_t)-1);
ATF_REQUIRE(errno == EILSEQ);
ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
}
ATF_TC_WITHOUT_HEAD(c16rtomb_iso_8859_1_test);
ATF_TC_BODY(c16rtomb_iso_8859_1_test, tc)
{
require_lc_ctype("en_US.ISO8859-1");
/* Unicode character 'Euro sign'. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, 0x20ac, &s) == (size_t)-1);
ATF_REQUIRE(errno == EILSEQ);
ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
}
ATF_TC_WITHOUT_HEAD(c16rtomb_iso_8859_15_test);
ATF_TC_BODY(c16rtomb_iso_8859_15_test, tc)
{
require_lc_ctype("en_US.ISO8859-15");
/* Unicode character 'Euro sign'. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, 0x20ac, &s) == 1);
ATF_REQUIRE((unsigned char)buf[0] == 0xa4 && (unsigned char)buf[1] == 0xcc);
}
ATF_TC_WITHOUT_HEAD(c16rtomb_utf_8_test);
ATF_TC_BODY(c16rtomb_utf_8_test, tc)
{
require_lc_ctype("en_US.UTF-8");
/* Unicode character 'Pile of poo'. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, 0xd83d, &s) == 0);
ATF_REQUIRE(c16rtomb(buf, 0xdca9, &s) == 4);
ATF_REQUIRE((unsigned char)buf[0] == 0xf0 && (unsigned char)buf[1] == 0x9f &&
(unsigned char)buf[2] == 0x92 && (unsigned char)buf[3] == 0xa9 &&
(unsigned char)buf[4] == 0xcc);
/* Invalid code; 'Pile of poo' without the trail surrogate. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, 0xd83d, &s) == 0);
ATF_REQUIRE(c16rtomb(buf, L'A', &s) == (size_t)-1);
ATF_REQUIRE(errno == EILSEQ);
ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
/* Invalid code; 'Pile of poo' without the lead surrogate. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
ATF_REQUIRE(c16rtomb(buf, 0xdca9, &s) == (size_t)-1);
ATF_REQUIRE(errno == EILSEQ);
ATF_REQUIRE((unsigned char)buf[0] == 0xcc);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, c16rtomb_c_locale_test);
ATF_TP_ADD_TC(tp, c16rtomb_iso_8859_1_test);
ATF_TP_ADD_TC(tp, c16rtomb_iso_8859_15_test);
ATF_TP_ADD_TC(tp, c16rtomb_utf_8_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/iswctype_test.c b/lib/libc/tests/locale/iswctype_test.c
index 1780ade0bd4d..79b941522d2b 100644
--- a/lib/libc/tests/locale/iswctype_test.c
+++ b/lib/libc/tests/locale/iswctype_test.c
@@ -1,120 +1,119 @@
/*-
* Copyright (c) 2003 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wctype() and iswctype() as specified by
* IEEE Std. 1003.1-2001 and ISO/IEC 9899:1999.
*
* The functions are tested in the "C" and "ja_JP.eucJP" locales.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <errno.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include <atf-c.h>
static void
require_lc_ctype(const char *locale_name)
{
char *lc_ctype_set;
lc_ctype_set = setlocale(LC_CTYPE, locale_name);
if (lc_ctype_set == NULL)
atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d",
locale_name, errno);
ATF_REQUIRE(strcmp(lc_ctype_set, locale_name) == 0);
}
static wctype_t t;
static int i, j;
static struct {
const char *name;
int (*func)(wint_t);
} cls[] = {
{ "alnum", iswalnum },
{ "alpha", iswalpha },
{ "blank", iswblank },
{ "cntrl", iswcntrl },
{ "digit", iswdigit },
{ "graph", iswgraph },
{ "lower", iswlower },
{ "print", iswprint },
{ "punct", iswpunct },
{ "space", iswspace },
{ "upper", iswupper },
{ "xdigit", iswxdigit }
};
ATF_TC_WITHOUT_HEAD(iswctype_c_locale_test);
ATF_TC_BODY(iswctype_c_locale_test, tc)
{
require_lc_ctype("C");
for (i = 0; i < nitems(cls); i++) {
t = wctype(cls[i].name);
ATF_REQUIRE(t != 0);
for (j = 0; j < 256; j++)
ATF_REQUIRE(cls[i].func(j) == iswctype(j, t));
}
t = wctype("elephant");
ATF_REQUIRE(t == 0);
for (i = 0; i < 256; i++)
ATF_REQUIRE(iswctype(i, t) == 0);
}
ATF_TC_WITHOUT_HEAD(iswctype_euc_jp_test);
ATF_TC_BODY(iswctype_euc_jp_test, tc)
{
require_lc_ctype("ja_JP.eucJP");
for (i = 0; i < nitems(cls); i++) {
t = wctype(cls[i].name);
ATF_REQUIRE(t != 0);
for (j = 0; j < 65536; j++)
ATF_REQUIRE(cls[i].func(j) == iswctype(j, t));
}
t = wctype("elephant");
ATF_REQUIRE(t == 0);
for (i = 0; i < 65536; i++)
ATF_REQUIRE(iswctype(i, t) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, iswctype_c_locale_test);
ATF_TP_ADD_TC(tp, iswctype_euc_jp_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mblen_test.c b/lib/libc/tests/locale/mblen_test.c
index 91d01958e79a..e081b0d4246a 100644
--- a/lib/libc/tests/locale/mblen_test.c
+++ b/lib/libc/tests/locale/mblen_test.c
@@ -1,114 +1,113 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mblen(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1990.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(mblen_test);
ATF_TC_BODY(mblen_test, tc)
{
char buf[MB_LEN_MAX + 1];
/*
* C/POSIX locale.
*/
ATF_REQUIRE(MB_CUR_MAX == 1);
/* No shift states in C locale. */
ATF_REQUIRE(mblen(NULL, 0) == 0);
/* Null wide character. */
memset(buf, 0xcc, sizeof(buf));
buf[0] = '\0';
ATF_REQUIRE(mblen(buf, 1) == 0);
/* Latin letter A. */
buf[0] = 'A';
ATF_REQUIRE(mblen(buf, 1) == 1);
/* Incomplete character sequence. */
buf[0] = '\0';
ATF_REQUIRE(mblen(buf, 0) == -1);
ATF_REQUIRE(mblen(NULL, 0) == 0);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
/* No shift states in EUC. */
ATF_REQUIRE(mblen(NULL, 0) == 0);
/* Null wide character. */
memset(buf, 0xcc, sizeof(buf));
buf[0] = '\0';
ATF_REQUIRE(mblen(buf, 1) == 0);
/* Latin letter A. */
buf[0] = 'A';
ATF_REQUIRE(mblen(buf, 1) == 1);
/* Incomplete character sequence. */
buf[0] = '\0';
ATF_REQUIRE(mblen(buf, 0) == -1);
ATF_REQUIRE(mblen(NULL, 0) == 0);
/* Incomplete character sequence (truncated double-byte). */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0xa3;
buf[1] = 0x00;
ATF_REQUIRE(mblen(buf, 1) == -1);
ATF_REQUIRE(mblen(NULL, 0) == 0);
/* Same as above, but complete. */
buf[1] = 0xc1;
ATF_REQUIRE(mblen(buf, 2) == 2);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mblen_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mbrlen_test.c b/lib/libc/tests/locale/mbrlen_test.c
index 33fa156bd2f0..50088596fc89 100644
--- a/lib/libc/tests/locale/mbrlen_test.c
+++ b/lib/libc/tests/locale/mbrlen_test.c
@@ -1,124 +1,123 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mbrlen(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(mbrlen_test);
ATF_TC_BODY(mbrlen_test, tc)
{
mbstate_t s;
char buf[MB_LEN_MAX + 1];
/* C/POSIX locale. */
ATF_REQUIRE(MB_CUR_MAX == 1);
/* Null wide character, internal state. */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0;
ATF_REQUIRE(mbrlen(buf, 1, NULL) == 0);
/* Null wide character. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 1, &s) == 0);
/* Latin letter A, internal state. */
ATF_REQUIRE(mbrlen(NULL, 0, NULL) == 0);
buf[0] = 'A';
ATF_REQUIRE(mbrlen(buf, 1, NULL) == 1);
/* Latin letter A. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 1, &s) == 1);
/* Incomplete character sequence. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 0, &s) == (size_t)-2);
/* Japanese (EUC) locale. */
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
/* Null wide character, internal state. */
ATF_REQUIRE(mbrlen(NULL, 0, NULL) == 0);
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0;
ATF_REQUIRE(mbrlen(buf, 1, NULL) == 0);
/* Null wide character. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 1, &s) == 0);
/* Latin letter A, internal state. */
ATF_REQUIRE(mbrlen(NULL, 0, NULL) == 0);
buf[0] = 'A';
ATF_REQUIRE(mbrlen(buf, 1, NULL) == 1);
/* Latin letter A. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 1, &s) == 1);
/* Incomplete character sequence (zero length). */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 0, &s) == (size_t)-2);
/* Incomplete character sequence (truncated double-byte). */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0xa3;
buf[1] = 0x00;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 1, &s) == (size_t)-2);
/* Same as above, but complete. */
buf[1] = 0xc1;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrlen(buf, 2, &s) == 2);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mbrlen_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mbrtoc16_test.c b/lib/libc/tests/locale/mbrtoc16_test.c
index 09e0379ca021..98a140c56fc0 100644
--- a/lib/libc/tests/locale/mbrtoc16_test.c
+++ b/lib/libc/tests/locale/mbrtoc16_test.c
@@ -1,212 +1,211 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Copyright (c) 2013 Ed Schouten <ed@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mbrtoc16() as specified by ISO/IEC 9899:2011.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <uchar.h>
#include <atf-c.h>
static void
require_lc_ctype(const char *locale_name)
{
char *lc_ctype_set;
lc_ctype_set = setlocale(LC_CTYPE, locale_name);
if (lc_ctype_set == NULL)
atf_tc_fail("setlocale(LC_CTYPE, \"%s\") failed; errno=%d",
locale_name, errno);
ATF_REQUIRE(strcmp(lc_ctype_set, locale_name) == 0);
}
static mbstate_t s;
static char16_t c16;
ATF_TC_WITHOUT_HEAD(mbrtoc16_c_locale_test);
ATF_TC_BODY(mbrtoc16_c_locale_test, tc)
{
require_lc_ctype("C");
/* Null wide character, internal state. */
ATF_REQUIRE(mbrtoc16(&c16, "", 1, NULL) == 0);
ATF_REQUIRE(c16 == 0);
/* Null wide character. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "", 1, &s) == 0);
ATF_REQUIRE(c16 == 0);
/* Latin letter A, internal state. */
ATF_REQUIRE(mbrtoc16(NULL, 0, 0, NULL) == 0);
ATF_REQUIRE(mbrtoc16(&c16, "A", 1, NULL) == 1);
ATF_REQUIRE(c16 == L'A');
/* Latin letter A. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "A", 1, &s) == 1);
ATF_REQUIRE(c16 == L'A');
/* Incomplete character sequence. */
c16 = L'z';
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-2);
ATF_REQUIRE(c16 == L'z');
/* Check that mbrtoc16() doesn't access the buffer when n == 0. */
c16 = L'z';
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-2);
ATF_REQUIRE(c16 == L'z');
/* Check that mbrtoc16() doesn't read ahead too aggressively. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "AB", 2, &s) == 1);
ATF_REQUIRE(c16 == L'A');
ATF_REQUIRE(mbrtoc16(&c16, "C", 1, &s) == 1);
ATF_REQUIRE(c16 == L'C');
}
ATF_TC_WITHOUT_HEAD(mbrtoc16_iso_8859_1_test);
ATF_TC_BODY(mbrtoc16_iso_8859_1_test, tc)
{
require_lc_ctype("en_US.ISO8859-1");
/* Currency sign. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "\xa4", 1, &s) == 1);
ATF_REQUIRE(c16 == 0xa4);
}
ATF_TC_WITHOUT_HEAD(mbrtoc16_iso_8859_15_test);
ATF_TC_BODY(mbrtoc16_iso_8859_15_test, tc)
{
require_lc_ctype("en_US.ISO8859-15");
/* Euro sign. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "\xa4", 1, &s) == 1);
ATF_REQUIRE(c16 == 0x20ac);
}
ATF_TC_WITHOUT_HEAD(mbrtoc16_utf_8_test);
ATF_TC_BODY(mbrtoc16_utf_8_test, tc)
{
require_lc_ctype("en_US.UTF-8");
/* Null wide character, internal state. */
ATF_REQUIRE(mbrtoc16(NULL, 0, 0, NULL) == 0);
ATF_REQUIRE(mbrtoc16(&c16, "", 1, NULL) == 0);
ATF_REQUIRE(c16 == 0);
/* Null wide character. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "", 1, &s) == 0);
ATF_REQUIRE(c16 == 0);
/* Latin letter A, internal state. */
ATF_REQUIRE(mbrtoc16(NULL, 0, 0, NULL) == 0);
ATF_REQUIRE(mbrtoc16(&c16, "A", 1, NULL) == 1);
ATF_REQUIRE(c16 == L'A');
/* Latin letter A. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "A", 1, &s) == 1);
ATF_REQUIRE(c16 == L'A');
/* Incomplete character sequence (zero length). */
c16 = L'z';
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-2);
ATF_REQUIRE(c16 == L'z');
/* Incomplete character sequence (truncated double-byte). */
memset(&s, 0, sizeof(s));
c16 = 0;
ATF_REQUIRE(mbrtoc16(&c16, "\xc3", 1, &s) == (size_t)-2);
/* Same as above, but complete. */
memset(&s, 0, sizeof(s));
c16 = 0;
ATF_REQUIRE(mbrtoc16(&c16, "\xc3\x84", 2, &s) == 2);
ATF_REQUIRE(c16 == 0xc4);
/* Test restarting behaviour. */
memset(&s, 0, sizeof(s));
c16 = 0;
ATF_REQUIRE(mbrtoc16(&c16, "\xc3", 1, &s) == (size_t)-2);
ATF_REQUIRE(c16 == 0);
ATF_REQUIRE(mbrtoc16(&c16, "\xb7", 1, &s) == 1);
ATF_REQUIRE(c16 == 0xf7);
/* Surrogate pair. */
memset(&s, 0, sizeof(s));
c16 = 0;
ATF_REQUIRE(mbrtoc16(&c16, "\xf0\x9f\x92\xa9", 4, &s) == 4);
ATF_REQUIRE(c16 == 0xd83d);
ATF_REQUIRE(mbrtoc16(&c16, "", 0, &s) == (size_t)-3);
ATF_REQUIRE(c16 == 0xdca9);
/* Letter e with acute, precomposed. */
memset(&s, 0, sizeof(s));
c16 = 0;
ATF_REQUIRE(mbrtoc16(&c16, "\xc3\xa9", 2, &s) == 2);
ATF_REQUIRE(c16 == 0xe9);
/* Letter e with acute, combined. */
memset(&s, 0, sizeof(s));
c16 = 0;
ATF_REQUIRE(mbrtoc16(&c16, "\x65\xcc\x81", 3, &s) == 1);
ATF_REQUIRE(c16 == 0x65);
ATF_REQUIRE(mbrtoc16(&c16, "\xcc\x81", 2, &s) == 2);
ATF_REQUIRE(c16 == 0x301);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mbrtoc16_c_locale_test);
ATF_TP_ADD_TC(tp, mbrtoc16_iso_8859_1_test);
ATF_TP_ADD_TC(tp, mbrtoc16_iso_8859_15_test);
ATF_TP_ADD_TC(tp, mbrtoc16_utf_8_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mbrtowc_test.c b/lib/libc/tests/locale/mbrtowc_test.c
index a7b7f9ae08a6..df611a7df573 100644
--- a/lib/libc/tests/locale/mbrtowc_test.c
+++ b/lib/libc/tests/locale/mbrtowc_test.c
@@ -1,163 +1,162 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mbrtowc(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(mbrtowc_test);
ATF_TC_BODY(mbrtowc_test, tc)
{
mbstate_t s;
wchar_t wc;
char buf[MB_LEN_MAX + 1];
/*
* C/POSIX locale.
*/
ATF_REQUIRE(MB_CUR_MAX == 1);
/* Null wide character, internal state. */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0;
ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 0);
ATF_REQUIRE(wc == 0);
/* Null wide character. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 0);
ATF_REQUIRE(wc == 0);
/* Latin letter A, internal state. */
ATF_REQUIRE(mbrtowc(NULL, 0, 0, NULL) == 0);
buf[0] = 'A';
ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 1);
ATF_REQUIRE(wc == L'A');
/* Latin letter A. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 1);
ATF_REQUIRE(wc == L'A');
/* Incomplete character sequence. */
wc = L'z';
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtowc(&wc, buf, 0, &s) == (size_t)-2);
ATF_REQUIRE(wc == L'z');
/* Check that mbrtowc() doesn't access the buffer when n == 0. */
wc = L'z';
memset(&s, 0, sizeof(s));
buf[0] = '\0';
ATF_REQUIRE(mbrtowc(&wc, buf, 0, &s) == (size_t)-2);
ATF_REQUIRE(wc == L'z');
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
/* Null wide character, internal state. */
ATF_REQUIRE(mbrtowc(NULL, 0, 0, NULL) == 0);
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0;
ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 0);
ATF_REQUIRE(wc == 0);
/* Null wide character. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 0);
ATF_REQUIRE(wc == 0);
/* Latin letter A, internal state. */
ATF_REQUIRE(mbrtowc(NULL, 0, 0, NULL) == 0);
buf[0] = 'A';
ATF_REQUIRE(mbrtowc(&wc, buf, 1, NULL) == 1);
ATF_REQUIRE(wc == L'A');
/* Latin letter A. */
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 1);
ATF_REQUIRE(wc == L'A');
/* Incomplete character sequence (zero length). */
wc = L'z';
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbrtowc(&wc, buf, 0, &s) == (size_t)-2);
ATF_REQUIRE(wc == L'z');
/* Incomplete character sequence (truncated double-byte). */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0xa3;
buf[1] = 0x00;
memset(&s, 0, sizeof(s));
wc = 0;
ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == (size_t)-2);
/* Same as above, but complete. */
buf[1] = 0xc1;
memset(&s, 0, sizeof(s));
wc = 0;
ATF_REQUIRE(mbrtowc(&wc, buf, 2, &s) == 2);
ATF_REQUIRE(wc == 0xa3c1);
/* Test restarting behaviour. */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0xa3;
memset(&s, 0, sizeof(s));
wc = 0;
ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == (size_t)-2);
ATF_REQUIRE(wc == 0);
buf[0] = 0xc1;
ATF_REQUIRE(mbrtowc(&wc, buf, 1, &s) == 1);
ATF_REQUIRE(wc == 0xa3c1);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mbrtowc_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mbsnrtowcs_test.c b/lib/libc/tests/locale/mbsnrtowcs_test.c
index 3295379eee0d..a355bc7d7a6a 100644
--- a/lib/libc/tests/locale/mbsnrtowcs_test.c
+++ b/lib/libc/tests/locale/mbsnrtowcs_test.c
@@ -1,193 +1,192 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mbsnrtowcs().
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(mbsnrtowcs_test);
ATF_TC_BODY(mbsnrtowcs_test, tc)
{
char srcbuf[128];
wchar_t dstbuf[128];
char *src;
mbstate_t s;
/* C/POSIX locale. */
/* Simple null terminated string. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 5);
ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
ATF_REQUIRE(dstbuf[6] == 0xcccc);
ATF_REQUIRE(src == NULL);
/* Simple null terminated string, stopping early. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 4, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 4);
ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
ATF_REQUIRE(dstbuf[5] == 0xcccc);
ATF_REQUIRE(src == srcbuf + 4);
/* Not enough space in destination buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, 4, &s) == 4);
ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
ATF_REQUIRE(dstbuf[5] == 0xcccc);
ATF_REQUIRE(src == srcbuf + 4);
/* Null terminated string, internal dest. buffer */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsnrtowcs(NULL, (const char **)&src, 6, 0, &s) == 5);
/* Null terminated string, internal dest. buffer, stopping early */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsnrtowcs(NULL, (const char **)&src, 4, 0, &s) == 4);
/* Null terminated string, internal state. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
src = srcbuf;
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) /
sizeof(*dstbuf), NULL) == 5);
ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
ATF_REQUIRE(dstbuf[6] == 0xcccc);
ATF_REQUIRE(src == NULL);
/* Null terminated string, internal state, internal dest. buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
src = srcbuf;
ATF_REQUIRE(mbsnrtowcs(NULL, (const char **)&src, 6, 0, NULL) == 5);
/* Empty source buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
srcbuf[0] = '\0';
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, 1, &s) == 0);
ATF_REQUIRE(dstbuf[0] == 0);
ATF_REQUIRE(dstbuf[1] == 0xcccc);
ATF_REQUIRE(src == NULL);
/* Zero length destination buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, 0, &s) == 0);
ATF_REQUIRE(dstbuf[0] == 0xcccc);
ATF_REQUIRE(src == srcbuf);
/* Zero length source buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 0, 1, &s) == 0);
ATF_REQUIRE(dstbuf[0] == 0xcccc);
ATF_REQUIRE(src == srcbuf);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 8, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 5);
ATF_REQUIRE(dstbuf[0] == 0xA3C1 && dstbuf[1] == 0x20 && dstbuf[2] == 0x42 &&
dstbuf[3] == 0x20 && dstbuf[4] == 0xA3C3 && dstbuf[5] == 0);
ATF_REQUIRE(src == NULL);
/* Partial character. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 6, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 4);
ATF_REQUIRE(src == srcbuf + 6);
ATF_REQUIRE(!mbsinit(&s));
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 1);
ATF_REQUIRE(src == srcbuf + 7);
ATF_REQUIRE(mbsnrtowcs(dstbuf, (const char **)&src, 1, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 0);
ATF_REQUIRE(src == NULL);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mbsnrtowcs_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mbsrtowcs_test.c b/lib/libc/tests/locale/mbsrtowcs_test.c
index 8c67023b134d..d8d215fda2ad 100644
--- a/lib/libc/tests/locale/mbsrtowcs_test.c
+++ b/lib/libc/tests/locale/mbsrtowcs_test.c
@@ -1,151 +1,150 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mbsrtowcs(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(mbsrtowcs_test);
ATF_TC_BODY(mbsrtowcs_test, tc)
{
char srcbuf[128];
wchar_t dstbuf[128];
char *src;
mbstate_t s;
/*
* C/POSIX locale.
*/
/* Simple null terminated string. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 5);
ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
ATF_REQUIRE(dstbuf[6] == 0xcccc);
ATF_REQUIRE(src == NULL);
/* Not enough space in destination buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, 4, &s) == 4);
ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
ATF_REQUIRE(dstbuf[5] == 0xcccc);
ATF_REQUIRE(src == srcbuf + 4);
/* Null terminated string, internal dest. buffer */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(mbsrtowcs(NULL, (const char **)&src, 0, &s) == 5);
/* Null terminated string, internal state. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
src = srcbuf;
ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, sizeof(dstbuf) /
sizeof(*dstbuf), NULL) == 5);
ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
ATF_REQUIRE(dstbuf[6] == 0xcccc);
ATF_REQUIRE(src == NULL);
/* Null terminated string, internal state, internal dest. buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
src = srcbuf;
ATF_REQUIRE(mbsrtowcs(NULL, (const char **)&src, 0, NULL) == 5);
/* Empty source buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
srcbuf[0] = '\0';
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, 1, &s) == 0);
ATF_REQUIRE(dstbuf[0] == 0);
ATF_REQUIRE(dstbuf[1] == 0xcccc);
ATF_REQUIRE(src == NULL);
/* Zero length destination buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, 0, &s) == 0);
ATF_REQUIRE(dstbuf[0] == 0xcccc);
ATF_REQUIRE(src == srcbuf);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
src = srcbuf;
memset(&s, 0, sizeof(s));
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbsrtowcs(dstbuf, (const char **)&src, sizeof(dstbuf) /
sizeof(*dstbuf), &s) == 5);
ATF_REQUIRE(dstbuf[0] == 0xA3C1 && dstbuf[1] == 0x20 && dstbuf[2] == 0x42 &&
dstbuf[3] == 0x20 && dstbuf[4] == 0xA3C3 && dstbuf[5] == 0);
ATF_REQUIRE(src == NULL);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mbsrtowcs_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mbstowcs_test.c b/lib/libc/tests/locale/mbstowcs_test.c
index ad5ac183ba5f..404adfd7b19a 100644
--- a/lib/libc/tests/locale/mbstowcs_test.c
+++ b/lib/libc/tests/locale/mbstowcs_test.c
@@ -1,109 +1,108 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mbstowcs(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(mbstowcs_test);
ATF_TC_BODY(mbstowcs_test, tc)
{
char srcbuf[128];
wchar_t dstbuf[128];
/* C/POSIX locale. */
/* Simple null terminated string. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, sizeof(dstbuf) / sizeof(*dstbuf)) == 5);
ATF_REQUIRE(wcscmp(dstbuf, L"hello") == 0);
ATF_REQUIRE(dstbuf[6] == 0xcccc);
/* Not enough space in destination buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, 4) == 4);
ATF_REQUIRE(wmemcmp(dstbuf, L"hell", 4) == 0);
ATF_REQUIRE(dstbuf[5] == 0xcccc);
/* Null terminated string, internal dest. buffer (XSI extension) */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
ATF_REQUIRE(mbstowcs(NULL, srcbuf, 0) == 5);
/* Empty source buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
srcbuf[0] = '\0';
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, 1) == 0);
ATF_REQUIRE(dstbuf[0] == 0);
ATF_REQUIRE(dstbuf[1] == 0xcccc);
/* Zero length destination buffer. */
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "hello");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, 0) == 0);
ATF_REQUIRE(dstbuf[0] == 0xcccc);
/* Japanese (EUC) locale. */
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
memset(srcbuf, 0xcc, sizeof(srcbuf));
strcpy(srcbuf, "\xA3\xC1 B \xA3\xC3");
wmemset(dstbuf, 0xcccc, sizeof(dstbuf) / sizeof(*dstbuf));
ATF_REQUIRE(mbstowcs(dstbuf, srcbuf, sizeof(dstbuf) / sizeof(*dstbuf)) == 5);
ATF_REQUIRE(dstbuf[0] == 0xA3C1 && dstbuf[1] == 0x20 && dstbuf[2] == 0x42 &&
dstbuf[3] == 0x20 && dstbuf[4] == 0xA3C3 && dstbuf[5] == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mbstowcs_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/mbtowc_test.c b/lib/libc/tests/locale/mbtowc_test.c
index 2a58b60df908..e5ff276b4610 100644
--- a/lib/libc/tests/locale/mbtowc_test.c
+++ b/lib/libc/tests/locale/mbtowc_test.c
@@ -1,120 +1,119 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mbtowc(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1990.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(mbtowc_test);
ATF_TC_BODY(mbtowc_test, tc)
{
char buf[MB_LEN_MAX + 1];
wchar_t wc;
/* C/POSIX locale. */
ATF_REQUIRE(MB_CUR_MAX == 1);
/* No shift states in C locale. */
ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
/* Null wide character. */
wc = 0xcccc;
memset(buf, 0, sizeof(buf));
ATF_REQUIRE(mbtowc(&wc, buf, 1) == 0);
ATF_REQUIRE(wc == 0);
/* Latin letter A. */
buf[0] = 'A';
ATF_REQUIRE(mbtowc(&wc, buf, 1) == 1);
ATF_REQUIRE(wc == L'A');
/* Incomplete character sequence. */
wc = L'z';
buf[0] = '\0';
ATF_REQUIRE(mbtowc(&wc, buf, 0) == -1);
ATF_REQUIRE(wc == L'z');
ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
/* Japanese (EUC) locale. */
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
/* Null wide character */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0;
wc = 0xcccc;
ATF_REQUIRE(mbtowc(&wc, buf, 1) == 0);
ATF_REQUIRE(wc == 0);
/* Latin letter A. */
buf[0] = 'A';
ATF_REQUIRE(mbtowc(&wc, buf, 1) == 1);
ATF_REQUIRE(wc == L'A');
/* Incomplete character sequence (zero length). */
wc = L'z';
buf[0] = '\0';
ATF_REQUIRE(mbtowc(&wc, buf, 0) == -1);
ATF_REQUIRE(wc == L'z');
ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
/* Incomplete character sequence (truncated double-byte). */
memset(buf, 0xcc, sizeof(buf));
buf[0] = 0xa3;
buf[1] = 0x00;
wc = L'z';
ATF_REQUIRE(mbtowc(&wc, buf, 1) == -1);
ATF_REQUIRE(wc == L'z');
ATF_REQUIRE(mbtowc(NULL, NULL, 0) == 0);
/* Same as above, but complete. */
buf[1] = 0xc1;
ATF_REQUIRE(mbtowc(&wc, buf, 2) == 2);
ATF_REQUIRE(wc == 0xa3c1);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mbtowc_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/towctrans_test.c b/lib/libc/tests/locale/towctrans_test.c
index 734c7557252d..f34eb554f283 100644
--- a/lib/libc/tests/locale/towctrans_test.c
+++ b/lib/libc/tests/locale/towctrans_test.c
@@ -1,88 +1,87 @@
/*-
* Copyright (c) 2003 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wctrans() and towctrans() as specified by
* IEEE Std. 1003.1-2001 and ISO/IEC 9899:1999.
*
* The functions are tested in the "C" and "ja_JP.eucJP" locales.
*/
-#include <sys/cdefs.h>
#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <wctype.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(towctrans_test);
ATF_TC_BODY(towctrans_test, tc)
{
wctype_t t;
int i, j;
struct {
const char *name;
wint_t (*func)(wint_t);
} tran[] = {
{ "tolower", towlower },
{ "toupper", towupper },
};
/* C/POSIX locale. */
for (i = 0; i < sizeof(tran) / sizeof(*tran); i++) {
t = wctrans(tran[i].name);
ATF_REQUIRE(t != 0);
for (j = 0; j < 256; j++)
ATF_REQUIRE(tran[i].func(j) == towctrans(j, t));
}
t = wctrans("elephant");
ATF_REQUIRE(t == 0);
for (i = 0; i < 256; i++)
ATF_REQUIRE(towctrans(i, t) == i);
/* Japanese (EUC) locale. */
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
for (i = 0; i < sizeof(tran) / sizeof(*tran); i++) {
t = wctrans(tran[i].name);
ATF_REQUIRE(t != 0);
for (j = 0; j < 65536; j++)
ATF_REQUIRE(tran[i].func(j) == towctrans(j, t));
}
t = wctrans("elephant");
ATF_REQUIRE(t == 0);
for (i = 0; i < 65536; i++)
ATF_REQUIRE(towctrans(i, t) == i);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, towctrans_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/wcrtomb_test.c b/lib/libc/tests/locale/wcrtomb_test.c
index 58713faf625d..2bc7cbc2365f 100644
--- a/lib/libc/tests/locale/wcrtomb_test.c
+++ b/lib/libc/tests/locale/wcrtomb_test.c
@@ -1,133 +1,132 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wcrtomb(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(wcrtomb_test);
ATF_TC_BODY(wcrtomb_test, tc)
{
mbstate_t s;
size_t len;
char buf[MB_LEN_MAX + 1];
/* C/POSIX locale. */
ATF_REQUIRE(MB_CUR_MAX == 1);
/*
* If the buffer argument is NULL, wc is implicitly L'\0',
* wcrtomb() resets its internal state.
*/
ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
ATF_REQUIRE(wcrtomb(NULL, UCHAR_MAX + 1, NULL) == 1);
/* Null wide character. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
len = wcrtomb(buf, L'\0', &s);
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
/* Latin letter A, internal state. */
ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
ATF_REQUIRE(wcrtomb(NULL, L'A', NULL) == 1);
/* Latin letter A. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
len = wcrtomb(buf, L'A', &s);
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
/* Invalid code. */
ATF_REQUIRE(wcrtomb(buf, UCHAR_MAX + 1, NULL) == (size_t)-1);
ATF_REQUIRE(errno == EILSEQ);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX == 3);
/*
* If the buffer argument is NULL, wc is implicitly L'\0',
* wcrtomb() resets its internal state.
*/
ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
/* Null wide character. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
len = wcrtomb(buf, L'\0', &s);
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
/* Latin letter A, internal state. */
ATF_REQUIRE(wcrtomb(NULL, L'\0', NULL) == 1);
ATF_REQUIRE(wcrtomb(NULL, L'A', NULL) == 1);
/* Latin letter A. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
len = wcrtomb(buf, L'A', &s);
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
/* Full width letter A. */
memset(&s, 0, sizeof(s));
memset(buf, 0xcc, sizeof(buf));
len = wcrtomb(buf, 0xa3c1, &s);
ATF_REQUIRE(len == 2);
ATF_REQUIRE((unsigned char)buf[0] == 0xa3 &&
(unsigned char)buf[1] == 0xc1 &&
(unsigned char)buf[2] == 0xcc);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, wcrtomb_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/wcsnrtombs_test.c b/lib/libc/tests/locale/wcsnrtombs_test.c
index d6b8be0dbdbe..8764c1567066 100644
--- a/lib/libc/tests/locale/wcsnrtombs_test.c
+++ b/lib/libc/tests/locale/wcsnrtombs_test.c
@@ -1,193 +1,192 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wcsnrtombs().
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(wcsnrtombs_test);
ATF_TC_BODY(wcsnrtombs_test, tc)
{
wchar_t srcbuf[128];
char dstbuf[128];
wchar_t *src;
mbstate_t s;
/* C/POSIX locale. */
/* Simple null terminated string. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, sizeof(dstbuf),
&s) == 5);
ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
ATF_REQUIRE(src == NULL);
/* Simple null terminated string, stopping early. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 4, sizeof(dstbuf),
&s) == 4);
ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
ATF_REQUIRE(src == srcbuf + 4);
/* Not enough space in destination buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, 4,
&s) == 4);
ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
ATF_REQUIRE(src == srcbuf + 4);
/* Null terminated string, internal dest. buffer */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(NULL, (const wchar_t **)&src, 6, sizeof(dstbuf),
&s) == 5);
/* Null terminated string, internal dest. buffer, stopping early. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(NULL, (const wchar_t **)&src, 4, sizeof(dstbuf),
&s) == 4);
/* Null terminated string, internal state. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, sizeof(dstbuf),
NULL) == 5);
ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
ATF_REQUIRE(src == NULL);
/* Null terminated string, internal state, internal dest. buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
src = srcbuf;
ATF_REQUIRE(wcsnrtombs(NULL, (const wchar_t **)&src, 6, 0, NULL) == 5);
/* Empty source buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
srcbuf[0] = L'\0';
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 1, sizeof(dstbuf),
&s) == 0);
ATF_REQUIRE(dstbuf[0] == L'\0');
/* Zero length destination buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, 0, &s) == 0);
ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
/* Zero length source buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 0, sizeof(dstbuf),
&s) == 0);
ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
ATF_REQUIRE(src == srcbuf);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
srcbuf[0] = 0xA3C1;
srcbuf[1] = 0x0020;
srcbuf[2] = 0x0042;
srcbuf[3] = 0x0020;
srcbuf[4] = 0xA3C3;
srcbuf[5] = 0x0000;
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, sizeof(dstbuf),
&s) == 7);
ATF_REQUIRE(strcmp(dstbuf, "\xA3\xC1 B \xA3\xC3") == 0);
ATF_REQUIRE((unsigned char)dstbuf[8] == 0xcc);
ATF_REQUIRE(src == NULL);
/* Stopping early. */
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsnrtombs(dstbuf, (const wchar_t **)&src, 6, 6,
&s) == 5);
ATF_REQUIRE(memcmp(dstbuf, "\xA3\xC1 B ", 5) == 0);
ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
ATF_REQUIRE(src == srcbuf + 4);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, wcsnrtombs_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/wcsrtombs_test.c b/lib/libc/tests/locale/wcsrtombs_test.c
index 10f4a4d46e1a..dcb111dfd87c 100644
--- a/lib/libc/tests/locale/wcsrtombs_test.c
+++ b/lib/libc/tests/locale/wcsrtombs_test.c
@@ -1,154 +1,153 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wcsrtombs(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(wcsrtombs_test);
ATF_TC_BODY(wcsrtombs_test, tc)
{
wchar_t srcbuf[128];
char dstbuf[128];
wchar_t *src;
mbstate_t s;
/* C/POSIX locale. */
/* Simple null terminated string. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
&s) == 5);
ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
ATF_REQUIRE(src == NULL);
/* Not enough space in destination buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, 4,
&s) == 4);
ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
ATF_REQUIRE(src == srcbuf + 4);
/* Null terminated string, internal dest. buffer */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsrtombs(NULL, (const wchar_t **)&src, sizeof(dstbuf),
&s) == 5);
/* Null terminated string, internal state. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
NULL) == 5);
ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
ATF_REQUIRE(src == NULL);
/* Null terminated string, internal state, internal dest. buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
src = srcbuf;
ATF_REQUIRE(wcsrtombs(NULL, (const wchar_t **)&src, 0, NULL) == 5);
/* Empty source buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
srcbuf[0] = L'\0';
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
&s) == 0);
ATF_REQUIRE(dstbuf[0] == L'\0');
/* Zero length destination buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, 0, &s) == 0);
ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
srcbuf[0] = 0xA3C1;
srcbuf[1] = 0x0020;
srcbuf[2] = 0x0042;
srcbuf[3] = 0x0020;
srcbuf[4] = 0xA3C3;
srcbuf[5] = 0x0000;
memset(dstbuf, 0xcc, sizeof(dstbuf));
src = srcbuf;
memset(&s, 0, sizeof(s));
ATF_REQUIRE(wcsrtombs(dstbuf, (const wchar_t **)&src, sizeof(dstbuf),
&s) == 7);
ATF_REQUIRE(strcmp(dstbuf, "\xA3\xC1 B \xA3\xC3") == 0);
ATF_REQUIRE((unsigned char)dstbuf[8] == 0xcc);
ATF_REQUIRE(src == NULL);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, wcsrtombs_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/wcstombs_test.c b/lib/libc/tests/locale/wcstombs_test.c
index 90f893b2fb31..2506be2806f6 100644
--- a/lib/libc/tests/locale/wcstombs_test.c
+++ b/lib/libc/tests/locale/wcstombs_test.c
@@ -1,128 +1,127 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wcstombs(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(wcstombs_test);
ATF_TC_BODY(wcstombs_test, tc)
{
wchar_t srcbuf[128];
char dstbuf[128];
/* C/POSIX locale. */
/* Simple null terminated string. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 5);
ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
/* Not enough space in destination buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
ATF_REQUIRE(wcstombs(dstbuf, srcbuf, 4) == 4);
ATF_REQUIRE(memcmp(dstbuf, "hell", 4) == 0);
ATF_REQUIRE((unsigned char)dstbuf[5] == 0xcc);
/* Null terminated string, internal dest. buffer */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
ATF_REQUIRE(wcstombs(NULL, srcbuf, sizeof(dstbuf)) == 5);
/* Null terminated string, internal state. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 5);
ATF_REQUIRE(strcmp(dstbuf, "hello") == 0);
ATF_REQUIRE((unsigned char)dstbuf[6] == 0xcc);
/* Null terminated string, internal state, internal dest. buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
ATF_REQUIRE(wcstombs(NULL, srcbuf, 0) == 5);
/* Empty source buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
srcbuf[0] = L'\0';
memset(dstbuf, 0xcc, sizeof(dstbuf));
ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 0);
ATF_REQUIRE(dstbuf[0] == L'\0');
/* Zero length destination buffer. */
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
wcscpy(srcbuf, L"hello");
memset(dstbuf, 0xcc, sizeof(dstbuf));
ATF_REQUIRE(wcstombs(dstbuf, srcbuf, 0) == 0);
ATF_REQUIRE((unsigned char)dstbuf[0] == 0xcc);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX > 1);
wmemset(srcbuf, 0xcc, sizeof(srcbuf) / sizeof(*srcbuf));
srcbuf[0] = 0xA3C1;
srcbuf[1] = 0x0020;
srcbuf[2] = 0x0042;
srcbuf[3] = 0x0020;
srcbuf[4] = 0xA3C3;
srcbuf[5] = 0x0000;
memset(dstbuf, 0xcc, sizeof(dstbuf));
ATF_REQUIRE(wcstombs(dstbuf, srcbuf, sizeof(dstbuf)) == 7);
ATF_REQUIRE(strcmp(dstbuf, "\xA3\xC1 B \xA3\xC3") == 0);
ATF_REQUIRE((unsigned char)dstbuf[8] == 0xcc);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, wcstombs_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/locale/wctomb_test.c b/lib/libc/tests/locale/wctomb_test.c
index a1f19a44be4b..1e142ed74c48 100644
--- a/lib/libc/tests/locale/wctomb_test.c
+++ b/lib/libc/tests/locale/wctomb_test.c
@@ -1,111 +1,110 @@
/*-
* Copyright (c) 2002-2004 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for wctomb(), as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*
* The function is tested with both the "C" ("POSIX") LC_CTYPE setting and
* "ja_JP.eucJP". Other encodings are not tested.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(wctomb_test);
ATF_TC_BODY(wctomb_test, tc)
{
size_t len;
char buf[MB_LEN_MAX + 1];
/* C/POSIX locale. */
ATF_REQUIRE(MB_CUR_MAX == 1);
/* No shift states in C locale. */
ATF_REQUIRE(wctomb(NULL, L'\0') == 0);
/* Null wide character. */
memset(buf, 0xcc, sizeof(buf));
len = wctomb(buf, L'\0');
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
/* Latin letter A. */
memset(buf, 0xcc, sizeof(buf));
len = wctomb(buf, L'A');
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
/* Invalid code. */
ATF_REQUIRE(wctomb(buf, UCHAR_MAX + 1) == -1);
ATF_REQUIRE(wctomb(NULL, 0) == 0);
/*
* Japanese (EUC) locale.
*/
ATF_REQUIRE(strcmp(setlocale(LC_CTYPE, "ja_JP.eucJP"), "ja_JP.eucJP") == 0);
ATF_REQUIRE(MB_CUR_MAX == 3);
/* No shift states in EUC encoding. */
ATF_REQUIRE(wctomb(NULL, L'\0') == 0);
/* Null wide character. */
memset(buf, 0xcc, sizeof(buf));
len = wctomb(buf, L'\0');
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 0 && (unsigned char)buf[1] == 0xcc);
/* Latin letter A. */
memset(buf, 0xcc, sizeof(buf));
len = wctomb(buf, L'A');
ATF_REQUIRE(len == 1);
ATF_REQUIRE((unsigned char)buf[0] == 'A' && (unsigned char)buf[1] == 0xcc);
/* Full width letter A. */
memset(buf, 0xcc, sizeof(buf));
len = wctomb(buf, 0xa3c1);
ATF_REQUIRE(len == 2);
ATF_REQUIRE((unsigned char)buf[0] == 0xa3 &&
(unsigned char)buf[1] == 0xc1 &&
(unsigned char)buf[2] == 0xcc);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, wctomb_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/getaddrinfo_test.c b/lib/libc/tests/nss/getaddrinfo_test.c
index b7c4eec99779..4528e272a46f 100644
--- a/lib/libc/tests/nss/getaddrinfo_test.c
+++ b/lib/libc/tests/nss/getaddrinfo_test.c
@@ -1,555 +1,554 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include <atf-c.h>
#include "freebsd_test_suite/macros.h"
#include "testutil.h"
enum test_methods {
TEST_GETADDRINFO,
TEST_BUILD_SNAPSHOT
};
static struct addrinfo hints;
static enum test_methods method = TEST_GETADDRINFO;
DECLARE_TEST_DATA(addrinfo)
DECLARE_TEST_FILE_SNAPSHOT(addrinfo)
DECLARE_2PASS_TEST(addrinfo)
static void clone_addrinfo(struct addrinfo *, struct addrinfo const *);
static int compare_addrinfo(struct addrinfo *, struct addrinfo *, void *);
static void dump_addrinfo(struct addrinfo *);
static void sdump_addrinfo(struct addrinfo *, char *, size_t);
IMPLEMENT_TEST_DATA(addrinfo)
IMPLEMENT_TEST_FILE_SNAPSHOT(addrinfo)
IMPLEMENT_2PASS_TEST(addrinfo)
static void
clone_addrinfo(struct addrinfo *dest, struct addrinfo const *src)
{
ATF_REQUIRE(dest != NULL);
ATF_REQUIRE(src != NULL);
memcpy(dest, src, sizeof(struct addrinfo));
if (src->ai_canonname != NULL)
dest->ai_canonname = strdup(src->ai_canonname);
if (src->ai_addr != NULL) {
dest->ai_addr = malloc(src->ai_addrlen);
ATF_REQUIRE(dest->ai_addr != NULL);
memcpy(dest->ai_addr, src->ai_addr, src->ai_addrlen);
}
if (src->ai_next != NULL) {
dest->ai_next = malloc(sizeof(struct addrinfo));
ATF_REQUIRE(dest->ai_next != NULL);
clone_addrinfo(dest->ai_next, src->ai_next);
}
}
static int
compare_addrinfo_(struct addrinfo *ai1, struct addrinfo *ai2)
{
if ((ai1 == NULL) || (ai2 == NULL))
return (-1);
if (ai1->ai_flags != ai2->ai_flags ||
ai1->ai_family != ai2->ai_family ||
ai1->ai_socktype != ai2->ai_socktype ||
ai1->ai_protocol != ai2->ai_protocol ||
ai1->ai_addrlen != ai2->ai_addrlen ||
((ai1->ai_addr == NULL || ai2->ai_addr == NULL) &&
ai1->ai_addr != ai2->ai_addr) ||
((ai1->ai_canonname == NULL || ai2->ai_canonname == NULL) &&
ai1->ai_canonname != ai2->ai_canonname))
return (-1);
if (ai1->ai_canonname != NULL &&
strcmp(ai1->ai_canonname, ai2->ai_canonname) != 0)
return (-1);
if (ai1->ai_addr != NULL &&
memcmp(ai1->ai_addr, ai2->ai_addr, ai1->ai_addrlen) != 0)
return (-1);
if (ai1->ai_next == NULL && ai2->ai_next == NULL)
return (0);
else
return (compare_addrinfo_(ai1->ai_next, ai2->ai_next));
}
static int
compare_addrinfo(struct addrinfo *ai1, struct addrinfo *ai2,
void *mdata __unused)
{
int rv;
printf("testing equality of 2 addrinfo structures\n");
rv = compare_addrinfo_(ai1, ai2);
if (rv == 0)
printf("equal\n");
else {
dump_addrinfo(ai1);
dump_addrinfo(ai2);
printf("not equal\n");
}
return (rv);
}
static void
free_addrinfo(struct addrinfo *ai)
{
if (ai == NULL)
return;
free(ai->ai_addr);
free(ai->ai_canonname);
free_addrinfo(ai->ai_next);
}
void
sdump_addrinfo(struct addrinfo *ai, char *buffer, size_t buflen)
{
int written, i;
written = snprintf(buffer, buflen, "%d %d %d %d %d ",
ai->ai_flags, ai->ai_family, ai->ai_socktype, ai->ai_protocol,
ai->ai_addrlen);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
written = snprintf(buffer, buflen, "%s ",
ai->ai_canonname == NULL ? "(null)" : ai->ai_canonname);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (ai->ai_addr == NULL) {
written = snprintf(buffer, buflen, "(null)");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
} else {
for (i = 0; i < (int)ai->ai_addrlen; i++) {
written = snprintf(buffer, buflen,
i + 1 != (int)ai->ai_addrlen ? "%d." : "%d",
((unsigned char *)ai->ai_addr)[i]);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
}
if (ai->ai_next != NULL) {
written = snprintf(buffer, buflen, ":");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
sdump_addrinfo(ai->ai_next, buffer, buflen);
}
}
void
dump_addrinfo(struct addrinfo *result)
{
if (result != NULL) {
char buffer[2048];
sdump_addrinfo(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
addrinfo_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
{
char *s, *ps, *ts;
ps = addr;
while ((s = strsep(&ps, ".")) != NULL) {
if (len == 0)
return (-1);
*result = (unsigned char)strtol(s, &ts, 10);
++result;
if (*ts != '\0')
return (-1);
--len;
}
if (len != 0)
return (-1);
else
return (0);
}
static int
addrinfo_read_snapshot_ai(struct addrinfo *ai, char *line)
{
char *s, *ps, *ts;
int i, rv, *pi;
rv = 0;
i = 0;
ps = line;
memset(ai, 0, sizeof(struct addrinfo));
while ((s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
case 1:
case 2:
case 3:
pi = &ai->ai_flags + i;
*pi = (int)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 4:
ai->ai_addrlen = (socklen_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 5:
if (strcmp(s, "(null)") != 0) {
ai->ai_canonname = strdup(s);
ATF_REQUIRE(ai->ai_canonname != NULL);
}
break;
case 6:
if (strcmp(s, "(null)") != 0) {
ai->ai_addr = calloc(1, ai->ai_addrlen);
ATF_REQUIRE(ai->ai_addr != NULL);
rv = addrinfo_read_snapshot_addr(s,
(unsigned char *)ai->ai_addr,
ai->ai_addrlen);
if (rv != 0)
goto fin;
}
break;
default:
/* NOTE: should not be reachable */
rv = -1;
goto fin;
}
++i;
}
fin:
if (i != 7 || rv != 0) {
free_addrinfo(ai);
ai = NULL;
return (-1);
}
return (0);
}
static int
addrinfo_read_snapshot_func(struct addrinfo *ai, char *line)
{
struct addrinfo *ai2;
char *s, *ps;
int rv;
printf("1 line read from snapshot:\n%s\n", line);
rv = 0;
ps = line;
s = strsep(&ps, ":");
if (s == NULL)
return (-1);
rv = addrinfo_read_snapshot_ai(ai, s);
if (rv != 0)
return (-1);
ai2 = ai;
while ((s = strsep(&ps, ":")) != NULL) {
ai2->ai_next = calloc(1, sizeof(struct addrinfo));
ATF_REQUIRE(ai2->ai_next != NULL);
rv = addrinfo_read_snapshot_ai(ai2->ai_next, s);
if (rv != 0) {
free_addrinfo(ai);
ai = NULL;
return (-1);
}
ai2 = ai2->ai_next;
}
return (0);
}
static int
addrinfo_test_correctness(struct addrinfo *ai, void *mdata __unused)
{
printf("testing correctness with the following data:\n");
dump_addrinfo(ai);
if (ai == NULL)
goto errfin;
if (!(ai->ai_family >= 0 && ai->ai_family < AF_MAX))
goto errfin;
if (ai->ai_socktype != 0 && ai->ai_socktype != SOCK_STREAM &&
ai->ai_socktype != SOCK_DGRAM && ai->ai_socktype != SOCK_RAW)
goto errfin;
if (ai->ai_protocol != 0 && ai->ai_protocol != IPPROTO_UDP &&
ai->ai_protocol != IPPROTO_TCP)
goto errfin;
if ((ai->ai_flags & ~(AI_CANONNAME | AI_NUMERICHOST | AI_PASSIVE)) != 0)
goto errfin;
if (ai->ai_addrlen != ai->ai_addr->sa_len ||
ai->ai_family != ai->ai_addr->sa_family)
goto errfin;
printf("correct\n");
return (0);
errfin:
printf("incorrect\n");
return (-1);
}
static int
addrinfo_read_hostlist_func(struct addrinfo *ai, char *line)
{
struct addrinfo *result;
int rv;
printf("resolving %s: ", line);
rv = getaddrinfo(line, NULL, &hints, &result);
if (rv == 0) {
printf("found\n");
rv = addrinfo_test_correctness(result, NULL);
if (rv != 0) {
freeaddrinfo(result);
result = NULL;
return (rv);
}
clone_addrinfo(ai, result);
freeaddrinfo(result);
result = NULL;
} else {
printf("not found\n");
memset(ai, 0, sizeof(struct addrinfo));
}
return (0);
}
static void
run_tests(char *hostlist_file, const char *snapshot_file, int ai_family)
{
struct addrinfo_test_data td, td_snap;
char *snapshot_file_copy;
int rv;
if (snapshot_file == NULL)
snapshot_file_copy = NULL;
else {
snapshot_file_copy = strdup(snapshot_file);
ATF_REQUIRE(snapshot_file_copy != NULL);
}
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = ai_family;
hints.ai_flags = AI_CANONNAME;
if (snapshot_file != NULL)
method = TEST_BUILD_SNAPSHOT;
TEST_DATA_INIT(addrinfo, &td, clone_addrinfo, free_addrinfo);
TEST_DATA_INIT(addrinfo, &td_snap, clone_addrinfo, free_addrinfo);
ATF_REQUIRE_MSG(access(hostlist_file, R_OK) == 0,
"can't access the hostlist file %s\n", hostlist_file);
printf("building host lists from %s\n", hostlist_file);
rv = TEST_SNAPSHOT_FILE_READ(addrinfo, hostlist_file, &td,
addrinfo_read_hostlist_func);
if (rv != 0)
goto fin;
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
printf("can't access the snapshot "
"file %s\n", snapshot_file);
rv = -1;
goto fin;
}
} else {
rv = TEST_SNAPSHOT_FILE_READ(addrinfo, snapshot_file,
&td_snap, addrinfo_read_snapshot_func);
if (rv != 0) {
printf("error reading snapshot file: %s\n",
strerror(errno));
goto fin;
}
}
}
switch (method) {
case TEST_GETADDRINFO:
if (snapshot_file != NULL)
ATF_CHECK(DO_2PASS_TEST(addrinfo, &td, &td_snap,
compare_addrinfo, NULL) == 0);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL) {
ATF_CHECK(TEST_SNAPSHOT_FILE_WRITE(addrinfo,
snapshot_file, &td, sdump_addrinfo) == 0);
}
break;
default:
break;
}
fin:
TEST_DATA_DESTROY(addrinfo, &td_snap);
TEST_DATA_DESTROY(addrinfo, &td);
free(snapshot_file_copy);
}
#define HOSTLIST_FILE "mach"
#define RUN_TESTS(tc, snapshot_file, ai_family) do { \
char *_hostlist_file; \
ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
run_tests(_hostlist_file, snapshot_file, ai_family); \
free(_hostlist_file); \
} while (0)
ATF_TC_WITHOUT_HEAD(pf_unspec);
ATF_TC_BODY(pf_unspec, tc)
{
RUN_TESTS(tc, NULL, AF_UNSPEC);
}
ATF_TC_WITHOUT_HEAD(pf_unspec_with_snapshot);
ATF_TC_BODY(pf_unspec_with_snapshot, tc)
{
RUN_TESTS(tc, "snapshot_ai", AF_UNSPEC);
}
ATF_TC_WITHOUT_HEAD(pf_inet);
ATF_TC_BODY(pf_inet, tc)
{
ATF_REQUIRE_FEATURE("inet");
RUN_TESTS(tc, NULL, AF_INET);
}
ATF_TC_WITHOUT_HEAD(pf_inet_with_snapshot);
ATF_TC_BODY(pf_inet_with_snapshot, tc)
{
ATF_REQUIRE_FEATURE("inet");
RUN_TESTS(tc, "snapshot_ai4", AF_INET);
}
ATF_TC_WITHOUT_HEAD(pf_inet6);
ATF_TC_BODY(pf_inet6, tc)
{
ATF_REQUIRE_FEATURE("inet6");
RUN_TESTS(tc, NULL, AF_INET6);
}
ATF_TC_WITHOUT_HEAD(pf_inet6_with_snapshot);
ATF_TC_BODY(pf_inet6_with_snapshot, tc)
{
ATF_REQUIRE_FEATURE("inet6");
RUN_TESTS(tc, "snapshot_ai6", AF_INET6);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, pf_unspec);
ATF_TP_ADD_TC(tp, pf_unspec_with_snapshot);
ATF_TP_ADD_TC(tp, pf_inet);
ATF_TP_ADD_TC(tp, pf_inet_with_snapshot);
ATF_TP_ADD_TC(tp, pf_inet6);
ATF_TP_ADD_TC(tp, pf_inet6_with_snapshot);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/getgr_test.c b/lib/libc/tests/nss/getgr_test.c
index 28c5e2e98028..7c0e265fa6f6 100644
--- a/lib/libc/tests/nss/getgr_test.c
+++ b/lib/libc/tests/nss/getgr_test.c
@@ -1,571 +1,570 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <arpa/inet.h>
#include <errno.h>
#include <grp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include <atf-c.h>
#include "testutil.h"
enum test_methods {
TEST_GETGRENT,
TEST_GETGRNAM,
TEST_GETGRGID,
TEST_GETGRENT_2PASS,
TEST_GETGRENT_INTERLEAVED_GETGRNAM,
TEST_GETGRENT_INTERLEAVED_GETGRGID,
TEST_BUILD_SNAPSHOT,
};
DECLARE_TEST_DATA(group)
DECLARE_TEST_FILE_SNAPSHOT(group)
DECLARE_1PASS_TEST(group)
DECLARE_2PASS_TEST(group)
static void clone_group(struct group *, struct group const *);
static int compare_group(struct group *, struct group *, void *);
static void dump_group(struct group *);
static void free_group(struct group *);
static void sdump_group(struct group *, char *, size_t);
static int group_read_snapshot_func(struct group *, char *);
static int group_check_ambiguity(struct group_test_data *, struct group *);
static int group_fill_test_data(struct group_test_data *,
int (*cb)(struct group *, void *));
static int group_test_correctness(struct group *, void *);
static int group_test_getgrnam(struct group *, void *);
static int group_test_getgrgid(struct group *, void *);
static int group_test_getgrent(struct group *, void *);
IMPLEMENT_TEST_DATA(group)
IMPLEMENT_TEST_FILE_SNAPSHOT(group)
IMPLEMENT_1PASS_TEST(group)
IMPLEMENT_2PASS_TEST(group)
static void
clone_group(struct group *dest, struct group const *src)
{
ATF_REQUIRE(dest != NULL);
ATF_REQUIRE(src != NULL);
char **cp;
int members_num;
memset(dest, 0, sizeof(struct group));
if (src->gr_name != NULL) {
dest->gr_name = strdup(src->gr_name);
ATF_REQUIRE(dest->gr_name != NULL);
}
if (src->gr_passwd != NULL) {
dest->gr_passwd = strdup(src->gr_passwd);
ATF_REQUIRE(dest->gr_passwd != NULL);
}
dest->gr_gid = src->gr_gid;
if (src->gr_mem != NULL) {
members_num = 0;
for (cp = src->gr_mem; *cp; ++cp)
++members_num;
dest->gr_mem = calloc(members_num + 1, sizeof(char *));
ATF_REQUIRE(dest->gr_mem != NULL);
for (cp = src->gr_mem; *cp; ++cp) {
dest->gr_mem[cp - src->gr_mem] = strdup(*cp);
ATF_REQUIRE(dest->gr_mem[cp - src->gr_mem] != NULL);
}
}
}
static void
free_group(struct group *grp)
{
char **cp;
ATF_REQUIRE(grp != NULL);
free(grp->gr_name);
free(grp->gr_passwd);
for (cp = grp->gr_mem; *cp; ++cp)
free(*cp);
free(grp->gr_mem);
}
static int
compare_group(struct group *grp1, struct group *grp2, void *mdata)
{
char **c1, **c2;
if (grp1 == grp2)
return (0);
if (grp1 == NULL || grp2 == NULL)
goto errfin;
if (strcmp(grp1->gr_name, grp2->gr_name) != 0 ||
strcmp(grp1->gr_passwd, grp2->gr_passwd) != 0 ||
grp1->gr_gid != grp2->gr_gid)
goto errfin;
c1 = grp1->gr_mem;
c2 = grp2->gr_mem;
if (grp1->gr_mem == NULL || grp2->gr_mem == NULL)
goto errfin;
for (; *c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if (*c1 != NULL || *c2 != NULL)
goto errfin;
return 0;
errfin:
if (mdata == NULL) {
printf("following structures are not equal:\n");
dump_group(grp1);
dump_group(grp2);
}
return (-1);
}
static void
sdump_group(struct group *grp, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s:%s:%d:",
grp->gr_name, grp->gr_passwd, grp->gr_gid);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (grp->gr_mem != NULL) {
if (*(grp->gr_mem) != NULL) {
for (cp = grp->gr_mem; *cp; ++cp) {
written = snprintf(buffer, buflen, "%s%s",
cp == grp->gr_mem ? "" : ",", *cp);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, "nomem");
} else
snprintf(buffer, buflen, "(null)");
}
static int
group_read_snapshot_func(struct group *grp, char *line)
{
StringList *sl;
char *s, *ps, *ts;
const char *sep;
int i;
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
sep = ":";
memset(grp, 0, sizeof(struct group));
while ((s = strsep(&ps, sep)) != NULL) {
switch (i) {
case 0:
grp->gr_name = strdup(s);
ATF_REQUIRE(grp->gr_name != NULL);
break;
case 1:
grp->gr_passwd = strdup(s);
ATF_REQUIRE(grp->gr_passwd != NULL);
break;
case 2:
grp->gr_gid = (gid_t)strtol(s, &ts, 10);
if (*ts != '\0') {
free(grp->gr_name);
free(grp->gr_passwd);
grp->gr_name = NULL;
grp->gr_passwd = NULL;
return (-1);
}
/* Change to parsing groups. */
sep = ",";
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
ATF_REQUIRE(sl != NULL);
if (strcmp(s, "nomem") != 0) {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl, ts);
}
break;
}
++i;
}
if (i < 3) {
free(grp->gr_name);
free(grp->gr_passwd);
memset(grp, 0, sizeof(struct group));
return (-1);
}
sl_add(sl, NULL);
grp->gr_mem = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_group(struct group *result)
{
if (result != NULL) {
char buffer[1024];
sdump_group(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
group_fill_test_data(struct group_test_data *td,
int (*cb)(struct group *, void *))
{
struct group *grp;
setgroupent(1);
while ((grp = getgrent()) != NULL) {
if (group_test_correctness(grp, NULL) == 0) {
TEST_DATA_APPEND(group, td, grp);
if (cb != NULL && cb(grp, td) != 0)
return (-1);
} else {
return (-1);
}
}
endgrent();
return (0);
}
static int
group_test_correctness(struct group *grp, void *mdata __unused)
{
printf("testing correctness with the following data:\n");
dump_group(grp);
if (grp == NULL)
goto errfin;
if (grp->gr_name == NULL)
goto errfin;
if (grp->gr_passwd == NULL)
goto errfin;
if (grp->gr_mem == NULL)
goto errfin;
printf("correct\n");
return (0);
errfin:
printf("incorrect\n");
return (-1);
}
/* group_check_ambiguity() is needed here because when doing the getgrent()
* calls sequence, records from different nsswitch sources can be different,
* though having the same pw_name/pw_uid */
static int
group_check_ambiguity(struct group_test_data *td, struct group *pwd)
{
return (TEST_DATA_FIND(group, td, pwd, compare_group, NULL) !=
NULL ? 0 : -1);
}
static int
group_test_getgrnam(struct group *grp_model, void *mdata)
{
struct group *grp;
printf("testing getgrnam() with the following data:\n");
dump_group(grp_model);
grp = getgrnam(grp_model->gr_name);
if (group_test_correctness(grp, NULL) != 0)
goto errfin;
if (compare_group(grp, grp_model, NULL) != 0 &&
group_check_ambiguity((struct group_test_data *)mdata, grp) != 0)
goto errfin;
return (0);
errfin:
return (-1);
}
static int
group_test_getgrgid(struct group *grp_model, void *mdata)
{
struct group *grp;
printf("testing getgrgid() with the following data...\n");
dump_group(grp_model);
grp = getgrgid(grp_model->gr_gid);
if (group_test_correctness(grp, NULL) != 0 ||
(compare_group(grp, grp_model, NULL) != 0 &&
group_check_ambiguity((struct group_test_data *)mdata, grp) != 0))
return (-1);
else
return (0);
}
static int
group_test_getgrent(struct group *grp, void *mdata __unused)
{
/*
* Only correctness can be checked when doing 1-pass test for
* getgrent().
*/
return (group_test_correctness(grp, NULL));
}
static int
run_tests(const char *snapshot_file, enum test_methods method)
{
struct group_test_data td, td_snap, td_2pass, td_interleaved;
int rv;
TEST_DATA_INIT(group, &td, clone_group, free_group);
TEST_DATA_INIT(group, &td_snap, clone_group, free_group);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(group, snapshot_file,
&td_snap, group_read_snapshot_func);
}
}
rv = group_fill_test_data(&td, NULL);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETGRNAM:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(group, &td,
group_test_getgrnam, (void *)&td);
else
rv = DO_1PASS_TEST(group, &td_snap,
group_test_getgrnam, (void *)&td_snap);
break;
case TEST_GETGRGID:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(group, &td,
group_test_getgrgid, (void *)&td);
else
rv = DO_1PASS_TEST(group, &td_snap,
group_test_getgrgid, (void *)&td_snap);
break;
case TEST_GETGRENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(group, &td, group_test_getgrent,
(void *)&td);
else
rv = DO_2PASS_TEST(group, &td, &td_snap,
compare_group, NULL);
break;
case TEST_GETGRENT_2PASS:
TEST_DATA_INIT(group, &td_2pass, clone_group, free_group);
rv = group_fill_test_data(&td_2pass, NULL);
if (rv != -1)
rv = DO_2PASS_TEST(group, &td, &td_2pass,
compare_group, NULL);
TEST_DATA_DESTROY(group, &td_2pass);
break;
case TEST_GETGRENT_INTERLEAVED_GETGRNAM:
TEST_DATA_INIT(group, &td_interleaved, clone_group, free_group);
rv = group_fill_test_data(&td_interleaved, group_test_getgrnam);
if (rv != -1)
rv = DO_2PASS_TEST(group, &td, &td_interleaved,
compare_group, NULL);
TEST_DATA_DESTROY(group, &td_interleaved);
break;
case TEST_GETGRENT_INTERLEAVED_GETGRGID:
TEST_DATA_INIT(group, &td_interleaved, clone_group, free_group);
rv = group_fill_test_data(&td_interleaved, group_test_getgrgid);
if (rv != -1)
rv = DO_2PASS_TEST(group, &td, &td_interleaved,
compare_group, NULL);
TEST_DATA_DESTROY(group, &td_interleaved);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(group, snapshot_file, &td,
sdump_group);
break;
default:
rv = 0;
break;
}
fin:
TEST_DATA_DESTROY(group, &td_snap);
TEST_DATA_DESTROY(group, &td);
return (rv);
}
#define SNAPSHOT_FILE "snapshot_grp"
ATF_TC_WITHOUT_HEAD(getgrent);
ATF_TC_BODY(getgrent, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrent_with_snapshot);
ATF_TC_BODY(getgrent_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrent_with_two_pass);
ATF_TC_BODY(getgrent_with_two_pass, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT_2PASS) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrgid);
ATF_TC_BODY(getgrgid, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETGRGID) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrgid_with_snapshot);
ATF_TC_BODY(getgrgid_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRGID) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrnam);
ATF_TC_BODY(getgrnam, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETGRNAM) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrnam_with_snapshot);
ATF_TC_BODY(getgrnam_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETGRNAM) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrent_interleaved_getgrnam);
ATF_TC_BODY(getgrent_interleaved_getgrnam, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT_INTERLEAVED_GETGRNAM) == 0);
}
ATF_TC_WITHOUT_HEAD(getgrent_interleaved_getgrgid);
ATF_TC_BODY(getgrent_interleaved_getgrgid, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETGRENT_INTERLEAVED_GETGRGID) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getgrent);
ATF_TP_ADD_TC(tp, getgrent_with_snapshot);
ATF_TP_ADD_TC(tp, getgrent_with_two_pass);
ATF_TP_ADD_TC(tp, getgrgid);
ATF_TP_ADD_TC(tp, getgrgid_with_snapshot);
ATF_TP_ADD_TC(tp, getgrnam);
ATF_TP_ADD_TC(tp, getgrnam_with_snapshot);
ATF_TP_ADD_TC(tp, getgrent_interleaved_getgrnam);
ATF_TP_ADD_TC(tp, getgrent_interleaved_getgrgid);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/gethostby_test.c b/lib/libc/tests/nss/gethostby_test.c
index e13ffce15dac..0ed96170fc6d 100644
--- a/lib/libc/tests/nss/gethostby_test.c
+++ b/lib/libc/tests/nss/gethostby_test.c
@@ -1,1511 +1,1510 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <errno.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include <atf-c.h>
#include "freebsd_test_suite/macros.h"
#include "testutil.h"
enum test_methods {
TEST_GETHOSTBYNAME2,
TEST_GETHOSTBYADDR,
TEST_GETHOSTBYNAME2_GETADDRINFO,
TEST_GETHOSTBYADDR_GETNAMEINFO,
TEST_BUILD_SNAPSHOT,
TEST_BUILD_ADDR_SNAPSHOT
};
static int ipnode_flags = 0;
static int af_type = AF_INET;
static bool use_ipnode_functions;
DECLARE_TEST_DATA(hostent)
DECLARE_TEST_FILE_SNAPSHOT(hostent)
DECLARE_1PASS_TEST(hostent)
DECLARE_2PASS_TEST(hostent)
/* These stubs will use gethostby***() or getipnodeby***() functions,
* depending on the use_ipnode_functions global variable value */
static struct hostent *__gethostbyname2(const char *, int);
static struct hostent *__gethostbyaddr(const void *, socklen_t, int);
static void __freehostent(struct hostent *);
static void clone_hostent(struct hostent *, struct hostent const *);
static int compare_hostent(struct hostent *, struct hostent *, void *);
static void dump_hostent(struct hostent *);
static void free_hostent(struct hostent *);
static int is_hostent_equal(struct hostent *, struct addrinfo *);
static void sdump_hostent(struct hostent *, char *, size_t);
static int hostent_read_hostlist_func(struct hostent *, char *);
static int hostent_read_snapshot_addr(char *, unsigned char *, size_t);
static int hostent_read_snapshot_func(struct hostent *, char *);
static int hostent_test_correctness(struct hostent *, void *);
static int hostent_test_gethostbyaddr(struct hostent *, void *);
static int hostent_test_getaddrinfo_eq(struct hostent *, void *);
static int hostent_test_getnameinfo_eq(struct hostent *, void *);
IMPLEMENT_TEST_DATA(hostent)
IMPLEMENT_TEST_FILE_SNAPSHOT(hostent)
IMPLEMENT_1PASS_TEST(hostent)
IMPLEMENT_2PASS_TEST(hostent)
static struct hostent *
__gethostbyname2(const char *name, int af)
{
struct hostent *he;
int error;
if (use_ipnode_functions) {
error = 0;
he = getipnodebyname(name, af, ipnode_flags, &error);
if (he == NULL)
errno = error;
} else
he = gethostbyname2(name, af);
return (he);
}
static struct hostent *
__gethostbyaddr(const void *addr, socklen_t len, int af)
{
struct hostent *he;
int error;
if (use_ipnode_functions) {
error = 0;
he = getipnodebyaddr(addr, len, af, &error);
if (he == NULL)
errno = error;
} else
he = gethostbyaddr(addr, len, af);
return (he);
}
static void
__freehostent(struct hostent *he)
{
/* NOTE: checking for he != NULL - just in case */
if (use_ipnode_functions && he != NULL)
freehostent(he);
}
static void
clone_hostent(struct hostent *dest, struct hostent const *src)
{
ATF_REQUIRE(dest != NULL);
ATF_REQUIRE(src != NULL);
char **cp;
int aliases_num;
int addrs_num;
size_t offset;
memset(dest, 0, sizeof(struct hostent));
if (src->h_name != NULL) {
dest->h_name = strdup(src->h_name);
ATF_REQUIRE(dest->h_name != NULL);
}
dest->h_addrtype = src->h_addrtype;
dest->h_length = src->h_length;
if (src->h_aliases != NULL) {
aliases_num = 0;
for (cp = src->h_aliases; *cp; ++cp)
++aliases_num;
dest->h_aliases = calloc(aliases_num + 1, sizeof(char *));
ATF_REQUIRE(dest->h_aliases != NULL);
for (cp = src->h_aliases; *cp; ++cp) {
dest->h_aliases[cp - src->h_aliases] = strdup(*cp);
ATF_REQUIRE(dest->h_aliases[cp - src->h_aliases] != NULL);
}
}
if (src->h_addr_list != NULL) {
addrs_num = 0;
for (cp = src->h_addr_list; *cp; ++cp)
++addrs_num;
dest->h_addr_list = calloc(addrs_num + 1, sizeof(char *));
ATF_REQUIRE(dest->h_addr_list != NULL);
for (cp = src->h_addr_list; *cp; ++cp) {
offset = cp - src->h_addr_list;
dest->h_addr_list[offset] = malloc(src->h_length);
ATF_REQUIRE(dest->h_addr_list[offset] != NULL);
memcpy(dest->h_addr_list[offset],
src->h_addr_list[offset], src->h_length);
}
}
}
static void
free_hostent(struct hostent *ht)
{
char **cp;
ATF_REQUIRE(ht != NULL);
free(ht->h_name);
if (ht->h_aliases != NULL) {
for (cp = ht->h_aliases; *cp; ++cp)
free(*cp);
free(ht->h_aliases);
}
if (ht->h_addr_list != NULL) {
for (cp = ht->h_addr_list; *cp; ++cp)
free(*cp);
free(ht->h_addr_list);
}
}
static int
compare_hostent(struct hostent *ht1, struct hostent *ht2, void *mdata)
{
char **c1, **c2, **ct, **cb;
int b;
if (ht1 == ht2)
return 0;
if (ht1 == NULL || ht2 == NULL)
goto errfin;
if (ht1->h_name == NULL || ht2->h_name == NULL)
goto errfin;
if (ht1->h_addrtype != ht2->h_addrtype ||
ht1->h_length != ht2->h_length ||
strcmp(ht1->h_name, ht2->h_name) != 0)
goto errfin;
c1 = ht1->h_aliases;
c2 = ht2->h_aliases;
if ((ht1->h_aliases == NULL || ht2->h_aliases == NULL) &&
ht1->h_aliases != ht2->h_aliases)
goto errfin;
if (c1 != NULL && c2 != NULL) {
cb = c1;
for (;*c1; ++c1) {
b = 0;
for (ct = c2; *ct; ++ct) {
if (strcmp(*c1, *ct) == 0) {
b = 1;
break;
}
}
if (b == 0) {
printf("h1 aliases item can't be found in h2 "
"aliases\n");
goto errfin;
}
}
c1 = cb;
for (;*c2; ++c2) {
b = 0;
for (ct = c1; *ct; ++ct) {
if (strcmp(*c2, *ct) == 0) {
b = 1;
break;
}
}
if (b == 0) {
printf("h2 aliases item can't be found in h1 "
"aliases\n");
goto errfin;
}
}
}
c1 = ht1->h_addr_list;
c2 = ht2->h_addr_list;
if ((ht1->h_addr_list == NULL || ht2->h_addr_list== NULL) &&
ht1->h_addr_list != ht2->h_addr_list)
goto errfin;
if (c1 != NULL && c2 != NULL) {
cb = c1;
for (; *c1; ++c1) {
b = 0;
for (ct = c2; *ct; ++ct) {
if (memcmp(*c1, *ct, ht1->h_length) == 0) {
b = 1;
break;
}
}
if (b == 0) {
printf("h1 addresses item can't be found in "
"h2 addresses\n");
goto errfin;
}
}
c1 = cb;
for (; *c2; ++c2) {
b = 0;
for (ct = c1; *ct; ++ct) {
if (memcmp(*c2, *ct, ht1->h_length) == 0) {
b = 1;
break;
}
}
if (b == 0) {
printf("h2 addresses item can't be found in "
"h1 addresses\n");
goto errfin;
}
}
}
return 0;
errfin:
if (mdata == NULL) {
printf("following structures are not equal:\n");
dump_hostent(ht1);
dump_hostent(ht2);
}
return (-1);
}
static int
check_addrinfo_for_name(struct addrinfo *ai, char const *name)
{
struct addrinfo *ai2;
for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
if (strcmp(ai2->ai_canonname, name) == 0)
return (0);
}
return (-1);
}
static int
check_addrinfo_for_addr(struct addrinfo *ai, char const *addr,
socklen_t addrlen, int af)
{
struct addrinfo *ai2;
for (ai2 = ai; ai2 != NULL; ai2 = ai2->ai_next) {
if (af != ai2->ai_family)
continue;
switch (af) {
case AF_INET:
if (memcmp(addr,
(void *)&((struct sockaddr_in *)ai2->ai_addr)->sin_addr,
MIN(addrlen, ai2->ai_addrlen)) == 0)
return (0);
break;
case AF_INET6:
if (memcmp(addr,
(void *)&((struct sockaddr_in6 *)ai2->ai_addr)->sin6_addr,
MIN(addrlen, ai2->ai_addrlen)) == 0)
return (0);
break;
default:
break;
}
}
return (-1);
}
static int
is_hostent_equal(struct hostent *he, struct addrinfo *ai)
{
char **cp;
int rv;
#ifdef DEBUG
printf("checking equality of he and ai\n");
#endif
rv = check_addrinfo_for_name(ai, he->h_name);
if (rv != 0) {
printf("not equal - he->h_name couldn't be found\n");
return (rv);
}
for (cp = he->h_addr_list; *cp; ++cp) {
rv = check_addrinfo_for_addr(ai, *cp, he->h_length,
he->h_addrtype);
if (rv != 0) {
printf("not equal - one of he->h_addr_list couldn't be found\n");
return (rv);
}
}
#ifdef DEBUG
printf("equal\n");
#endif
return (0);
}
static void
sdump_hostent(struct hostent *ht, char *buffer, size_t buflen)
{
char **cp;
size_t i;
int written;
written = snprintf(buffer, buflen, "%s %d %d",
ht->h_name, ht->h_addrtype, ht->h_length);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (ht->h_aliases != NULL) {
if (*(ht->h_aliases) != NULL) {
for (cp = ht->h_aliases; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s",*cp);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else {
written = snprintf(buffer, buflen, " noaliases");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
}
} else {
written = snprintf(buffer, buflen, " (null)");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
}
written = snprintf(buffer, buflen, " : ");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (ht->h_addr_list != NULL) {
if (*(ht->h_addr_list) != NULL) {
for (cp = ht->h_addr_list; *cp; ++cp) {
for (i = 0; i < (size_t)ht->h_length; ++i) {
written = snprintf(buffer, buflen,
i + 1 != (size_t)ht->h_length ?
"%d." : "%d",
(unsigned char)(*cp)[i]);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
if (*(cp + 1)) {
written = snprintf(buffer, buflen,
" ");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
}
}
} else {
written = snprintf(buffer, buflen, " noaddrs");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
}
} else {
written = snprintf(buffer, buflen, " (null)");
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
}
}
static int
hostent_read_hostlist_func(struct hostent *he, char *line)
{
struct hostent *result;
int rv;
#ifdef DEBUG
printf("resolving %s: ", line);
#endif
result = __gethostbyname2(line, af_type);
if (result != NULL) {
#ifdef DEBUG
printf("found\n");
#endif
rv = hostent_test_correctness(result, NULL);
if (rv != 0) {
__freehostent(result);
return (rv);
}
clone_hostent(he, result);
__freehostent(result);
} else {
#ifdef DEBUG
printf("not found\n");
#endif
memset(he, 0, sizeof(struct hostent));
he->h_name = strdup(line);
ATF_REQUIRE(he->h_name != NULL);
}
return (0);
}
static int
hostent_read_snapshot_addr(char *addr, unsigned char *result, size_t len)
{
char *s, *ps, *ts;
ps = addr;
while ( (s = strsep(&ps, ".")) != NULL) {
if (len == 0)
return (-1);
*result = (unsigned char)strtol(s, &ts, 10);
++result;
if (*ts != '\0')
return (-1);
--len;
}
if (len != 0)
return (-1);
else
return (0);
}
static int
hostent_read_snapshot_func(struct hostent *ht, char *line)
{
StringList *sl1, *sl2;
char *s, *ps, *ts;
int i, rv;
#ifdef DEBUG
printf("1 line read from snapshot:\n%s\n", line);
#endif
rv = 0;
i = 0;
sl1 = sl2 = NULL;
ps = line;
memset(ht, 0, sizeof(struct hostent));
while ((s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
ht->h_name = strdup(s);
ATF_REQUIRE(ht->h_name != NULL);
break;
case 1:
ht->h_addrtype = (int)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 2:
ht->h_length = (int)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 3:
if (sl1 == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl1 = sl_init();
ATF_REQUIRE(sl1 != NULL);
if (strcmp(s, "noaliases") != 0) {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl1, ts);
}
} else {
if (strcmp(s, ":") == 0)
++i;
else {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl1, ts);
}
}
break;
case 4:
if (sl2 == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl2 = sl_init();
ATF_REQUIRE(sl2 != NULL);
if (strcmp(s, "noaddrs") != 0) {
ts = calloc(1, ht->h_length);
ATF_REQUIRE(ts != NULL);
rv = hostent_read_snapshot_addr(s,
(unsigned char *)ts,
ht->h_length);
sl_add(sl2, ts);
if (rv != 0)
goto fin;
}
} else {
ts = calloc(1, ht->h_length);
ATF_REQUIRE(ts != NULL);
rv = hostent_read_snapshot_addr(s,
(unsigned char *)ts, ht->h_length);
sl_add(sl2, ts);
if (rv != 0)
goto fin;
}
break;
default:
break;
}
if (i != 3 && i != 4)
++i;
}
fin:
if (sl1 != NULL) {
sl_add(sl1, NULL);
ht->h_aliases = sl1->sl_str;
}
if (sl2 != NULL) {
sl_add(sl2, NULL);
ht->h_addr_list = sl2->sl_str;
}
if ((i != 4) || (rv != 0)) {
free_hostent(ht);
memset(ht, 0, sizeof(struct hostent));
return (-1);
}
/* NOTE: is it a dirty hack or not? */
free(sl1);
free(sl2);
return (0);
}
static void
dump_hostent(struct hostent *result)
{
if (result != NULL) {
char buffer[1024];
sdump_hostent(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
hostent_test_correctness(struct hostent *ht, void *mdata __unused)
{
#ifdef DEBUG
printf("testing correctness with the following data:\n");
dump_hostent(ht);
#endif
if (ht == NULL)
goto errfin;
if (ht->h_name == NULL)
goto errfin;
if (!((ht->h_addrtype >= 0) && (ht->h_addrtype < AF_MAX)))
goto errfin;
if ((ht->h_length != sizeof(struct in_addr)) &&
(ht->h_length != sizeof(struct in6_addr)))
goto errfin;
if (ht->h_aliases == NULL)
goto errfin;
if (ht->h_addr_list == NULL)
goto errfin;
#ifdef DEBUG
printf("correct\n");
#endif
return (0);
errfin:
printf("incorrect\n");
return (-1);
}
static int
hostent_test_gethostbyaddr(struct hostent *he, void *mdata)
{
struct hostent *result;
struct hostent_test_data *addr_test_data;
int rv;
addr_test_data = (struct hostent_test_data *)mdata;
/* We should omit unresolved hostents */
if (he->h_addr_list != NULL) {
char **cp;
for (cp = he->h_addr_list; *cp; ++cp) {
#ifdef DEBUG
printf("doing reverse lookup for %s\n", he->h_name);
#endif
result = __gethostbyaddr(*cp, he->h_length,
he->h_addrtype);
if (result == NULL) {
#ifdef DEBUG
printf("%s: warning: reverse lookup failed "
"for %s: %s\n", __func__, he->h_name,
strerror(errno));
#endif
continue;
}
rv = hostent_test_correctness(result, NULL);
if (rv != 0) {
__freehostent(result);
return (rv);
}
if (addr_test_data != NULL)
TEST_DATA_APPEND(hostent, addr_test_data,
result);
__freehostent(result);
}
}
return (0);
}
static int
hostent_test_getaddrinfo_eq(struct hostent *he, void *mdata __unused)
{
struct addrinfo *ai, hints;
int rv;
ai = NULL;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = af_type;
hints.ai_flags = AI_CANONNAME;
printf("using getaddrinfo() to resolve %s\n", he->h_name);
/* struct hostent *he was not resolved */
if (he->h_addr_list == NULL) {
/* We can be sure that he->h_name is not NULL */
rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
if (rv == 0) {
printf("not ok - shouldn't have been resolved\n");
rv = -1;
} else
rv = 0;
} else {
rv = getaddrinfo(he->h_name, NULL, &hints, &ai);
if (rv != 0) {
printf("not ok - should have been resolved\n");
rv = -1;
goto done;
}
rv = is_hostent_equal(he, ai);
if (rv != 0) {
printf("not ok - addrinfo and hostent are not equal\n");
rv = -1;
}
}
done:
if (ai != NULL)
freeaddrinfo(ai);
return (rv);
}
static int
hostent_test_getnameinfo_eq(struct hostent *he, void *mdata __unused)
{
char **cp;
char buffer[NI_MAXHOST];
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr *saddr;
struct hostent *result;
int i, rv;
if (he->h_addr_list == NULL)
return (0);
for (cp = he->h_addr_list; *cp; ++cp) {
#ifdef DEBUG
printf("doing reverse lookup for %s\n", he->h_name);
#endif
result = __gethostbyaddr(*cp, he->h_length,
he->h_addrtype);
if (result != NULL) {
rv = hostent_test_correctness(result, NULL);
if (rv != 0) {
__freehostent(result);
return (rv);
}
} else
printf("%s: warning: reverse lookup failed "
"for %s: %s\n", __func__, he->h_name,
strerror(errno));
switch (he->h_addrtype) {
case AF_INET:
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_len = sizeof(struct sockaddr_in);
sin.sin_family = AF_INET;
memcpy(&sin.sin_addr, *cp, he->h_length);
saddr = (struct sockaddr *)&sin;
break;
case AF_INET6:
memset(&sin6, 0, sizeof(struct sockaddr_in6));
sin6.sin6_len = sizeof(struct sockaddr_in6);
sin6.sin6_family = AF_INET6;
memcpy(&sin6.sin6_addr, *cp, he->h_length);
saddr = (struct sockaddr *)&sin6;
break;
default:
printf("warning: %d family is unsupported\n",
he->h_addrtype);
continue;
}
ATF_REQUIRE(saddr != NULL);
rv = getnameinfo(saddr, saddr->sa_len, buffer,
sizeof(buffer), NULL, 0, NI_NAMEREQD);
if (rv != 0 && result != NULL) {
printf("getnameinfo() didn't make the reverse "
"lookup, when it should have (%s)\n",
gai_strerror(rv));
return (rv);
}
if (rv == 0 && result == NULL) {
printf("getnameinfo() made the "
"reverse lookup, when it shouldn't have\n");
return (rv);
}
if (rv != 0 && result == NULL) {
#ifdef DEBUG
printf("both getnameinfo() and ***byaddr() failed as "
"expected\n");
#endif
continue;
}
#ifdef DEBUG
printf("comparing %s with %s\n", result->h_name,
buffer);
#endif
/*
* An address might reverse resolve to hostname alias or the
* official hostname, e.g. moon.vub.ac.be.
*/
bool found_a_match = false;
if (strcmp(result->h_name, buffer) == 0) {
found_a_match = true;
#ifdef DEBUG
printf("matched official hostname\n");
#endif
} else {
for (i = 0; result->h_aliases[i] != NULL; i++) {
printf("[%d] resolved: %s\n", i,
result->h_aliases[i]);
if (strcmp(result->h_aliases[i],
buffer) == 0) {
printf("matched hostname alias\n");
found_a_match = true;
break;
}
}
}
__freehostent(result);
if (found_a_match) {
#ifdef DEBUG
printf("getnameinfo() and ***byaddr() results are "
"equal\n");
#endif
} else {
printf("getnameinfo() and ***byaddr() results are not "
"equal for %s\n", he->h_name);
return (-1);
}
}
return (0);
}
static int
run_tests(const char *hostlist_file, const char *snapshot_file, int _af_type,
enum test_methods method, bool use_ipv6_mapping)
{
char *snapshot_file_copy;
struct hostent_test_data td, td_addr, td_snap;
res_state statp;
int rv = -2;
if (snapshot_file == NULL)
snapshot_file_copy = NULL;
else {
snapshot_file_copy = strdup(snapshot_file);
ATF_REQUIRE(snapshot_file_copy != NULL);
}
snapshot_file = snapshot_file_copy;
switch (_af_type) {
case AF_INET:
ATF_REQUIRE_FEATURE("inet");
ATF_REQUIRE(!use_ipv6_mapping);
break;
case AF_INET6:
ATF_REQUIRE_FEATURE("inet6");
break;
default:
atf_tc_fail("unhandled address family: %d", _af_type);
break;
}
if (!use_ipnode_functions) {
statp = __res_state();
if (statp == NULL || ((statp->options & RES_INIT) == 0 &&
res_ninit(statp) == -1)) {
printf("error: can't init res_state\n");
rv = -1;
goto fin2;
}
if (use_ipv6_mapping)
statp->options |= RES_USE_INET6;
else
statp->options &= ~RES_USE_INET6;
}
TEST_DATA_INIT(hostent, &td, clone_hostent, free_hostent);
TEST_DATA_INIT(hostent, &td_addr, clone_hostent, free_hostent);
TEST_DATA_INIT(hostent, &td_snap, clone_hostent, free_hostent);
if (access(hostlist_file, R_OK) != 0) {
printf("can't access the hostlist file %s\n", hostlist_file);
rv = -1;
goto fin;
}
#ifdef DEBUG
printf("building host lists from %s\n", hostlist_file);
#endif
rv = TEST_SNAPSHOT_FILE_READ(hostent, hostlist_file, &td,
hostent_read_hostlist_func);
if (rv != 0) {
printf("failed to read the host list file: %s\n",
hostlist_file);
goto fin;
}
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT) {
if (method != TEST_GETHOSTBYADDR)
method = TEST_BUILD_SNAPSHOT;
else
method = TEST_BUILD_ADDR_SNAPSHOT;
} else {
printf("can't access the snapshot file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
rv = TEST_SNAPSHOT_FILE_READ(hostent, snapshot_file,
&td_snap, hostent_read_snapshot_func);
if (rv != 0) {
printf("error reading snapshot file\n");
goto fin;
}
}
}
switch (method) {
case TEST_GETHOSTBYNAME2:
if (snapshot_file != NULL)
rv = DO_2PASS_TEST(hostent, &td, &td_snap,
compare_hostent, NULL);
break;
case TEST_GETHOSTBYADDR:
rv = DO_1PASS_TEST(hostent, &td,
hostent_test_gethostbyaddr, (void *)&td_addr);
if (rv != 0)
goto fin;
if (snapshot_file != NULL)
rv = DO_2PASS_TEST(hostent, &td_addr, &td_snap,
compare_hostent, NULL);
break;
case TEST_GETHOSTBYNAME2_GETADDRINFO:
rv = DO_1PASS_TEST(hostent, &td,
hostent_test_getaddrinfo_eq, NULL);
break;
case TEST_GETHOSTBYADDR_GETNAMEINFO:
rv = DO_1PASS_TEST(hostent, &td,
hostent_test_getnameinfo_eq, NULL);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL) {
rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file,
&td, sdump_hostent);
}
break;
case TEST_BUILD_ADDR_SNAPSHOT:
if (snapshot_file != NULL) {
rv = DO_1PASS_TEST(hostent, &td,
hostent_test_gethostbyaddr, (void *)&td_addr);
if (rv != 0)
goto fin;
rv = TEST_SNAPSHOT_FILE_WRITE(hostent, snapshot_file,
&td_addr, sdump_hostent);
}
break;
default:
rv = 0;
break;
}
fin:
TEST_DATA_DESTROY(hostent, &td_snap);
TEST_DATA_DESTROY(hostent, &td_addr);
TEST_DATA_DESTROY(hostent, &td);
fin2:
free(snapshot_file_copy);
return (rv);
}
#define HOSTLIST_FILE "mach"
#define _RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
do { \
char *_hostlist_file; \
ATF_REQUIRE(0 < asprintf(&_hostlist_file, "%s/%s", \
atf_tc_get_config_var(tc, "srcdir"), HOSTLIST_FILE)); \
ATF_REQUIRE(run_tests(_hostlist_file, snapshot_file, af_type, \
method, use_ipv6_mapping) == 0); \
free(_hostlist_file); \
} while (0)
#define RUN_HOST_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
do { \
use_ipnode_functions = false; \
_RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \
} while (0)
#define RUN_IPNODE_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping) \
do { \
use_ipnode_functions = true; \
_RUN_TESTS(tc, snapshot_file, af_type, method, use_ipv6_mapping); \
} while (0)
ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4);
ATF_TC_BODY(gethostbyaddr_ipv4, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv4_with_snapshot);
ATF_TC_BODY(gethostbyaddr_ipv4_with_snapshot, tc)
{
RUN_HOST_TESTS(tc, "snapshot_htaddr4", AF_INET, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6);
ATF_TC_BODY(gethostbyaddr_ipv6, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_AI_V4MAPPED);
ATF_TC_BODY(gethostbyaddr_ipv6_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot);
ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot, tc)
{
RUN_HOST_TESTS(tc, "snapshot_htaddr6", AF_INET6, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED);
ATF_TC_BODY(gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_HOST_TESTS(tc, "snapshot_htaddr6map", AF_INET6, TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv4);
ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv4, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_getaddrinfo_ipv6);
ATF_TC_BODY(gethostbyname2_getaddrinfo_ipv6, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv4);
ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv4, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyaddr_getnameinfo_ipv6);
ATF_TC_BODY(gethostbyaddr_getnameinfo_ipv6, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4);
ATF_TC_BODY(gethostbyname2_ipv4, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv4_with_snapshot);
ATF_TC_BODY(gethostbyname2_ipv4_with_snapshot, tc)
{
RUN_HOST_TESTS(tc, "snapshot_htname4", AF_INET, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6);
ATF_TC_BODY(gethostbyname2_ipv6, tc)
{
RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_AI_V4MAPPED);
ATF_TC_BODY(gethostbyname2_ipv6_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_HOST_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot);
ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot, tc)
{
RUN_HOST_TESTS(tc, "snapshot_htname6", AF_INET6, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED);
ATF_TC_BODY(gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_HOST_TESTS(tc, "snapshot_htname6map", AF_INET6, TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4);
ATF_TC_BODY(getipnodebyaddr_ipv4, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv4_with_snapshot);
ATF_TC_BODY(getipnodebyaddr_ipv4_with_snapshot, tc)
{
RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr4", AF_INET, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv4);
ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv4, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6);
ATF_TC_BODY(getipnodebyaddr_ipv6, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED);
ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG);
ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG, tc)
{
ipnode_flags = AI_V4MAPPED_CFG;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL);
ATF_TC_BODY(getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc)
{
ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot);
ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot, tc)
{
RUN_IPNODE_TESTS(tc, "snapshot_ipnodeaddr6", AF_INET6, TEST_GETHOSTBYADDR, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED);
ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_IPNODE_TESTS(tc,
"snapshot_ipnodeaddr6_AI_V4MAPPED", AF_INET6,
TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG);
ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc)
{
ipnode_flags = AI_V4MAPPED_CFG;
RUN_IPNODE_TESTS(tc,
"snapshot_ipnodeaddr6_AI_V4MAPPED_CFG", AF_INET6,
TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
ATF_TC_BODY(getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc)
{
ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
RUN_IPNODE_TESTS(tc,
"snapshot_ipnodeaddr6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6,
TEST_GETHOSTBYADDR, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyaddr_getnameinfo_ipv6);
ATF_TC_BODY(getipnodebyaddr_getnameinfo_ipv6, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYADDR_GETNAMEINFO, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4);
ATF_TC_BODY(getipnodebyname_ipv4, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot);
ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot, tc)
{
RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4", AF_INET, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_AI_ADDRCONFIG);
ATF_TC_BODY(getipnodebyname_ipv4_AI_ADDRCONFIG, tc)
{
ipnode_flags = AI_ADDRCONFIG;
RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG);
ATF_TC_BODY(getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG, tc)
{
ipnode_flags = AI_ADDRCONFIG;
RUN_IPNODE_TESTS(tc, "snapshot_ipnodename4_AI_ADDRCONFIG", AF_INET,
TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv4);
ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv4, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6);
ATF_TC_BODY(getipnodebyname_ipv6, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot);
ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot, tc)
{
RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6", AF_INET6, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_ADDRCONFIG);
ATF_TC_BODY(getipnodebyname_ipv6_AI_ADDRCONFIG, tc)
{
ipnode_flags = AI_ADDRCONFIG;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED);
ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG);
ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG, tc)
{
ipnode_flags = AI_V4MAPPED_CFG;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc)
{
ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL);
ATF_TC_BODY(getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL, tc)
{
ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED);
ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED, tc)
{
ipnode_flags = AI_V4MAPPED;
RUN_IPNODE_TESTS(tc,
"snapshot_ipnodename6_AI_V4MAPPED", AF_INET6,
TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG);
ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG, tc)
{
ipnode_flags = AI_V4MAPPED_CFG;
RUN_IPNODE_TESTS(tc,
"snapshot_ipnodename6_AI_V4MAPPED_CFG", AF_INET6,
TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG, tc)
{
ipnode_flags = AI_V4MAPPED_CFG | AI_ADDRCONFIG;
RUN_IPNODE_TESTS(tc,
"snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ADDRCONFIG", AF_INET6,
TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL, tc)
{
ipnode_flags = AI_V4MAPPED_CFG | AI_ALL;
RUN_IPNODE_TESTS(tc,
"snapshot_ipnodename6_AI_V4MAPPED_CFG_AI_ALL", AF_INET6,
TEST_GETHOSTBYNAME2, true);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG);
ATF_TC_BODY(getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG, tc)
{
ipnode_flags = AI_ADDRCONFIG;
RUN_IPNODE_TESTS(tc, "snapshot_ipnodename6_AI_ADDRCONFIG", AF_INET6,
TEST_GETHOSTBYNAME2, false);
}
ATF_TC_WITHOUT_HEAD(getipnodebyname_getaddrinfo_ipv6);
ATF_TC_BODY(getipnodebyname_getaddrinfo_ipv6, tc)
{
RUN_IPNODE_TESTS(tc, NULL, AF_INET6, TEST_GETHOSTBYNAME2_GETADDRINFO, false);
}
ATF_TP_ADD_TCS(tp)
{
/* gethostbyaddr */
ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4);
ATF_TP_ADD_TC(tp, gethostbyaddr_ipv4_with_snapshot);
ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6);
ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_AI_V4MAPPED); /* XXX */
ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot);
ATF_TP_ADD_TC(tp, gethostbyaddr_ipv6_with_snapshot_AI_V4MAPPED);
ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv4);
ATF_TP_ADD_TC(tp, gethostbyaddr_getnameinfo_ipv6);
/* gethostbyname2 */
ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv4);
ATF_TP_ADD_TC(tp, gethostbyname2_getaddrinfo_ipv6);
ATF_TP_ADD_TC(tp, gethostbyname2_ipv4);
ATF_TP_ADD_TC(tp, gethostbyname2_ipv4_with_snapshot);
ATF_TP_ADD_TC(tp, gethostbyname2_ipv6);
ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_AI_V4MAPPED);
ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot);
ATF_TP_ADD_TC(tp, gethostbyname2_ipv6_with_snapshot_AI_V4MAPPED);
/* getipnodebyaddr */
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv4_with_snapshot);
ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv4);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_AI_V4MAPPED_CFG_AI_ALL);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG);
ATF_TP_ADD_TC(tp, getipnodebyaddr_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
ATF_TP_ADD_TC(tp, getipnodebyaddr_getnameinfo_ipv6);
/* getipnodebyname */
ATF_TP_ADD_TC(tp, getipnodebyname_ipv4);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_AI_ADDRCONFIG);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv4_with_snapshot_AI_ADDRCONFIG);
ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv4);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_ADDRCONFIG);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_AI_V4MAPPED_CFG_AI_ALL);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ADDRCONFIG);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_V4MAPPED_CFG_AI_ALL);
ATF_TP_ADD_TC(tp, getipnodebyname_ipv6_with_snapshot_AI_ADDRCONFIG);
ATF_TP_ADD_TC(tp, getipnodebyname_getaddrinfo_ipv6);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/getproto_test.c b/lib/libc/tests/nss/getproto_test.c
index 18a8f8b667af..9b8250e47032 100644
--- a/lib/libc/tests/nss/getproto_test.c
+++ b/lib/libc/tests/nss/getproto_test.c
@@ -1,554 +1,553 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <arpa/inet.h>
#include <assert.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include <atf-c.h>
#include "testutil.h"
enum test_methods {
TEST_GETPROTOENT,
TEST_GETPROTOBYNAME,
TEST_GETPROTOBYNUMBER,
TEST_GETPROTOENT_2PASS,
TEST_BUILD_SNAPSHOT
};
DECLARE_TEST_DATA(protoent)
DECLARE_TEST_FILE_SNAPSHOT(protoent)
DECLARE_1PASS_TEST(protoent)
DECLARE_2PASS_TEST(protoent)
static void clone_protoent(struct protoent *, struct protoent const *);
static int compare_protoent(struct protoent *, struct protoent *, void *);
static void dump_protoent(struct protoent *);
static void free_protoent(struct protoent *);
static void sdump_protoent(struct protoent *, char *, size_t);
static int protoent_read_snapshot_func(struct protoent *, char *);
static int protoent_check_ambiguity(struct protoent_test_data *,
struct protoent *);
static int protoent_fill_test_data(struct protoent_test_data *);
static int protoent_test_correctness(struct protoent *, void *);
static int protoent_test_getprotobyname(struct protoent *, void *);
static int protoent_test_getprotobynumber(struct protoent *, void *);
static int protoent_test_getprotoent(struct protoent *, void *);
IMPLEMENT_TEST_DATA(protoent)
IMPLEMENT_TEST_FILE_SNAPSHOT(protoent)
IMPLEMENT_1PASS_TEST(protoent)
IMPLEMENT_2PASS_TEST(protoent)
static void
clone_protoent(struct protoent *dest, struct protoent const *src)
{
assert(dest != NULL);
assert(src != NULL);
char **cp;
int aliases_num;
memset(dest, 0, sizeof(struct protoent));
if (src->p_name != NULL) {
dest->p_name = strdup(src->p_name);
assert(dest->p_name != NULL);
}
dest->p_proto = src->p_proto;
if (src->p_aliases != NULL) {
aliases_num = 0;
for (cp = src->p_aliases; *cp; ++cp)
++aliases_num;
dest->p_aliases = calloc(aliases_num + 1, sizeof(char *));
assert(dest->p_aliases != NULL);
for (cp = src->p_aliases; *cp; ++cp) {
dest->p_aliases[cp - src->p_aliases] = strdup(*cp);
assert(dest->p_aliases[cp - src->p_aliases] != NULL);
}
}
}
static void
free_protoent(struct protoent *pe)
{
char **cp;
assert(pe != NULL);
free(pe->p_name);
for (cp = pe->p_aliases; *cp; ++cp)
free(*cp);
free(pe->p_aliases);
}
static int
compare_protoent(struct protoent *pe1, struct protoent *pe2, void *mdata)
{
char **c1, **c2;
if (pe1 == pe2)
return 0;
if ((pe1 == NULL) || (pe2 == NULL))
goto errfin;
if ((strcmp(pe1->p_name, pe2->p_name) != 0) ||
(pe1->p_proto != pe2->p_proto))
goto errfin;
c1 = pe1->p_aliases;
c2 = pe2->p_aliases;
if ((pe1->p_aliases == NULL) || (pe2->p_aliases == NULL))
goto errfin;
for (;*c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if ((*c1 != NULL) || (*c2 != NULL))
goto errfin;
return 0;
errfin:
if (mdata == NULL) {
printf("following structures are not equal:\n");
dump_protoent(pe1);
dump_protoent(pe2);
}
return (-1);
}
static void
sdump_protoent(struct protoent *pe, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s %d",
pe->p_name, pe->p_proto);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (pe->p_aliases != NULL) {
if (*(pe->p_aliases) != NULL) {
for (cp = pe->p_aliases; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s", *cp);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, " noaliases");
} else
snprintf(buffer, buflen, " (null)");
}
static int
protoent_read_snapshot_func(struct protoent *pe, char *line)
{
StringList *sl;
char *s, *ps, *ts;
int i;
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
memset(pe, 0, sizeof(struct protoent));
while ( (s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
pe->p_name = strdup(s);
assert(pe->p_name != NULL);
break;
case 1:
pe->p_proto = (int)strtol(s, &ts, 10);
if (*ts != '\0') {
free(pe->p_name);
return (-1);
}
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
assert(sl != NULL);
if (strcmp(s, "noaliases") != 0) {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
assert(ts != NULL);
sl_add(sl, ts);
}
break;
}
++i;
}
if (i < 3) {
free(pe->p_name);
memset(pe, 0, sizeof(struct protoent));
return (-1);
}
sl_add(sl, NULL);
pe->p_aliases = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_protoent(struct protoent *result)
{
if (result != NULL) {
char buffer[1024];
sdump_protoent(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
protoent_fill_test_data(struct protoent_test_data *td)
{
struct protoent *pe;
setprotoent(1);
while ((pe = getprotoent()) != NULL) {
if (protoent_test_correctness(pe, NULL) == 0)
TEST_DATA_APPEND(protoent, td, pe);
else
return (-1);
}
endprotoent();
return (0);
}
static int
protoent_test_correctness(struct protoent *pe, void *mdata __unused)
{
printf("testing correctness with the following data:\n");
dump_protoent(pe);
if (pe == NULL)
goto errfin;
if (pe->p_name == NULL)
goto errfin;
if (pe->p_proto < 0)
goto errfin;
if (pe->p_aliases == NULL)
goto errfin;
printf("correct\n");
return (0);
errfin:
printf("incorrect\n");
return (-1);
}
/* protoent_check_ambiguity() is needed when one port+proto is associated with
* more than one piece (these cases are usually marked as PROBLEM in
* /etc/peices. This functions is needed also when one piece+proto is
* associated with several ports. We have to check all the protoent structures
* to make sure that pe really exists and correct */
static int
protoent_check_ambiguity(struct protoent_test_data *td, struct protoent *pe)
{
return (TEST_DATA_FIND(protoent, td, pe, compare_protoent,
NULL) != NULL ? 0 : -1);
}
static int
protoent_test_getprotobyname(struct protoent *pe_model, void *mdata)
{
char **alias;
struct protoent *pe;
printf("testing getprotobyname() with the following data:\n");
dump_protoent(pe_model);
pe = getprotobyname(pe_model->p_name);
if (protoent_test_correctness(pe, NULL) != 0)
goto errfin;
if ((compare_protoent(pe, pe_model, NULL) != 0) &&
(protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
!=0))
goto errfin;
for (alias = pe_model->p_aliases; *alias; ++alias) {
pe = getprotobyname(*alias);
if (protoent_test_correctness(pe, NULL) != 0)
goto errfin;
if ((compare_protoent(pe, pe_model, NULL) != 0) &&
(protoent_check_ambiguity(
(struct protoent_test_data *)mdata, pe) != 0))
goto errfin;
}
printf("ok\n");
return (0);
errfin:
printf("not ok\n");
return (-1);
}
static int
protoent_test_getprotobynumber(struct protoent *pe_model, void *mdata)
{
struct protoent *pe;
printf("testing getprotobyport() with the following data...\n");
dump_protoent(pe_model);
pe = getprotobynumber(pe_model->p_proto);
if ((protoent_test_correctness(pe, NULL) != 0) ||
((compare_protoent(pe, pe_model, NULL) != 0) &&
(protoent_check_ambiguity((struct protoent_test_data *)mdata, pe)
!= 0))) {
printf("not ok\n");
return (-1);
} else {
printf("ok\n");
return (0);
}
}
static int
protoent_test_getprotoent(struct protoent *pe, void *mdata __unused)
{
/* Only correctness can be checked when doing 1-pass test for
* getprotoent(). */
return (protoent_test_correctness(pe, NULL));
}
static int
run_tests(const char *snapshot_file, enum test_methods method)
{
struct protoent_test_data td, td_snap, td_2pass;
int rv;
TEST_DATA_INIT(protoent, &td, clone_protoent, free_protoent);
TEST_DATA_INIT(protoent, &td_snap, clone_protoent, free_protoent);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(protoent, snapshot_file,
&td_snap, protoent_read_snapshot_func);
}
}
rv = protoent_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETPROTOBYNAME:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(protoent, &td,
protoent_test_getprotobyname, (void *)&td);
else
rv = DO_1PASS_TEST(protoent, &td_snap,
protoent_test_getprotobyname, (void *)&td_snap);
break;
case TEST_GETPROTOBYNUMBER:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(protoent, &td,
protoent_test_getprotobynumber, (void *)&td);
else
rv = DO_1PASS_TEST(protoent, &td_snap,
protoent_test_getprotobynumber, (void *)&td_snap);
break;
case TEST_GETPROTOENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(protoent, &td,
protoent_test_getprotoent, (void *)&td);
else
rv = DO_2PASS_TEST(protoent, &td, &td_snap,
compare_protoent, NULL);
break;
case TEST_GETPROTOENT_2PASS:
TEST_DATA_INIT(protoent, &td_2pass, clone_protoent,
free_protoent);
rv = protoent_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(protoent, &td, &td_2pass,
compare_protoent, NULL);
TEST_DATA_DESTROY(protoent, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(protoent, snapshot_file,
&td, sdump_protoent);
break;
default:
rv = 0;
break;
}
fin:
TEST_DATA_DESTROY(protoent, &td_snap);
TEST_DATA_DESTROY(protoent, &td);
return (rv);
}
#define SNAPSHOT_FILE "snapshot_proto"
ATF_TC_WITHOUT_HEAD(build_snapshot);
ATF_TC_BODY(build_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
}
ATF_TC_WITHOUT_HEAD(getprotoent);
ATF_TC_BODY(getprotoent, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getprotoent_with_snapshot);
ATF_TC_BODY(getprotoent_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getprotoent_with_two_pass);
ATF_TC_BODY(getprotoent_with_two_pass, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOENT_2PASS) == 0);
}
ATF_TC_WITHOUT_HEAD(getprotobyname);
ATF_TC_BODY(getprotobyname, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNAME) == 0);
}
ATF_TC_WITHOUT_HEAD(getprotobyname_with_snapshot);
ATF_TC_BODY(getprotobyname_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNAME) == 0);
}
ATF_TC_WITHOUT_HEAD(getprotobynumber);
ATF_TC_BODY(getprotobynumber, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPROTOBYNUMBER) == 0);
}
ATF_TC_WITHOUT_HEAD(getprotobynumber_with_snapshot);
ATF_TC_BODY(getprotobynumber_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPROTOBYNUMBER) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, build_snapshot);
ATF_TP_ADD_TC(tp, getprotoent);
ATF_TP_ADD_TC(tp, getprotoent_with_snapshot);
ATF_TP_ADD_TC(tp, getprotoent_with_two_pass);
ATF_TP_ADD_TC(tp, getprotobyname);
ATF_TP_ADD_TC(tp, getprotobyname_with_snapshot);
ATF_TP_ADD_TC(tp, getprotobynumber);
ATF_TP_ADD_TC(tp, getprotobynumber_with_snapshot);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/getpw_test.c b/lib/libc/tests/nss/getpw_test.c
index 7525cd28b962..3a44497cf848 100644
--- a/lib/libc/tests/nss/getpw_test.c
+++ b/lib/libc/tests/nss/getpw_test.c
@@ -1,552 +1,551 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
#include "testutil.h"
enum test_methods {
TEST_GETPWENT,
TEST_GETPWENT_INTERLEAVED_GETPWNAM,
TEST_GETPWENT_INTERLEAVED_GETPWUID,
TEST_GETPWNAM,
TEST_GETPWUID,
TEST_GETPWENT_2PASS,
TEST_BUILD_SNAPSHOT
};
DECLARE_TEST_DATA(passwd)
DECLARE_TEST_FILE_SNAPSHOT(passwd)
DECLARE_1PASS_TEST(passwd)
DECLARE_2PASS_TEST(passwd)
static void clone_passwd(struct passwd *, struct passwd const *);
static int compare_passwd(struct passwd *, struct passwd *, void *);
static void free_passwd(struct passwd *);
static void sdump_passwd(struct passwd *, char *, size_t);
#ifdef DEBUG
static void dump_passwd(struct passwd *);
#endif
static int passwd_read_snapshot_func(struct passwd *, char *);
static int passwd_check_ambiguity(struct passwd_test_data *, struct passwd *);
static int passwd_fill_test_data(struct passwd_test_data *,
int (*cb)(struct passwd *, void *));
static int passwd_test_correctness(struct passwd *, void *);
static int passwd_test_getpwnam(struct passwd *, void *);
static int passwd_test_getpwuid(struct passwd *, void *);
static int passwd_test_getpwent(struct passwd *, void *);
IMPLEMENT_TEST_DATA(passwd)
IMPLEMENT_TEST_FILE_SNAPSHOT(passwd)
IMPLEMENT_1PASS_TEST(passwd)
IMPLEMENT_2PASS_TEST(passwd)
static void
clone_passwd(struct passwd *dest, struct passwd const *src)
{
ATF_REQUIRE(dest != NULL);
ATF_REQUIRE(src != NULL);
memcpy(dest, src, sizeof(struct passwd));
if (src->pw_name != NULL)
dest->pw_name = strdup(src->pw_name);
if (src->pw_passwd != NULL)
dest->pw_passwd = strdup(src->pw_passwd);
if (src->pw_class != NULL)
dest->pw_class = strdup(src->pw_class);
if (src->pw_gecos != NULL)
dest->pw_gecos = strdup(src->pw_gecos);
if (src->pw_dir != NULL)
dest->pw_dir = strdup(src->pw_dir);
if (src->pw_shell != NULL)
dest->pw_shell = strdup(dest->pw_shell);
}
static int
compare_passwd(struct passwd *pwd1, struct passwd *pwd2, void *mdata __unused)
{
ATF_REQUIRE(pwd1 != NULL);
ATF_REQUIRE(pwd2 != NULL);
if (pwd1 == pwd2)
return (0);
if (pwd1->pw_uid != pwd2->pw_uid ||
pwd1->pw_gid != pwd2->pw_gid ||
pwd1->pw_change != pwd2->pw_change ||
pwd1->pw_expire != pwd2->pw_expire ||
pwd1->pw_fields != pwd2->pw_fields ||
strcmp(pwd1->pw_name, pwd2->pw_name) != 0 ||
strcmp(pwd1->pw_passwd, pwd2->pw_passwd) != 0 ||
strcmp(pwd1->pw_class, pwd2->pw_class) != 0 ||
strcmp(pwd1->pw_gecos, pwd2->pw_gecos) != 0 ||
strcmp(pwd1->pw_dir, pwd2->pw_dir) != 0 ||
strcmp(pwd1->pw_shell, pwd2->pw_shell) != 0)
return (-1);
else
return (0);
}
static void
free_passwd(struct passwd *pwd)
{
free(pwd->pw_name);
free(pwd->pw_passwd);
free(pwd->pw_class);
free(pwd->pw_gecos);
free(pwd->pw_dir);
free(pwd->pw_shell);
}
static void
sdump_passwd(struct passwd *pwd, char *buffer, size_t buflen)
{
snprintf(buffer, buflen, "%s:%s:%d:%d:%jd:%s:%s:%s:%s:%jd:%d",
pwd->pw_name, pwd->pw_passwd, pwd->pw_uid, pwd->pw_gid,
(uintmax_t)pwd->pw_change, pwd->pw_class, pwd->pw_gecos,
pwd->pw_dir, pwd->pw_shell, (uintmax_t)pwd->pw_expire,
pwd->pw_fields);
}
#ifdef DEBUG
static void
dump_passwd(struct passwd *pwd)
{
if (pwd != NULL) {
char buffer[2048];
sdump_passwd(pwd, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
#endif
static int
passwd_read_snapshot_func(struct passwd *pwd, char *line)
{
char *s, *ps, *ts;
int i;
#ifdef DEBUG
printf("1 line read from snapshot:\n%s\n", line);
#endif
i = 0;
ps = line;
memset(pwd, 0, sizeof(struct passwd));
while ((s = strsep(&ps, ":")) != NULL) {
switch (i) {
case 0:
pwd->pw_name = strdup(s);
ATF_REQUIRE(pwd->pw_name != NULL);
break;
case 1:
pwd->pw_passwd = strdup(s);
ATF_REQUIRE(pwd->pw_passwd != NULL);
break;
case 2:
pwd->pw_uid = (uid_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 3:
pwd->pw_gid = (gid_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 4:
pwd->pw_change = (time_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 5:
pwd->pw_class = strdup(s);
ATF_REQUIRE(pwd->pw_class != NULL);
break;
case 6:
pwd->pw_gecos = strdup(s);
ATF_REQUIRE(pwd->pw_gecos != NULL);
break;
case 7:
pwd->pw_dir = strdup(s);
ATF_REQUIRE(pwd->pw_dir != NULL);
break;
case 8:
pwd->pw_shell = strdup(s);
ATF_REQUIRE(pwd->pw_shell != NULL);
break;
case 9:
pwd->pw_expire = (time_t)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
case 10:
pwd->pw_fields = (int)strtol(s, &ts, 10);
if (*ts != '\0')
goto fin;
break;
default:
break;
}
++i;
}
fin:
if (i != 11) {
free_passwd(pwd);
memset(pwd, 0, sizeof(struct passwd));
return (-1);
}
return (0);
}
static int
passwd_fill_test_data(struct passwd_test_data *td,
int (*cb)(struct passwd *, void *))
{
struct passwd *pwd;
setpassent(1);
while ((pwd = getpwent()) != NULL) {
if (passwd_test_correctness(pwd, NULL) == 0) {
TEST_DATA_APPEND(passwd, td, pwd);
if (cb != NULL && cb(pwd, td) != 0)
return (-1);
} else {
return (-1);
}
}
endpwent();
return (0);
}
static int
passwd_test_correctness(struct passwd *pwd, void *mdata __unused)
{
#ifdef DEBUG
printf("testing correctness with the following data:\n");
dump_passwd(pwd);
#endif
if (pwd == NULL)
return (-1);
if (pwd->pw_name == NULL)
goto errfin;
if (pwd->pw_passwd == NULL)
goto errfin;
if (pwd->pw_class == NULL)
goto errfin;
if (pwd->pw_gecos == NULL)
goto errfin;
if (pwd->pw_dir == NULL)
goto errfin;
if (pwd->pw_shell == NULL)
goto errfin;
#ifdef DEBUG
printf("correct\n");
#endif
return (0);
errfin:
#ifdef DEBUG
printf("incorrect\n");
#endif
return (-1);
}
/* passwd_check_ambiguity() is needed here because when doing the getpwent()
* calls sequence, records from different nsswitch sources can be different,
* though having the same pw_name/pw_uid */
static int
passwd_check_ambiguity(struct passwd_test_data *td, struct passwd *pwd)
{
return (TEST_DATA_FIND(passwd, td, pwd, compare_passwd, NULL) !=
NULL ? 0 : -1);
}
static int
passwd_test_getpwnam(struct passwd *pwd_model, void *mdata)
{
struct passwd *pwd;
#ifdef DEBUG
printf("testing getpwnam() with the following data:\n");
dump_passwd(pwd_model);
#endif
pwd = getpwnam(pwd_model->pw_name);
if (passwd_test_correctness(pwd, NULL) != 0)
goto errfin;
if (compare_passwd(pwd, pwd_model, NULL) != 0 &&
passwd_check_ambiguity((struct passwd_test_data *)mdata, pwd) != 0)
goto errfin;
#ifdef DEBUG
printf("ok\n");
#endif
return (0);
errfin:
#ifdef DEBUG
printf("not ok\n");
#endif
return (-1);
}
static int
passwd_test_getpwuid(struct passwd *pwd_model, void *mdata)
{
struct passwd *pwd;
#ifdef DEBUG
printf("testing getpwuid() with the following data...\n");
dump_passwd(pwd_model);
#endif
pwd = getpwuid(pwd_model->pw_uid);
if (passwd_test_correctness(pwd, NULL) != 0 ||
(compare_passwd(pwd, pwd_model, NULL) != 0 &&
passwd_check_ambiguity((struct passwd_test_data *)mdata,
pwd) != 0)) {
#ifdef DEBUG
printf("not ok\n");
#endif
return (-1);
} else {
#ifdef DEBUG
printf("ok\n");
#endif
return (0);
}
}
static int
passwd_test_getpwent(struct passwd *pwd, void *mdata __unused)
{
/*
* Only correctness can be checked when doing 1-pass test for
* getpwent().
*/
return (passwd_test_correctness(pwd, NULL));
}
static int
run_tests(const char *snapshot_file, enum test_methods method)
{
struct passwd_test_data td, td_snap, td_2pass, td_interleaved;
int rv;
TEST_DATA_INIT(passwd, &td, clone_passwd, free_passwd);
TEST_DATA_INIT(passwd, &td_snap, clone_passwd, free_passwd);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(passwd, snapshot_file,
&td_snap, passwd_read_snapshot_func);
}
}
rv = passwd_fill_test_data(&td, NULL);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETPWNAM:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(passwd, &td,
passwd_test_getpwnam, (void *)&td);
else
rv = DO_1PASS_TEST(passwd, &td_snap,
passwd_test_getpwnam, (void *)&td_snap);
break;
case TEST_GETPWUID:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(passwd, &td,
passwd_test_getpwuid, (void *)&td);
else
rv = DO_1PASS_TEST(passwd, &td_snap,
passwd_test_getpwuid, (void *)&td_snap);
break;
case TEST_GETPWENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(passwd, &td, passwd_test_getpwent,
(void *)&td);
else
rv = DO_2PASS_TEST(passwd, &td, &td_snap,
compare_passwd, NULL);
break;
case TEST_GETPWENT_2PASS:
TEST_DATA_INIT(passwd, &td_2pass, clone_passwd, free_passwd);
rv = passwd_fill_test_data(&td_2pass, NULL);
if (rv != -1)
rv = DO_2PASS_TEST(passwd, &td, &td_2pass,
compare_passwd, NULL);
TEST_DATA_DESTROY(passwd, &td_2pass);
break;
case TEST_GETPWENT_INTERLEAVED_GETPWNAM:
TEST_DATA_INIT(passwd, &td_interleaved, clone_passwd, free_passwd);
rv = passwd_fill_test_data(&td_interleaved, passwd_test_getpwnam);
if (rv != -1)
rv = DO_2PASS_TEST(passwd, &td, &td_interleaved,
compare_passwd, NULL);
TEST_DATA_DESTROY(passwd, &td_interleaved);
break;
case TEST_GETPWENT_INTERLEAVED_GETPWUID:
TEST_DATA_INIT(passwd, &td_interleaved, clone_passwd, free_passwd);
rv = passwd_fill_test_data(&td_interleaved, passwd_test_getpwuid);
if (rv != -1)
rv = DO_2PASS_TEST(passwd, &td, &td_interleaved,
compare_passwd, NULL);
TEST_DATA_DESTROY(passwd, &td_interleaved);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(passwd, snapshot_file,
&td, sdump_passwd);
break;
default:
rv = 0;
break;
}
fin:
TEST_DATA_DESTROY(passwd, &td_snap);
TEST_DATA_DESTROY(passwd, &td);
return (rv);
}
#define SNAPSHOT_FILE "snapshot_pwd"
ATF_TC_WITHOUT_HEAD(getpwent);
ATF_TC_BODY(getpwent, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwent_with_snapshot);
ATF_TC_BODY(getpwent_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwent_with_two_pass);
ATF_TC_BODY(getpwent_with_two_pass, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT_2PASS) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwnam);
ATF_TC_BODY(getpwnam, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPWNAM) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwnam_with_snapshot);
ATF_TC_BODY(getpwnam_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWNAM) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwuid);
ATF_TC_BODY(getpwuid, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPWUID) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwuid_with_snapshot);
ATF_TC_BODY(getpwuid_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETPWUID) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwent_interleaved_getpwnam);
ATF_TC_BODY(getpwent_interleaved_getpwnam, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT_INTERLEAVED_GETPWNAM) == 0);
}
ATF_TC_WITHOUT_HEAD(getpwent_interleaved_getpwuid);
ATF_TC_BODY(getpwent_interleaved_getpwuid, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETPWENT_INTERLEAVED_GETPWUID) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getpwent);
ATF_TP_ADD_TC(tp, getpwent_with_snapshot);
ATF_TP_ADD_TC(tp, getpwent_with_two_pass);
ATF_TP_ADD_TC(tp, getpwnam);
ATF_TP_ADD_TC(tp, getpwnam_with_snapshot);
ATF_TP_ADD_TC(tp, getpwuid);
ATF_TP_ADD_TC(tp, getpwuid_with_snapshot);
ATF_TP_ADD_TC(tp, getpwent_interleaved_getpwnam);
ATF_TP_ADD_TC(tp, getpwent_interleaved_getpwuid);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/getrpc_test.c b/lib/libc/tests/nss/getrpc_test.c
index 5b7098962cf3..6cca3cab9e86 100644
--- a/lib/libc/tests/nss/getrpc_test.c
+++ b/lib/libc/tests/nss/getrpc_test.c
@@ -1,556 +1,555 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <arpa/inet.h>
#include <rpc/rpc.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include <atf-c.h>
#include "testutil.h"
enum test_methods {
TEST_GETRPCENT,
TEST_GETRPCBYNAME,
TEST_GETRPCBYNUMBER,
TEST_GETRPCENT_2PASS,
TEST_BUILD_SNAPSHOT
};
DECLARE_TEST_DATA(rpcent)
DECLARE_TEST_FILE_SNAPSHOT(rpcent)
DECLARE_1PASS_TEST(rpcent)
DECLARE_2PASS_TEST(rpcent)
static void clone_rpcent(struct rpcent *, struct rpcent const *);
static int compare_rpcent(struct rpcent *, struct rpcent *, void *);
static void dump_rpcent(struct rpcent *);
static void free_rpcent(struct rpcent *);
static void sdump_rpcent(struct rpcent *, char *, size_t);
static int rpcent_read_snapshot_func(struct rpcent *, char *);
static int rpcent_check_ambiguity(struct rpcent_test_data *,
struct rpcent *);
static int rpcent_fill_test_data(struct rpcent_test_data *);
static int rpcent_test_correctness(struct rpcent *, void *);
static int rpcent_test_getrpcbyname(struct rpcent *, void *);
static int rpcent_test_getrpcbynumber(struct rpcent *, void *);
static int rpcent_test_getrpcent(struct rpcent *, void *);
IMPLEMENT_TEST_DATA(rpcent)
IMPLEMENT_TEST_FILE_SNAPSHOT(rpcent)
IMPLEMENT_1PASS_TEST(rpcent)
IMPLEMENT_2PASS_TEST(rpcent)
static void
clone_rpcent(struct rpcent *dest, struct rpcent const *src)
{
ATF_REQUIRE(dest != NULL);
ATF_REQUIRE(src != NULL);
char **cp;
int aliases_num;
memset(dest, 0, sizeof(struct rpcent));
if (src->r_name != NULL) {
dest->r_name = strdup(src->r_name);
ATF_REQUIRE(dest->r_name != NULL);
}
dest->r_number = src->r_number;
if (src->r_aliases != NULL) {
aliases_num = 0;
for (cp = src->r_aliases; *cp; ++cp)
++aliases_num;
dest->r_aliases = calloc(aliases_num + 1, sizeof(char *));
ATF_REQUIRE(dest->r_aliases != NULL);
for (cp = src->r_aliases; *cp; ++cp) {
dest->r_aliases[cp - src->r_aliases] = strdup(*cp);
ATF_REQUIRE(dest->r_aliases[cp - src->r_aliases] != NULL);
}
}
}
static void
free_rpcent(struct rpcent *rpc)
{
char **cp;
ATF_REQUIRE(rpc != NULL);
free(rpc->r_name);
for (cp = rpc->r_aliases; *cp; ++cp)
free(*cp);
free(rpc->r_aliases);
}
static int
compare_rpcent(struct rpcent *rpc1, struct rpcent *rpc2, void *mdata)
{
char **c1, **c2;
if (rpc1 == rpc2)
return 0;
if ((rpc1 == NULL) || (rpc2 == NULL))
goto errfin;
if ((strcmp(rpc1->r_name, rpc2->r_name) != 0) ||
(rpc1->r_number != rpc2->r_number))
goto errfin;
c1 = rpc1->r_aliases;
c2 = rpc2->r_aliases;
if ((rpc1->r_aliases == NULL) || (rpc2->r_aliases == NULL))
goto errfin;
for (;*c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if ((*c1 != NULL) || (*c2 != NULL))
goto errfin;
return 0;
errfin:
if (mdata == NULL) {
printf("following structures are not equal:\n");
dump_rpcent(rpc1);
dump_rpcent(rpc2);
}
return (-1);
}
static void
sdump_rpcent(struct rpcent *rpc, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s %d",
rpc->r_name, rpc->r_number);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (rpc->r_aliases != NULL) {
if (*(rpc->r_aliases) != NULL) {
for (cp = rpc->r_aliases; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s", *cp);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, " noaliases");
} else
snprintf(buffer, buflen, " (null)");
}
static int
rpcent_read_snapshot_func(struct rpcent *rpc, char *line)
{
StringList *sl;
char *s, *ps, *ts;
int i;
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
memset(rpc, 0, sizeof(struct rpcent));
while ((s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
rpc->r_name = strdup(s);
ATF_REQUIRE(rpc->r_name != NULL);
break;
case 1:
rpc->r_number = (int)strtol(s, &ts, 10);
if (*ts != '\0') {
free(rpc->r_name);
return (-1);
}
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
ATF_REQUIRE(sl != NULL);
if (strcmp(s, "noaliases") != 0) {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl, ts);
}
break;
}
i++;
}
if (i < 3) {
free(rpc->r_name);
memset(rpc, 0, sizeof(struct rpcent));
return (-1);
}
sl_add(sl, NULL);
rpc->r_aliases = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_rpcent(struct rpcent *result)
{
if (result != NULL) {
char buffer[1024];
sdump_rpcent(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
rpcent_fill_test_data(struct rpcent_test_data *td)
{
struct rpcent *rpc;
setrpcent(1);
while ((rpc = getrpcent()) != NULL) {
if (rpcent_test_correctness(rpc, NULL) == 0)
TEST_DATA_APPEND(rpcent, td, rpc);
else
return (-1);
}
endrpcent();
return (0);
}
static int
rpcent_test_correctness(struct rpcent *rpc, void *mdata __unused)
{
printf("testing correctness with the following data:\n");
dump_rpcent(rpc);
if (rpc == NULL)
goto errfin;
if (rpc->r_name == NULL)
goto errfin;
if (rpc->r_number < 0)
goto errfin;
if (rpc->r_aliases == NULL)
goto errfin;
printf("correct\n");
return (0);
errfin:
printf("incorrect\n");
return (-1);
}
/* rpcent_check_ambiguity() is needed when one port+rpc is associated with
* more than one piece (these cases are usually marked as PROBLEM in
* /etc/peices. This functions is needed also when one piece+rpc is
* associated with several ports. We have to check all the rpcent structures
* to make sure that rpc really exists and correct */
static int
rpcent_check_ambiguity(struct rpcent_test_data *td, struct rpcent *rpc)
{
return (TEST_DATA_FIND(rpcent, td, rpc, compare_rpcent,
NULL) != NULL ? 0 : -1);
}
static int
rpcent_test_getrpcbyname(struct rpcent *rpc_model, void *mdata)
{
char **alias;
struct rpcent *rpc;
printf("testing getrpcbyname() with the following data:\n");
dump_rpcent(rpc_model);
rpc = getrpcbyname(rpc_model->r_name);
if (rpcent_test_correctness(rpc, NULL) != 0)
goto errfin;
if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
(rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
!=0))
goto errfin;
for (alias = rpc_model->r_aliases; *alias; ++alias) {
rpc = getrpcbyname(*alias);
if (rpcent_test_correctness(rpc, NULL) != 0)
goto errfin;
if ((compare_rpcent(rpc, rpc_model, NULL) != 0) &&
(rpcent_check_ambiguity(
(struct rpcent_test_data *)mdata, rpc) != 0))
goto errfin;
}
printf("ok\n");
return (0);
errfin:
printf("not ok\n");
return (-1);
}
static int
rpcent_test_getrpcbynumber(struct rpcent *rpc_model, void *mdata)
{
struct rpcent *rpc;
printf("testing getrpcbyport() with the following data...\n");
dump_rpcent(rpc_model);
rpc = getrpcbynumber(rpc_model->r_number);
if (rpcent_test_correctness(rpc, NULL) != 0 ||
(compare_rpcent(rpc, rpc_model, NULL) != 0 &&
rpcent_check_ambiguity((struct rpcent_test_data *)mdata, rpc)
!= 0)) {
printf("not ok\n");
return (-1);
} else {
printf("ok\n");
return (0);
}
}
static int
rpcent_test_getrpcent(struct rpcent *rpc, void *mdata __unused)
{
/*
* Only correctness can be checked when doing 1-pass test for
* getrpcent().
*/
return (rpcent_test_correctness(rpc, NULL));
}
static int
run_tests(const char *snapshot_file, enum test_methods method)
{
struct rpcent_test_data td, td_snap, td_2pass;
int rv;
TEST_DATA_INIT(rpcent, &td, clone_rpcent, free_rpcent);
TEST_DATA_INIT(rpcent, &td_snap, clone_rpcent, free_rpcent);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(rpcent, snapshot_file,
&td_snap, rpcent_read_snapshot_func);
}
}
rv = rpcent_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETRPCBYNAME:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(rpcent, &td,
rpcent_test_getrpcbyname, (void *)&td);
else
rv = DO_1PASS_TEST(rpcent, &td_snap,
rpcent_test_getrpcbyname, (void *)&td_snap);
break;
case TEST_GETRPCBYNUMBER:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(rpcent, &td,
rpcent_test_getrpcbynumber, (void *)&td);
else
rv = DO_1PASS_TEST(rpcent, &td_snap,
rpcent_test_getrpcbynumber, (void *)&td_snap);
break;
case TEST_GETRPCENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(rpcent, &td, rpcent_test_getrpcent,
(void *)&td);
else
rv = DO_2PASS_TEST(rpcent, &td, &td_snap,
compare_rpcent, NULL);
break;
case TEST_GETRPCENT_2PASS:
TEST_DATA_INIT(rpcent, &td_2pass, clone_rpcent, free_rpcent);
rv = rpcent_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(rpcent, &td, &td_2pass,
compare_rpcent, NULL);
TEST_DATA_DESTROY(rpcent, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(rpcent, snapshot_file, &td,
sdump_rpcent);
break;
default:
rv = 0;
break;
}
fin:
TEST_DATA_DESTROY(rpcent, &td_snap);
TEST_DATA_DESTROY(rpcent, &td);
return (rv);
}
#define SNAPSHOT_FILE "snapshot_rpc"
ATF_TC_WITHOUT_HEAD(build_snapshot);
ATF_TC_BODY(build_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
}
ATF_TC_WITHOUT_HEAD(getrpcbyname);
ATF_TC_BODY(getrpcbyname, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNAME) == 0);
}
ATF_TC_WITHOUT_HEAD(getrpcbyname_with_snapshot);
ATF_TC_BODY(getrpcbyname_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNAME) == 0);
}
ATF_TC_WITHOUT_HEAD(getrpcbynumber);
ATF_TC_BODY(getrpcbynumber, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETRPCBYNUMBER) == 0);
}
ATF_TC_WITHOUT_HEAD(getrpcbynumber_with_snapshot);
ATF_TC_BODY(getrpcbynumber_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCBYNUMBER) == 0);
}
ATF_TC_WITHOUT_HEAD(getrpcbyent);
ATF_TC_BODY(getrpcbyent, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getrpcbyent_with_snapshot);
ATF_TC_BODY(getrpcbyent_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETRPCENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getrpcbyent_with_two_pass);
ATF_TC_BODY(getrpcbyent_with_two_pass, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETRPCENT_2PASS) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, build_snapshot);
ATF_TP_ADD_TC(tp, getrpcbyname);
ATF_TP_ADD_TC(tp, getrpcbyname_with_snapshot);
ATF_TP_ADD_TC(tp, getrpcbynumber);
ATF_TP_ADD_TC(tp, getrpcbynumber_with_snapshot);
ATF_TP_ADD_TC(tp, getrpcbyent);
ATF_TP_ADD_TC(tp, getrpcbyent_with_snapshot);
ATF_TP_ADD_TC(tp, getrpcbyent_with_two_pass);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/getserv_test.c b/lib/libc/tests/nss/getserv_test.c
index d74feb113a69..486a8c20836f 100644
--- a/lib/libc/tests/nss/getserv_test.c
+++ b/lib/libc/tests/nss/getserv_test.c
@@ -1,568 +1,567 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <arpa/inet.h>
#include <errno.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stringlist.h>
#include <unistd.h>
#include <atf-c.h>
#include "testutil.h"
enum test_methods {
TEST_GETSERVENT,
TEST_GETSERVBYNAME,
TEST_GETSERVBYPORT,
TEST_GETSERVENT_2PASS,
TEST_BUILD_SNAPSHOT
};
DECLARE_TEST_DATA(servent)
DECLARE_TEST_FILE_SNAPSHOT(servent)
DECLARE_1PASS_TEST(servent)
DECLARE_2PASS_TEST(servent)
static void clone_servent(struct servent *, struct servent const *);
static int compare_servent(struct servent *, struct servent *, void *);
static void dump_servent(struct servent *);
static void free_servent(struct servent *);
static void sdump_servent(struct servent *, char *, size_t);
static int servent_read_snapshot_func(struct servent *, char *);
static int servent_check_ambiguity(struct servent_test_data *,
struct servent *);
static int servent_fill_test_data(struct servent_test_data *);
static int servent_test_correctness(struct servent *, void *);
static int servent_test_getservbyname(struct servent *, void *);
static int servent_test_getservbyport(struct servent *, void *);
static int servent_test_getservent(struct servent *, void *);
IMPLEMENT_TEST_DATA(servent)
IMPLEMENT_TEST_FILE_SNAPSHOT(servent)
IMPLEMENT_1PASS_TEST(servent)
IMPLEMENT_2PASS_TEST(servent)
static void
clone_servent(struct servent *dest, struct servent const *src)
{
ATF_REQUIRE(dest != NULL);
ATF_REQUIRE(src != NULL);
char **cp;
int aliases_num;
memset(dest, 0, sizeof(struct servent));
if (src->s_name != NULL) {
dest->s_name = strdup(src->s_name);
ATF_REQUIRE(dest->s_name != NULL);
}
if (src->s_proto != NULL) {
dest->s_proto = strdup(src->s_proto);
ATF_REQUIRE(dest->s_proto != NULL);
}
dest->s_port = src->s_port;
if (src->s_aliases != NULL) {
aliases_num = 0;
for (cp = src->s_aliases; *cp; ++cp)
++aliases_num;
dest->s_aliases = calloc(aliases_num + 1, sizeof(char *));
ATF_REQUIRE(dest->s_aliases != NULL);
for (cp = src->s_aliases; *cp; ++cp) {
dest->s_aliases[cp - src->s_aliases] = strdup(*cp);
ATF_REQUIRE(dest->s_aliases[cp - src->s_aliases] != NULL);
}
}
}
static void
free_servent(struct servent *serv)
{
char **cp;
ATF_REQUIRE(serv != NULL);
free(serv->s_name);
free(serv->s_proto);
for (cp = serv->s_aliases; *cp; ++cp)
free(*cp);
free(serv->s_aliases);
}
static int
compare_servent(struct servent *serv1, struct servent *serv2, void *mdata)
{
char **c1, **c2;
if (serv1 == serv2)
return 0;
if ((serv1 == NULL) || (serv2 == NULL))
goto errfin;
if ((strcmp(serv1->s_name, serv2->s_name) != 0) ||
(strcmp(serv1->s_proto, serv2->s_proto) != 0) ||
(serv1->s_port != serv2->s_port))
goto errfin;
c1 = serv1->s_aliases;
c2 = serv2->s_aliases;
if ((serv1->s_aliases == NULL) || (serv2->s_aliases == NULL))
goto errfin;
for (;*c1 && *c2; ++c1, ++c2)
if (strcmp(*c1, *c2) != 0)
goto errfin;
if ((*c1 != NULL) || (*c2 != NULL))
goto errfin;
return 0;
errfin:
if (mdata == NULL) {
printf("following structures are not equal:\n");
dump_servent(serv1);
dump_servent(serv2);
}
return (-1);
}
static void
sdump_servent(struct servent *serv, char *buffer, size_t buflen)
{
char **cp;
int written;
written = snprintf(buffer, buflen, "%s %d %s",
serv->s_name, ntohs(serv->s_port), serv->s_proto);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (serv->s_aliases != NULL) {
if (*(serv->s_aliases) != NULL) {
for (cp = serv->s_aliases; *cp; ++cp) {
written = snprintf(buffer, buflen, " %s", *cp);
buffer += written;
if (written > (int)buflen)
return;
buflen -= written;
if (buflen == 0)
return;
}
} else
snprintf(buffer, buflen, " noaliases");
} else
snprintf(buffer, buflen, " (null)");
}
static int
servent_read_snapshot_func(struct servent *serv, char *line)
{
StringList *sl;
char *s, *ps, *ts;
int i;
printf("1 line read from snapshot:\n%s\n", line);
i = 0;
sl = NULL;
ps = line;
memset(serv, 0, sizeof(struct servent));
while ( (s = strsep(&ps, " ")) != NULL) {
switch (i) {
case 0:
serv->s_name = strdup(s);
ATF_REQUIRE(serv->s_name != NULL);
break;
case 1:
serv->s_port = htons(
(int)strtol(s, &ts, 10));
if (*ts != '\0') {
free(serv->s_name);
return (-1);
}
break;
case 2:
serv->s_proto = strdup(s);
ATF_REQUIRE(serv->s_proto != NULL);
break;
default:
if (sl == NULL) {
if (strcmp(s, "(null)") == 0)
return (0);
sl = sl_init();
ATF_REQUIRE(sl != NULL);
if (strcmp(s, "noaliases") != 0) {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl, ts);
}
} else {
ts = strdup(s);
ATF_REQUIRE(ts != NULL);
sl_add(sl, ts);
}
break;
}
++i;
}
if (i < 3) {
free(serv->s_name);
free(serv->s_proto);
memset(serv, 0, sizeof(struct servent));
return (-1);
}
sl_add(sl, NULL);
serv->s_aliases = sl->sl_str;
/* NOTE: is it a dirty hack or not? */
free(sl);
return (0);
}
static void
dump_servent(struct servent *result)
{
if (result != NULL) {
char buffer[1024];
sdump_servent(result, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
servent_fill_test_data(struct servent_test_data *td)
{
struct servent *serv;
setservent(1);
while ((serv = getservent()) != NULL) {
if (servent_test_correctness(serv, NULL) == 0)
TEST_DATA_APPEND(servent, td, serv);
else
return (-1);
}
endservent();
return (0);
}
static int
servent_test_correctness(struct servent *serv, void *mdata __unused)
{
printf("testing correctness with the following data:\n");
dump_servent(serv);
if (serv == NULL)
goto errfin;
if (serv->s_name == NULL)
goto errfin;
if (serv->s_proto == NULL)
goto errfin;
if (ntohs(serv->s_port < 0))
goto errfin;
if (serv->s_aliases == NULL)
goto errfin;
printf("correct\n");
return (0);
errfin:
printf("incorrect\n");
return (-1);
}
/* servent_check_ambiguity() is needed when one port+proto is associated with
* more than one service (these cases are usually marked as PROBLEM in
* /etc/services. This functions is needed also when one service+proto is
* associated with several ports. We have to check all the servent structures
* to make sure that serv really exists and correct */
static int
servent_check_ambiguity(struct servent_test_data *td, struct servent *serv)
{
return (TEST_DATA_FIND(servent, td, serv, compare_servent,
NULL) != NULL ? 0 : -1);
}
static int
servent_test_getservbyname(struct servent *serv_model, void *mdata)
{
char **alias;
struct servent *serv;
printf("testing getservbyname() with the following data:\n");
dump_servent(serv_model);
serv = getservbyname(serv_model->s_name, serv_model->s_proto);
if (servent_test_correctness(serv, NULL) != 0)
goto errfin;
if ((compare_servent(serv, serv_model, NULL) != 0) &&
(servent_check_ambiguity((struct servent_test_data *)mdata, serv)
!=0))
goto errfin;
for (alias = serv_model->s_aliases; *alias; ++alias) {
serv = getservbyname(*alias, serv_model->s_proto);
if (servent_test_correctness(serv, NULL) != 0)
goto errfin;
if ((compare_servent(serv, serv_model, NULL) != 0) &&
(servent_check_ambiguity(
(struct servent_test_data *)mdata, serv) != 0))
goto errfin;
}
printf("ok\n");
return (0);
errfin:
printf("not ok\n");
return (-1);
}
static int
servent_test_getservbyport(struct servent *serv_model, void *mdata)
{
struct servent *serv;
printf("testing getservbyport() with the following data...\n");
dump_servent(serv_model);
serv = getservbyport(serv_model->s_port, serv_model->s_proto);
if ((servent_test_correctness(serv, NULL) != 0) ||
((compare_servent(serv, serv_model, NULL) != 0) &&
(servent_check_ambiguity((struct servent_test_data *)mdata, serv)
!= 0))) {
printf("not ok\n");
return (-1);
} else {
printf("ok\n");
return (0);
}
}
static int
servent_test_getservent(struct servent *serv, void *mdata __unused)
{
/* Only correctness can be checked when doing 1-pass test for
* getservent(). */
return (servent_test_correctness(serv, NULL));
}
static int
run_tests(const char *snapshot_file, enum test_methods method)
{
struct servent_test_data td, td_snap, td_2pass;
int rv;
TEST_DATA_INIT(servent, &td, clone_servent, free_servent);
TEST_DATA_INIT(servent, &td_snap, clone_servent, free_servent);
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
printf("can't access the file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
if (method == TEST_BUILD_SNAPSHOT) {
rv = 0;
goto fin;
}
TEST_SNAPSHOT_FILE_READ(servent, snapshot_file,
&td_snap, servent_read_snapshot_func);
}
}
rv = servent_fill_test_data(&td);
if (rv == -1)
return (-1);
switch (method) {
case TEST_GETSERVBYNAME:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(servent, &td,
servent_test_getservbyname, (void *)&td);
else
rv = DO_1PASS_TEST(servent, &td_snap,
servent_test_getservbyname, (void *)&td_snap);
break;
case TEST_GETSERVBYPORT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(servent, &td,
servent_test_getservbyport, (void *)&td);
else
rv = DO_1PASS_TEST(servent, &td_snap,
servent_test_getservbyport, (void *)&td_snap);
break;
case TEST_GETSERVENT:
if (snapshot_file == NULL)
rv = DO_1PASS_TEST(servent, &td, servent_test_getservent,
(void *)&td);
else
rv = DO_2PASS_TEST(servent, &td, &td_snap,
compare_servent, NULL);
break;
case TEST_GETSERVENT_2PASS:
TEST_DATA_INIT(servent, &td_2pass, clone_servent, free_servent);
rv = servent_fill_test_data(&td_2pass);
if (rv != -1)
rv = DO_2PASS_TEST(servent, &td, &td_2pass,
compare_servent, NULL);
TEST_DATA_DESTROY(servent, &td_2pass);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL)
rv = TEST_SNAPSHOT_FILE_WRITE(servent, snapshot_file, &td,
sdump_servent);
break;
default:
rv = 0;
break;
}
fin:
TEST_DATA_DESTROY(servent, &td_snap);
TEST_DATA_DESTROY(servent, &td);
return (rv);
}
#define SNAPSHOT_FILE "snapshot_serv"
ATF_TC_WITHOUT_HEAD(build_snapshot);
ATF_TC_BODY(build_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
}
ATF_TC_WITHOUT_HEAD(getservbyname);
ATF_TC_BODY(getservbyname, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYNAME) == 0);
}
ATF_TC_WITHOUT_HEAD(getservbyname_with_snapshot);
ATF_TC_BODY(getservbyname_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYNAME) == 0);
}
ATF_TC_WITHOUT_HEAD(getservbyport);
ATF_TC_BODY(getservbyport, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETSERVBYPORT) == 0);
}
ATF_TC_WITHOUT_HEAD(getservbyport_with_snapshot);
ATF_TC_BODY(getservbyport_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVBYPORT) == 0);
}
ATF_TC_WITHOUT_HEAD(getservbyent);
ATF_TC_BODY(getservbyent, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getservbyent_with_snapshot);
ATF_TC_BODY(getservbyent_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETSERVENT) == 0);
}
ATF_TC_WITHOUT_HEAD(getservbyent_with_two_pass);
ATF_TC_BODY(getservbyent_with_two_pass, tc)
{
ATF_REQUIRE(run_tests(NULL, TEST_GETSERVENT_2PASS) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, build_snapshot);
ATF_TP_ADD_TC(tp, getservbyent);
ATF_TP_ADD_TC(tp, getservbyent_with_snapshot);
ATF_TP_ADD_TC(tp, getservbyent_with_two_pass);
ATF_TP_ADD_TC(tp, getservbyname);
ATF_TP_ADD_TC(tp, getservbyname_with_snapshot);
ATF_TP_ADD_TC(tp, getservbyport);
ATF_TP_ADD_TC(tp, getservbyport_with_snapshot);
return (atf_no_error());
}
diff --git a/lib/libc/tests/nss/getusershell_test.c b/lib/libc/tests/nss/getusershell_test.c
index e130f36351fb..ac23792fde8e 100644
--- a/lib/libc/tests/nss/getusershell_test.c
+++ b/lib/libc/tests/nss/getusershell_test.c
@@ -1,222 +1,221 @@
/*-
* Copyright (c) 2006 Michael Bushkov <bushman@freebsd.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
#include "testutil.h"
enum test_methods {
TEST_GETUSERSHELL,
TEST_BUILD_SNAPSHOT
};
struct usershell {
char *path;
};
DECLARE_TEST_DATA(usershell)
DECLARE_TEST_FILE_SNAPSHOT(usershell)
DECLARE_2PASS_TEST(usershell)
static void clone_usershell(struct usershell *, struct usershell const *);
static int compare_usershell(struct usershell *, struct usershell *, void *);
static void free_usershell(struct usershell *);
static void sdump_usershell(struct usershell *, char *, size_t);
static void dump_usershell(struct usershell *);
IMPLEMENT_TEST_DATA(usershell)
IMPLEMENT_TEST_FILE_SNAPSHOT(usershell)
IMPLEMENT_2PASS_TEST(usershell)
static void
clone_usershell(struct usershell *dest, struct usershell const *src)
{
assert(dest != NULL);
assert(src != NULL);
if (src->path != NULL) {
dest->path = strdup(src->path);
assert(dest->path != NULL);
}
}
static int
compare_usershell(struct usershell *us1, struct usershell *us2,
void *mdata __unused)
{
int rv;
assert(us1 != NULL);
assert(us2 != NULL);
dump_usershell(us1);
dump_usershell(us2);
if (us1 == us2)
return (0);
rv = strcmp(us1->path, us2->path);
if (rv != 0) {
printf("following structures are not equal:\n");
dump_usershell(us1);
dump_usershell(us2);
}
return (rv);
}
static void
free_usershell(struct usershell *us)
{
free(us->path);
}
static void
sdump_usershell(struct usershell *us, char *buffer, size_t buflen)
{
snprintf(buffer, buflen, "%s", us->path);
}
static void
dump_usershell(struct usershell *us)
{
if (us != NULL) {
char buffer[2048];
sdump_usershell(us, buffer, sizeof(buffer));
printf("%s\n", buffer);
} else
printf("(null)\n");
}
static int
usershell_read_snapshot_func(struct usershell *us, char *line)
{
us->path = strdup(line);
ATF_REQUIRE(us->path != NULL);
return (0);
}
static int
run_tests(const char *snapshot_file, enum test_methods method)
{
struct usershell_test_data td, td_snap;
struct usershell ushell;
int rv;
rv = 0;
TEST_DATA_INIT(usershell, &td, clone_usershell, free_usershell);
TEST_DATA_INIT(usershell, &td_snap, clone_usershell, free_usershell);
setusershell();
while ((ushell.path = getusershell()) != NULL) {
printf("usershell found:\n");
dump_usershell(&ushell);
TEST_DATA_APPEND(usershell, &td, &ushell);
}
endusershell();
if (snapshot_file != NULL) {
if (access(snapshot_file, W_OK | R_OK) != 0) {
if (errno == ENOENT)
method = TEST_BUILD_SNAPSHOT;
else {
printf("can't access the snapshot file %s\n",
snapshot_file);
rv = -1;
goto fin;
}
} else {
rv = TEST_SNAPSHOT_FILE_READ(usershell, snapshot_file,
&td_snap, usershell_read_snapshot_func);
if (rv != 0) {
printf("error reading snapshot file\n");
goto fin;
}
}
}
switch (method) {
case TEST_GETUSERSHELL:
rv = DO_2PASS_TEST(usershell, &td, &td_snap,
compare_usershell, NULL);
break;
case TEST_BUILD_SNAPSHOT:
if (snapshot_file != NULL) {
rv = TEST_SNAPSHOT_FILE_WRITE(usershell, snapshot_file,
&td, sdump_usershell);
}
break;
default:
rv = 0;
break;
}
fin:
TEST_DATA_DESTROY(usershell, &td_snap);
TEST_DATA_DESTROY(usershell, &td);
return (rv);
}
#define SNAPSHOT_FILE "snapshot_usershell"
ATF_TC_WITHOUT_HEAD(getusershell_with_snapshot);
ATF_TC_BODY(getusershell_with_snapshot, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
}
ATF_TC_WITHOUT_HEAD(getusershell_with_two_pass);
ATF_TC_BODY(getusershell_with_two_pass, tc)
{
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_BUILD_SNAPSHOT) == 0);
ATF_REQUIRE(run_tests(SNAPSHOT_FILE, TEST_GETUSERSHELL) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getusershell_with_snapshot);
ATF_TP_ADD_TC(tp, getusershell_with_two_pass);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/fdopen_test.c b/lib/libc/tests/stdio/fdopen_test.c
index 211e16279a3c..5abaed7375b6 100644
--- a/lib/libc/tests/stdio/fdopen_test.c
+++ b/lib/libc/tests/stdio/fdopen_test.c
@@ -1,223 +1,222 @@
/*-
* Copyright (c) 2014 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
static void
runtest(const char *fname, int intmode, const char *strmode, bool success)
{
FILE *fp;
int fd;
fd = open(fname, intmode);
ATF_REQUIRE_MSG(fd != -1,
"open(\"%s\", %#x) failed; errno=%d", fname, intmode, errno);
fp = fdopen(fd, strmode);
if (fp == NULL) {
close(fd);
ATF_REQUIRE_MSG(success == false,
"fdopen(open(\"%s\", %#x), \"%s\") succeeded unexpectedly",
fname, intmode, strmode);
return;
}
ATF_REQUIRE_MSG(success == true,
"fdopen(open(\"%s\", %#x), \"%s\") failed; errno=%d",
fname, intmode, strmode, errno);
fclose(fp);
}
ATF_TC_WITHOUT_HEAD(null__O_RDONLY__r_test);
ATF_TC_BODY(null__O_RDONLY__r_test, tc)
{
runtest(_PATH_DEVNULL, O_RDONLY, "r", true);
}
ATF_TC_WITHOUT_HEAD(null__O_WRONLY__r_test);
ATF_TC_BODY(null__O_WRONLY__r_test, tc)
{
runtest(_PATH_DEVNULL, O_WRONLY, "r", false);
}
ATF_TC_WITHOUT_HEAD(null__O_RDWR__r_test);
ATF_TC_BODY(null__O_RDWR__r_test, tc)
{
runtest(_PATH_DEVNULL, O_RDWR, "r", true);
}
ATF_TC_WITHOUT_HEAD(null__O_RDONLY__w_test);
ATF_TC_BODY(null__O_RDONLY__w_test, tc)
{
runtest(_PATH_DEVNULL, O_RDONLY, "w", false);
}
ATF_TC_WITHOUT_HEAD(null__O_WRONLY__w_test);
ATF_TC_BODY(null__O_WRONLY__w_test, tc)
{
runtest(_PATH_DEVNULL, O_WRONLY, "w", true);
}
ATF_TC_WITHOUT_HEAD(null__O_RDWR__w_test);
ATF_TC_BODY(null__O_RDWR__w_test, tc)
{
runtest(_PATH_DEVNULL, O_RDWR, "w", true);
}
ATF_TC_WITHOUT_HEAD(null__O_RDONLY__a_test);
ATF_TC_BODY(null__O_RDONLY__a_test, tc)
{
runtest(_PATH_DEVNULL, O_RDONLY, "a", false);
}
ATF_TC_WITHOUT_HEAD(null__O_WRONLY__a_test);
ATF_TC_BODY(null__O_WRONLY__a_test, tc)
{
runtest(_PATH_DEVNULL, O_WRONLY, "a", true);
}
ATF_TC_WITHOUT_HEAD(null__O_RDWR__test);
ATF_TC_BODY(null__O_RDWR__test, tc)
{
runtest(_PATH_DEVNULL, O_RDWR, "a", true);
}
ATF_TC_WITHOUT_HEAD(null__O_RDONLY__r_append);
ATF_TC_BODY(null__O_RDONLY__r_append, tc)
{
runtest(_PATH_DEVNULL, O_RDONLY, "r+", false);
}
ATF_TC_WITHOUT_HEAD(null__O_WRONLY__r_append);
ATF_TC_BODY(null__O_WRONLY__r_append, tc)
{
runtest(_PATH_DEVNULL, O_WRONLY, "r+", false);
}
ATF_TC_WITHOUT_HEAD(null__O_RDWR__r_append);
ATF_TC_BODY(null__O_RDWR__r_append, tc)
{
runtest(_PATH_DEVNULL, O_RDWR, "r+", true);
}
ATF_TC_WITHOUT_HEAD(null__O_RDONLY__w_append);
ATF_TC_BODY(null__O_RDONLY__w_append, tc)
{
runtest(_PATH_DEVNULL, O_RDONLY, "w+", false);
}
ATF_TC_WITHOUT_HEAD(null__O_WRONLY__w_append);
ATF_TC_BODY(null__O_WRONLY__w_append, tc)
{
runtest(_PATH_DEVNULL, O_WRONLY, "w+", false);
}
ATF_TC_WITHOUT_HEAD(null__O_RDWR__w_append);
ATF_TC_BODY(null__O_RDWR__w_append, tc)
{
runtest(_PATH_DEVNULL, O_RDWR, "w+", true);
}
ATF_TC_WITHOUT_HEAD(sh__O_EXEC__r);
ATF_TC_BODY(sh__O_EXEC__r, tc)
{
runtest("/bin/sh", O_EXEC, "r", false);
}
ATF_TC_WITHOUT_HEAD(sh__O_EXEC__w);
ATF_TC_BODY(sh__O_EXEC__w, tc)
{
runtest("/bin/sh", O_EXEC, "w", false);
}
ATF_TC_WITHOUT_HEAD(sh__O_EXEC__r_append);
ATF_TC_BODY(sh__O_EXEC__r_append, tc)
{
runtest("/bin/sh", O_EXEC, "r+", false);
}
ATF_TC_WITHOUT_HEAD(sh__O_EXEC__w_append);
ATF_TC_BODY(sh__O_EXEC__w_append, tc)
{
runtest("/bin/sh", O_EXEC, "w+", false);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, null__O_RDONLY__r_test);
ATF_TP_ADD_TC(tp, null__O_WRONLY__r_test);
ATF_TP_ADD_TC(tp, null__O_RDWR__r_test);
ATF_TP_ADD_TC(tp, null__O_RDONLY__w_test);
ATF_TP_ADD_TC(tp, null__O_WRONLY__w_test);
ATF_TP_ADD_TC(tp, null__O_RDWR__w_test);
ATF_TP_ADD_TC(tp, null__O_RDONLY__a_test);
ATF_TP_ADD_TC(tp, null__O_WRONLY__a_test);
ATF_TP_ADD_TC(tp, null__O_RDWR__test);
ATF_TP_ADD_TC(tp, null__O_RDONLY__r_append);
ATF_TP_ADD_TC(tp, null__O_WRONLY__r_append);
ATF_TP_ADD_TC(tp, null__O_RDWR__r_append);
ATF_TP_ADD_TC(tp, null__O_RDONLY__w_append);
ATF_TP_ADD_TC(tp, null__O_WRONLY__w_append);
ATF_TP_ADD_TC(tp, null__O_RDWR__w_append);
ATF_TP_ADD_TC(tp, sh__O_EXEC__r);
ATF_TP_ADD_TC(tp, sh__O_EXEC__w);
ATF_TP_ADD_TC(tp, sh__O_EXEC__r_append);
ATF_TP_ADD_TC(tp, sh__O_EXEC__w_append);
return (atf_no_error());
}
/*
vim:ts=8:cin:sw=8
*/
diff --git a/lib/libc/tests/stdio/fmemopen2_test.c b/lib/libc/tests/stdio/fmemopen2_test.c
index d68150d19594..2e1b9ea917a5 100644
--- a/lib/libc/tests/stdio/fmemopen2_test.c
+++ b/lib/libc/tests/stdio/fmemopen2_test.c
@@ -1,286 +1,285 @@
/*-
Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
/*
* Test basic FILE * functions (fread, fwrite, fseek, fclose) against
* a FILE * retrieved using fmemopen()
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(test_preexisting);
ATF_TC_BODY(test_preexisting, tc)
{
/* Use a pre-existing buffer. */
char buf[512];
char buf2[512];
char str[] = "Test writing some stuff";
char str2[] = "AAAAAAAAA";
char str3[] = "AAAA writing some stuff";
FILE *fp;
size_t nofw, nofr;
int rc;
/* Open a FILE * using fmemopen. */
fp = fmemopen(buf, sizeof(buf), "w");
ATF_REQUIRE(fp != NULL);
/* Write to the buffer. */
nofw = fwrite(str, 1, sizeof(str), fp);
ATF_REQUIRE(nofw == sizeof(str));
/* Close the FILE *. */
rc = fclose(fp);
ATF_REQUIRE(rc == 0);
/* Re-open the FILE * to read back the data. */
fp = fmemopen(buf, sizeof(buf), "r");
ATF_REQUIRE(fp != NULL);
/* Read from the buffer. */
bzero(buf2, sizeof(buf2));
nofr = fread(buf2, 1, sizeof(buf2), fp);
ATF_REQUIRE(nofr == sizeof(buf2));
/*
* Since a write on a FILE * retrieved by fmemopen
* will add a '\0' (if there's space), we can check
* the strings for equality.
*/
ATF_REQUIRE(strcmp(str, buf2) == 0);
/* Close the FILE *. */
rc = fclose(fp);
ATF_REQUIRE(rc == 0);
/* Now open a FILE * on the first 4 bytes of the string. */
fp = fmemopen(str, 4, "w");
ATF_REQUIRE(fp != NULL);
/*
* Try to write more bytes than we shoud, we'll get a short count (4).
*/
nofw = fwrite(str2, 1, sizeof(str2), fp);
ATF_REQUIRE(nofw == 4);
/* Close the FILE *. */
rc = fclose(fp);
ATF_REQUIRE(rc == 0);
/* Check that the string was not modified after the first 4 bytes. */
ATF_REQUIRE(strcmp(str, str3) == 0);
}
ATF_TC_WITHOUT_HEAD(test_autoalloc);
ATF_TC_BODY(test_autoalloc, tc)
{
/* Let fmemopen allocate the buffer. */
FILE *fp;
long pos;
size_t nofw, i;
int rc;
/* Open a FILE * using fmemopen. */
fp = fmemopen(NULL, 512, "w+");
ATF_REQUIRE(fp != NULL);
/* fill the buffer */
for (i = 0; i < 512; i++) {
nofw = fwrite("a", 1, 1, fp);
ATF_REQUIRE(nofw == 1);
}
/* Get the current position into the stream. */
pos = ftell(fp);
ATF_REQUIRE(pos == 512);
/* Try to write past the end, we should get a short object count (0) */
nofw = fwrite("a", 1, 1, fp);
ATF_REQUIRE(nofw == 0);
/* Close the FILE *. */
rc = fclose(fp);
ATF_REQUIRE(rc == 0);
/* Open a FILE * using a wrong mode */
fp = fmemopen(NULL, 512, "r");
ATF_REQUIRE(fp == NULL);
fp = fmemopen(NULL, 512, "w");
ATF_REQUIRE(fp == NULL);
}
ATF_TC_WITHOUT_HEAD(test_data_length);
ATF_TC_BODY(test_data_length, tc)
{
/*
* Here we test that a read operation doesn't go past the end of the
* data actually written, and that a SEEK_END seeks from the end of the
* data, not of the whole buffer.
*/
FILE *fp;
char buf[512] = {'\0'};
char str[] = "Test data length. ";
char str2[] = "Do we have two sentences?";
char str3[sizeof(str) + sizeof(str2) -1];
long pos;
size_t nofw, nofr;
int rc;
/* Open a FILE * for updating our buffer. */
fp = fmemopen(buf, sizeof(buf), "w+");
ATF_REQUIRE(fp != NULL);
/* Write our string into the buffer. */
nofw = fwrite(str, 1, sizeof(str), fp);
ATF_REQUIRE(nofw == sizeof(str));
/* Now seek to the end and check that ftell gives us sizeof(str). */
rc = fseek(fp, 0, SEEK_END);
ATF_REQUIRE(rc == 0);
pos = ftell(fp);
ATF_REQUIRE(pos == sizeof(str));
/* Close the FILE *. */
rc = fclose(fp);
ATF_REQUIRE(rc == 0);
/* Reopen the buffer for appending. */
fp = fmemopen(buf, sizeof(buf), "a+");
ATF_REQUIRE(fp != NULL);
/* We should now be writing after the first string. */
nofw = fwrite(str2, 1, sizeof(str2), fp);
ATF_REQUIRE(nofw == sizeof(str2));
/* Rewind the FILE *. */
rc = fseek(fp, 0, SEEK_SET);
ATF_REQUIRE(rc == 0);
/* Make sure we're at the beginning. */
pos = ftell(fp);
ATF_REQUIRE(pos == 0);
/* Read the whole buffer. */
nofr = fread(str3, 1, sizeof(buf), fp);
ATF_REQUIRE(nofr == sizeof(str3));
/* Make sure the two strings are there. */
ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
/* Close the FILE *. */
rc = fclose(fp);
ATF_REQUIRE(rc == 0);
}
ATF_TC_WITHOUT_HEAD(test_binary);
ATF_TC_BODY(test_binary, tc)
{
/*
* Make sure that NULL bytes are never appended when opening a buffer
* in binary mode.
*/
FILE *fp;
char buf[20];
char str[] = "Test";
size_t nofw;
int rc, i;
/* Pre-fill the buffer. */
memset(buf, 'A', sizeof(buf));
/* Open a FILE * in binary mode. */
fp = fmemopen(buf, sizeof(buf), "w+b");
ATF_REQUIRE(fp != NULL);
/* Write some data into it. */
nofw = fwrite(str, 1, strlen(str), fp);
ATF_REQUIRE(nofw == strlen(str));
/* Make sure that the buffer doesn't contain any NULL bytes. */
for (i = 0; i < sizeof(buf); i++)
ATF_REQUIRE(buf[i] != '\0');
/* Close the FILE *. */
rc = fclose(fp);
ATF_REQUIRE(rc == 0);
}
ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
ATF_TC_BODY(test_append_binary_pos, tc)
{
/*
* For compatibility with other implementations (glibc), we set the
* position to 0 when opening an automatically allocated binary stream
* for appending.
*/
FILE *fp;
fp = fmemopen(NULL, 16, "ab+");
ATF_REQUIRE(fp != NULL);
ATF_REQUIRE(ftell(fp) == 0L);
fclose(fp);
/* Make sure that a pre-allocated buffer behaves correctly. */
char buf[] = "Hello";
fp = fmemopen(buf, sizeof(buf), "ab+");
ATF_REQUIRE(fp != NULL);
ATF_REQUIRE(ftell(fp) == strlen(buf));
fclose(fp);
}
ATF_TC_WITHOUT_HEAD(test_size_0);
ATF_TC_BODY(test_size_0, tc)
{
/* POSIX mandates that we return EINVAL if size is 0. */
FILE *fp;
fp = fmemopen(NULL, 0, "r+");
ATF_REQUIRE(fp == NULL);
ATF_REQUIRE(errno == EINVAL);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, test_autoalloc);
ATF_TP_ADD_TC(tp, test_preexisting);
ATF_TP_ADD_TC(tp, test_data_length);
ATF_TP_ADD_TC(tp, test_binary);
ATF_TP_ADD_TC(tp, test_append_binary_pos);
ATF_TP_ADD_TC(tp, test_size_0);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/fopen_test.c b/lib/libc/tests/stdio/fopen_test.c
index fdc460716ff2..4dda5cbf0e5e 100644
--- a/lib/libc/tests/stdio/fopen_test.c
+++ b/lib/libc/tests/stdio/fopen_test.c
@@ -1,203 +1,202 @@
/*-
* Copyright (c) 2013 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <string.h>
#include <atf-c.h>
/*
* O_ACCMODE is currently defined incorrectly. This is what it should be.
* Various code depends on the incorrect value.
*/
#define CORRECT_O_ACCMODE (O_ACCMODE | O_EXEC)
static void
runtest(const char *fname, const char *mode)
{
FILE *fp;
int exp_fget_ret, fget_ret, fd, flags, wantedflags;
fp = fopen(fname, mode);
ATF_REQUIRE_MSG(fp != NULL,
"fopen(\"%s\", \"%s\") failed", fname, mode);
fd = fileno(fp);
ATF_REQUIRE_MSG(fd >= 0, "fileno() failed for fopen");
exp_fget_ret = strchr(mode, 'e') != NULL ? FD_CLOEXEC : 0;
ATF_REQUIRE_MSG((fget_ret = fcntl(fd, F_GETFD)) == exp_fget_ret,
"fcntl(.., F_GETFD) didn't FD_CLOEXEC as expected %d != %d",
exp_fget_ret, fget_ret);
flags = fcntl(fd, F_GETFL);
if (strchr(mode, '+'))
wantedflags = O_RDWR | (*mode == 'a' ? O_APPEND : 0);
else if (*mode == 'r')
wantedflags = O_RDONLY;
else if (*mode == 'w')
wantedflags = O_WRONLY;
else if (*mode == 'a')
wantedflags = O_WRONLY | O_APPEND;
else
wantedflags = -1;
fclose(fp);
if (wantedflags == -1)
atf_tc_fail("unrecognized mode: %s", mode);
else if ((flags & (CORRECT_O_ACCMODE | O_APPEND)) != wantedflags)
atf_tc_fail("incorrect access mode: %s", mode);
}
ATF_TC_WITHOUT_HEAD(fopen_r_test);
ATF_TC_BODY(fopen_r_test, tc)
{
runtest(_PATH_DEVNULL, "r");
}
ATF_TC_WITHOUT_HEAD(fopen_r_append_test);
ATF_TC_BODY(fopen_r_append_test, tc)
{
runtest(_PATH_DEVNULL, "r+");
}
ATF_TC_WITHOUT_HEAD(fopen_w_test);
ATF_TC_BODY(fopen_w_test, tc)
{
runtest(_PATH_DEVNULL, "w");
}
ATF_TC_WITHOUT_HEAD(fopen_w_append_test);
ATF_TC_BODY(fopen_w_append_test, tc)
{
runtest(_PATH_DEVNULL, "w+");
}
ATF_TC_WITHOUT_HEAD(fopen_a_test);
ATF_TC_BODY(fopen_a_test, tc)
{
runtest(_PATH_DEVNULL, "a");
}
ATF_TC_WITHOUT_HEAD(fopen_a_append_test);
ATF_TC_BODY(fopen_a_append_test, tc)
{
runtest(_PATH_DEVNULL, "a+");
}
ATF_TC_WITHOUT_HEAD(fopen_re_test);
ATF_TC_BODY(fopen_re_test, tc)
{
runtest(_PATH_DEVNULL, "re");
}
ATF_TC_WITHOUT_HEAD(fopen_r_append_e_test);
ATF_TC_BODY(fopen_r_append_e_test, tc)
{
runtest(_PATH_DEVNULL, "r+e");
}
ATF_TC_WITHOUT_HEAD(fopen_we_test);
ATF_TC_BODY(fopen_we_test, tc)
{
runtest(_PATH_DEVNULL, "we");
}
ATF_TC_WITHOUT_HEAD(fopen_w_append_e_test);
ATF_TC_BODY(fopen_w_append_e_test, tc)
{
runtest(_PATH_DEVNULL, "w+e");
}
ATF_TC_WITHOUT_HEAD(fopen_ae_test);
ATF_TC_BODY(fopen_ae_test, tc)
{
runtest(_PATH_DEVNULL, "ae");
}
ATF_TC_WITHOUT_HEAD(fopen_a_append_e_test);
ATF_TC_BODY(fopen_a_append_e_test, tc)
{
runtest(_PATH_DEVNULL, "a+e");
}
ATF_TC_WITHOUT_HEAD(fopen_re_append_test);
ATF_TC_BODY(fopen_re_append_test, tc)
{
runtest(_PATH_DEVNULL, "re+");
}
ATF_TC_WITHOUT_HEAD(fopen_we_append_test);
ATF_TC_BODY(fopen_we_append_test, tc)
{
runtest(_PATH_DEVNULL, "we+");
}
ATF_TC_WITHOUT_HEAD(fopen_ae_append_test);
ATF_TC_BODY(fopen_ae_append_test, tc)
{
runtest(_PATH_DEVNULL, "ae+");
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, fopen_r_test);
ATF_TP_ADD_TC(tp, fopen_r_append_test);
ATF_TP_ADD_TC(tp, fopen_w_test);
ATF_TP_ADD_TC(tp, fopen_w_append_test);
ATF_TP_ADD_TC(tp, fopen_a_test);
ATF_TP_ADD_TC(tp, fopen_a_append_test);
ATF_TP_ADD_TC(tp, fopen_re_test);
ATF_TP_ADD_TC(tp, fopen_r_append_e_test);
ATF_TP_ADD_TC(tp, fopen_we_test);
ATF_TP_ADD_TC(tp, fopen_w_append_e_test);
ATF_TP_ADD_TC(tp, fopen_ae_test);
ATF_TP_ADD_TC(tp, fopen_a_append_e_test);
ATF_TP_ADD_TC(tp, fopen_re_append_test);
ATF_TP_ADD_TC(tp, fopen_we_append_test);
ATF_TP_ADD_TC(tp, fopen_ae_append_test);
return (atf_no_error());
}
/*
vim:ts=8:cin:sw=8
*/
diff --git a/lib/libc/tests/stdio/freopen_test.c b/lib/libc/tests/stdio/freopen_test.c
index 7318a95df089..55fe3c580dd3 100644
--- a/lib/libc/tests/stdio/freopen_test.c
+++ b/lib/libc/tests/stdio/freopen_test.c
@@ -1,221 +1,220 @@
/*-
* Copyright (c) 2014 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <errno.h>
#include <paths.h>
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <atf-c.h>
static void
runtest(const char *fname1, const char *mode1, const char *fname2,
const char *mode2, bool success)
{
FILE *fp1, *fp2;
const char *fname2_print;
fname2_print = fname2 != NULL ? fname2 : "<NULL>";
fp1 = fopen(fname1, mode1);
ATF_REQUIRE_MSG(fp1 != NULL,
"fopen(\"%s\", \"%s\") failed; errno=%d", fname1, mode1, errno);
fp2 = freopen(fname2, mode2, fp1);
if (fp2 == NULL) {
ATF_REQUIRE_MSG(success == false,
"freopen(\"%s\", \"%s\", fopen(\"%s\", \"%s\")) succeeded "
"unexpectedly", fname2_print, mode2, fname1, mode1);
return;
}
ATF_REQUIRE_MSG(success == true,
"freopen(\"%s\", \"%s\", fopen(\"%s\", \"%s\")) failed: %d",
fname2_print, mode2, fname1, mode1, errno);
fclose(fp2);
}
ATF_TC_WITHOUT_HEAD(null__r__r__test);
ATF_TC_BODY(null__r__r__test, tc)
{
runtest(_PATH_DEVNULL, "r", NULL, "r", true);
}
ATF_TC_WITHOUT_HEAD(null__w__r__test);
ATF_TC_BODY(null__w__r__test, tc)
{
runtest(_PATH_DEVNULL, "w", NULL, "r", false);
}
ATF_TC_WITHOUT_HEAD(null__r_append__r__test);
ATF_TC_BODY(null__r_append__r__test, tc)
{
runtest(_PATH_DEVNULL, "r+", NULL, "r", true);
}
ATF_TC_WITHOUT_HEAD(null__r__w__test);
ATF_TC_BODY(null__r__w__test, tc)
{
runtest(_PATH_DEVNULL, "r", NULL, "w", false);
}
ATF_TC_WITHOUT_HEAD(null__w__w__test);
ATF_TC_BODY(null__w__w__test, tc)
{
runtest(_PATH_DEVNULL, "w", NULL, "w", true);
}
ATF_TC_WITHOUT_HEAD(null__r_append__w__test);
ATF_TC_BODY(null__r_append__w__test, tc)
{
runtest(_PATH_DEVNULL, "r+", NULL, "w", true);
}
ATF_TC_WITHOUT_HEAD(null__r__a__test);
ATF_TC_BODY(null__r__a__test, tc)
{
runtest(_PATH_DEVNULL, "r", NULL, "a", false);
}
ATF_TC_WITHOUT_HEAD(null__w__a__test);
ATF_TC_BODY(null__w__a__test, tc)
{
runtest(_PATH_DEVNULL, "w", NULL, "a", true);
}
ATF_TC_WITHOUT_HEAD(null__r_append__a__test);
ATF_TC_BODY(null__r_append__a__test, tc)
{
runtest(_PATH_DEVNULL, "r+", NULL, "a", true);
}
ATF_TC_WITHOUT_HEAD(null__r__r_append__test);
ATF_TC_BODY(null__r__r_append__test, tc)
{
runtest(_PATH_DEVNULL, "r", NULL, "r+", false);
}
ATF_TC_WITHOUT_HEAD(null__w__r_append__test);
ATF_TC_BODY(null__w__r_append__test, tc)
{
runtest(_PATH_DEVNULL, "w", NULL, "r+", false);
}
ATF_TC_WITHOUT_HEAD(null__r_append__r_append__test);
ATF_TC_BODY(null__r_append__r_append__test, tc)
{
runtest(_PATH_DEVNULL, "r+", NULL, "r+", true);
}
ATF_TC_WITHOUT_HEAD(null__r__w_append__test);
ATF_TC_BODY(null__r__w_append__test, tc)
{
runtest(_PATH_DEVNULL, "r", NULL, "w+", false);
}
ATF_TC_WITHOUT_HEAD(null__w__w_append__test);
ATF_TC_BODY(null__w__w_append__test, tc)
{
runtest(_PATH_DEVNULL, "w", NULL, "w+", false);
}
ATF_TC_WITHOUT_HEAD(null__r_append__w_append__test);
ATF_TC_BODY(null__r_append__w_append__test, tc)
{
runtest(_PATH_DEVNULL, "r+", NULL, "w+", true);
}
ATF_TC_WITHOUT_HEAD(sh__r__r__test);
ATF_TC_BODY(sh__r__r__test, tc)
{
runtest("/bin/sh", "r", NULL, "r", true);
}
ATF_TC_WITHOUT_HEAD(sh__sh__r__r__test);
ATF_TC_BODY(sh__sh__r__r__test, tc)
{
runtest("/bin/sh", "r", "/bin/sh", "r", true);
}
ATF_TC_WITHOUT_HEAD(sh__null__r__r__test);
ATF_TC_BODY(sh__null__r__r__test, tc)
{
runtest("/bin/sh", "r", _PATH_DEVNULL, "r", true);
}
ATF_TC_WITHOUT_HEAD(sh__null__r__w__test);
ATF_TC_BODY(sh__null__r__w__test, tc)
{
runtest("/bin/sh", "r", _PATH_DEVNULL, "w", true);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, null__r__r__test);
ATF_TP_ADD_TC(tp, null__w__r__test);
ATF_TP_ADD_TC(tp, null__r_append__r__test);
ATF_TP_ADD_TC(tp, null__r__w__test);
ATF_TP_ADD_TC(tp, null__w__w__test);
ATF_TP_ADD_TC(tp, null__r_append__w__test);
ATF_TP_ADD_TC(tp, null__r__a__test);
ATF_TP_ADD_TC(tp, null__w__a__test);
ATF_TP_ADD_TC(tp, null__r_append__a__test);
ATF_TP_ADD_TC(tp, null__r__r_append__test);
ATF_TP_ADD_TC(tp, null__w__r_append__test);
ATF_TP_ADD_TC(tp, null__r_append__r_append__test);
ATF_TP_ADD_TC(tp, null__r__w_append__test);
ATF_TP_ADD_TC(tp, null__w__w_append__test);
ATF_TP_ADD_TC(tp, null__r_append__w_append__test);
ATF_TP_ADD_TC(tp, sh__r__r__test);
ATF_TP_ADD_TC(tp, sh__sh__r__r__test);
ATF_TP_ADD_TC(tp, sh__null__r__r__test);
ATF_TP_ADD_TC(tp, sh__null__r__w__test);
return (atf_no_error());
}
/*
vim:ts=8:cin:sw=8
*/
diff --git a/lib/libc/tests/stdio/getdelim_test.c b/lib/libc/tests/stdio/getdelim_test.c
index 8cb1763d9e01..01a0ab0949fe 100644
--- a/lib/libc/tests/stdio/getdelim_test.c
+++ b/lib/libc/tests/stdio/getdelim_test.c
@@ -1,432 +1,431 @@
/*-
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* Copyright (c) 2021 Dell EMC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
#define CHUNK_MAX 10
/* The assertions depend on this string. */
char apothegm[] = "All work and no play\0 makes Jack a dull boy.\n";
/*
* This is a neurotic reader function designed to give getdelim() a
* hard time. It reads through the string `apothegm' and returns a
* random number of bytes up to the requested length.
*/
static int
_reader(void *cookie, char *buf, int len)
{
size_t *offp = cookie;
size_t r;
r = random() % CHUNK_MAX + 1;
if (len > r)
len = r;
if (len > sizeof(apothegm) - *offp)
len = sizeof(apothegm) - *offp;
memcpy(buf, apothegm + *offp, len);
*offp += len;
return (len);
}
static FILE *
mkfilebuf(void)
{
size_t *offp;
offp = malloc(sizeof(*offp)); /* XXX leak */
*offp = 0;
return (fropen(offp, _reader));
}
ATF_TC_WITHOUT_HEAD(getline_basic);
ATF_TC_BODY(getline_basic, tc)
{
FILE *fp;
char *line;
size_t linecap;
int i;
srandom(0);
/*
* Test multiple times with different buffer sizes
* and different _reader() return values.
*/
errno = 0;
for (i = 0; i < 8; i++) {
fp = mkfilebuf();
linecap = i;
line = malloc(i);
/* First line: the full apothegm */
ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
ATF_REQUIRE(linecap >= sizeof(apothegm));
/* Second line: the NUL terminator following the newline */
ATF_REQUIRE(getline(&line, &linecap, fp) == 1);
ATF_REQUIRE(line[0] == '\0' && line[1] == '\0');
/* Third line: EOF */
line[0] = 'X';
ATF_REQUIRE(getline(&line, &linecap, fp) == -1);
ATF_REQUIRE(line[0] == '\0');
free(line);
line = NULL;
ATF_REQUIRE(feof(fp));
ATF_REQUIRE(!ferror(fp));
fclose(fp);
}
ATF_REQUIRE(errno == 0);
}
ATF_TC_WITHOUT_HEAD(stream_error);
ATF_TC_BODY(stream_error, tc)
{
char *line;
size_t linecap;
/* Make sure read errors are handled properly. */
line = NULL;
linecap = 0;
errno = 0;
ATF_REQUIRE(getline(&line, &linecap, stdout) == -1);
ATF_REQUIRE(errno == EBADF);
errno = 0;
ATF_REQUIRE(getdelim(&line, &linecap, 'X', stdout) == -1);
ATF_REQUIRE(errno == EBADF);
ATF_REQUIRE(ferror(stdout));
}
ATF_TC_WITHOUT_HEAD(invalid_params);
ATF_TC_BODY(invalid_params, tc)
{
FILE *fp;
char *line;
size_t linecap;
/* Make sure NULL linep or linecapp pointers are handled. */
fp = mkfilebuf();
ATF_REQUIRE(getline(NULL, &linecap, fp) == -1);
ATF_REQUIRE(errno == EINVAL);
ATF_REQUIRE(getline(&line, NULL, fp) == -1);
ATF_REQUIRE(errno == EINVAL);
ATF_REQUIRE(ferror(fp));
fclose(fp);
}
ATF_TC_WITHOUT_HEAD(eof);
ATF_TC_BODY(eof, tc)
{
FILE *fp;
char *line;
size_t linecap;
/* Make sure getline() allocates memory as needed if fp is at EOF. */
errno = 0;
fp = mkfilebuf();
while (!feof(fp)) /* advance to EOF; can't fseek this stream */
getc(fp);
line = NULL;
linecap = 0;
printf("getline\n");
ATF_REQUIRE(getline(&line, &linecap, fp) == -1);
ATF_REQUIRE(line[0] == '\0');
ATF_REQUIRE(linecap > 0);
ATF_REQUIRE(errno == 0);
printf("feof\n");
ATF_REQUIRE(feof(fp));
ATF_REQUIRE(!ferror(fp));
fclose(fp);
}
ATF_TC_WITHOUT_HEAD(nul);
ATF_TC_BODY(nul, tc)
{
FILE *fp;
char *line;
size_t linecap, n;
errno = 0;
line = NULL;
linecap = 0;
/* Make sure a NUL delimiter works. */
fp = mkfilebuf();
n = strlen(apothegm);
printf("getdelim\n");
ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1);
ATF_REQUIRE(strcmp(line, apothegm) == 0);
ATF_REQUIRE(line[n + 1] == '\0');
ATF_REQUIRE(linecap > n + 1);
n = strlen(apothegm + n + 1);
printf("getdelim 2\n");
ATF_REQUIRE(getdelim(&line, &linecap, '\0', fp) == n + 1);
ATF_REQUIRE(line[n + 1] == '\0');
ATF_REQUIRE(linecap > n + 1);
ATF_REQUIRE(errno == 0);
ATF_REQUIRE(!ferror(fp));
fclose(fp);
}
ATF_TC_WITHOUT_HEAD(empty_NULL_buffer);
ATF_TC_BODY(empty_NULL_buffer, tc)
{
FILE *fp;
char *line;
size_t linecap;
/* Make sure NULL *linep and zero *linecapp are handled. */
fp = mkfilebuf();
line = NULL;
linecap = 42;
ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
fp = mkfilebuf();
free(line);
line = malloc(100);
linecap = 0;
ATF_REQUIRE(getline(&line, &linecap, fp) == sizeof(apothegm) - 1);
ATF_REQUIRE(memcmp(line, apothegm, sizeof(apothegm)) == 0);
free(line);
ATF_REQUIRE(!ferror(fp));
fclose(fp);
}
static void
_ipc_read(int fd, char wait_c)
{
char c;
ssize_t len;
c = 0;
while (c != wait_c) {
len = read(fd, &c, 1);
ATF_CHECK_MSG(len != 0,
"EOF on IPC pipe while waiting. Did other side fail?");
ATF_CHECK_MSG(len == 1 || errno == EINTR,
"read %zu bytes errno %d\n", len, errno);
if (len != 1 || errno != EINTR)
break;
}
}
static void
_ipc_write(int fd, char c)
{
while ((write(fd, &c, 1) != 1))
ATF_REQUIRE(errno == EINTR);
}
static void
ipc_wait(int ipcfd[2])
{
_ipc_read(ipcfd[0], '+');
/* Send ACK. */
_ipc_write(ipcfd[1], '-');
}
static void
ipc_wakeup(int ipcfd[2])
{
_ipc_write(ipcfd[1], '+');
/* Wait for ACK. */
_ipc_read(ipcfd[0], '-');
}
static void
_nonblock_eagain(int buf_mode)
{
FILE *fp;
const char delim = '!';
const char *strs[] = {
"first line partial!",
"second line is sent in full!",
"third line is sent partially!",
"last line is sent in full!",
};
char *line;
size_t linecap, strslen[nitems(strs)];
ssize_t linelen;
int fd_fifo, flags, i, ipcfd[2], pipedes[2], pipedes2[2], status;
pid_t pid;
line = NULL;
linecap = 0;
for (i = 0; i < nitems(strslen); i++)
strslen[i] = strlen(strs[i]);
ATF_REQUIRE(pipe2(pipedes, O_CLOEXEC) == 0);
ATF_REQUIRE(pipe2(pipedes2, O_CLOEXEC) == 0);
(void)unlink("fifo");
ATF_REQUIRE(mkfifo("fifo", 0666) == 0);
ATF_REQUIRE((pid = fork()) >= 0);
if (pid == 0) {
close(pipedes[0]);
ipcfd[1] = pipedes[1];
ipcfd[0] = pipedes2[0];
close(pipedes2[1]);
ATF_REQUIRE((fd_fifo = open("fifo", O_WRONLY)) != -1);
/* Partial write. */
ATF_REQUIRE(write(fd_fifo, strs[0], strslen[0] - 3) ==
strslen[0] - 3);
ipc_wakeup(ipcfd);
ipc_wait(ipcfd);
/* Finish off the first line. */
ATF_REQUIRE(write(fd_fifo,
&(strs[0][strslen[0] - 3]), 3) == 3);
/* And include the second full line and a partial 3rd line. */
ATF_REQUIRE(write(fd_fifo, strs[1], strslen[1]) == strslen[1]);
ATF_REQUIRE(write(fd_fifo, strs[2], strslen[2] - 3) ==
strslen[2] - 3);
ipc_wakeup(ipcfd);
ipc_wait(ipcfd);
/* Finish the partial write and partially send the last. */
ATF_REQUIRE(write(fd_fifo,
&(strs[2][strslen[2] - 3]), 3) == 3);
ATF_REQUIRE(write(fd_fifo, strs[3], strslen[3] - 3) ==
strslen[3] - 3);
ipc_wakeup(ipcfd);
ipc_wait(ipcfd);
/* Finish the write */
ATF_REQUIRE(write(fd_fifo,
&(strs[3][strslen[3] - 3]), 3) == 3);
ipc_wakeup(ipcfd);
_exit(0);
}
ipcfd[0] = pipedes[0];
close(pipedes[1]);
close(pipedes2[0]);
ipcfd[1] = pipedes2[1];
ATF_REQUIRE((fp = fopen("fifo", "r")) != NULL);
setvbuf(fp, (char *)NULL, buf_mode, 0);
ATF_REQUIRE((flags = fcntl(fileno(fp), F_GETFL, 0)) != -1);
ATF_REQUIRE(fcntl(fileno(fp), F_SETFL, flags | O_NONBLOCK) >= 0);
/* Wait until the writer completes its partial write. */
ipc_wait(ipcfd);
ATF_REQUIRE_ERRNO(EAGAIN,
(linelen = getdelim(&line, &linecap, delim, fp)) == -1);
ATF_REQUIRE_STREQ("", line);
ATF_REQUIRE(ferror(fp));
ATF_REQUIRE(!feof(fp));
clearerr(fp);
ipc_wakeup(ipcfd);
ipc_wait(ipcfd);
/*
* Should now have the finished first line, a full second line,
* and a partial third line.
*/
ATF_CHECK(getdelim(&line, &linecap, delim, fp) == strslen[0]);
ATF_REQUIRE_STREQ(strs[0], line);
ATF_REQUIRE(getdelim(&line, &linecap, delim, fp) == strslen[1]);
ATF_REQUIRE_STREQ(strs[1], line);
ATF_REQUIRE_ERRNO(EAGAIN,
(linelen = getdelim(&line, &linecap, delim, fp)) == -1);
ATF_REQUIRE_STREQ("", line);
ATF_REQUIRE(ferror(fp));
ATF_REQUIRE(!feof(fp));
clearerr(fp);
ipc_wakeup(ipcfd);
/* Wait for the partial write to be completed and another to be done. */
ipc_wait(ipcfd);
ATF_REQUIRE((linelen = getdelim(&line, &linecap, delim, fp)) != -1);
ATF_REQUIRE(!ferror(fp));
ATF_REQUIRE(!feof(fp));
ATF_REQUIRE_STREQ(strs[2], line);
ATF_REQUIRE(linelen == strslen[2]);
ATF_REQUIRE_ERRNO(EAGAIN,
(linelen = getdelim(&line, &linecap, delim, fp)) == -1);
ATF_REQUIRE_STREQ("", line);
ATF_REQUIRE(ferror(fp));
ATF_REQUIRE(!feof(fp));
clearerr(fp);
ipc_wakeup(ipcfd);
ipc_wait(ipcfd);
ATF_REQUIRE((linelen = getdelim(&line, &linecap, delim, fp)) != -1);
ATF_REQUIRE(!ferror(fp));
ATF_REQUIRE(!feof(fp));
ATF_REQUIRE_STREQ(strs[3], line);
ATF_REQUIRE(linelen == strslen[3]);
ATF_REQUIRE(waitpid(pid, &status, WEXITED) != -1);
ATF_REQUIRE(WIFEXITED(status));
ATF_REQUIRE(WEXITSTATUS(status) == 0);
}
ATF_TC_WITHOUT_HEAD(nonblock_eagain_buffered);
ATF_TC_BODY(nonblock_eagain_buffered, tc)
{
_nonblock_eagain(_IOFBF);
}
ATF_TC_WITHOUT_HEAD(nonblock_eagain_unbuffered);
ATF_TC_BODY(nonblock_eagain_unbuffered, tc)
{
_nonblock_eagain(_IONBF);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, getline_basic);
ATF_TP_ADD_TC(tp, stream_error);
ATF_TP_ADD_TC(tp, eof);
ATF_TP_ADD_TC(tp, invalid_params);
ATF_TP_ADD_TC(tp, nul);
ATF_TP_ADD_TC(tp, empty_NULL_buffer);
ATF_TP_ADD_TC(tp, nonblock_eagain_unbuffered);
ATF_TP_ADD_TC(tp, nonblock_eagain_buffered);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/gets_s_test.c b/lib/libc/tests/stdio/gets_s_test.c
index c6eda57c03ea..4e1a59006b60 100644
--- a/lib/libc/tests/stdio/gets_s_test.c
+++ b/lib/libc/tests/stdio/gets_s_test.c
@@ -1,143 +1,142 @@
/*-
* Copyright (c) 2017 Cyril S. E. Schubert
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
#include <atf-c.h>
static errno_t error_code;
static const char * message;
void
h(const char * msg, void * ptr __unused, errno_t error)
{
error_code = error;
message = msg;
}
/* null ptr */
ATF_TC_WITHOUT_HEAD(null_ptr);
ATF_TC_BODY(null_ptr, tc)
{
ATF_CHECK_MSG(gets_s(NULL, 1) == NULL,
"gets_s() failed to handle NULL pointer");
}
/* normal */
ATF_TC_WITHOUT_HEAD(normal);
ATF_TC_BODY(normal, tc)
{
pid_t kidpid;
int fd[2];
int nfd;
// close(STDIN_FILENO);
// close(STDOUT_FILENO);
pipe(fd);
if ((kidpid = fork()) == 0) {
char b[10];
close(fd[1]);
nfd = dup2(fd[0], 0);
close(fd[0]);
stdin = fdopen(nfd, "r");
ATF_CHECK_MSG(gets_s(b, sizeof(b)) == 0, "gets_s() normal failed");
fclose(stdin);
} else {
int stat;
close(fd[0]);
stdout = fdopen(fd[1], "w");
puts("a sting");
fclose(stdout);
(void) waitpid(kidpid, &stat, WEXITED);
}
}
/* n > rmax */
ATF_TC_WITHOUT_HEAD(n_gt_rmax);
ATF_TC_BODY(n_gt_rmax, tc)
{
char b;
ATF_CHECK_MSG(gets_s(&b, RSIZE_MAX + 1) == NULL,
"gets_s() n > RSIZE_MAX");
}
/* n == 0 */
ATF_TC_WITHOUT_HEAD(n_eq_zero);
ATF_TC_BODY(n_eq_zero, tc)
{
char b;
ATF_CHECK_MSG(gets_s(&b, 0) == NULL, "gets_s() n is zero");
}
/* n > rmax, handler */
ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler);
ATF_TC_BODY(n_gt_rmax_handler, tc)
{
char b;
error_code = 0;
message = NULL;
set_constraint_handler_s(h);
ATF_CHECK_MSG(gets_s(&b, RSIZE_MAX + 1) == NULL, "gets_s() n > RSIZE_MAX");
ATF_CHECK_MSG(error_code > 0, "gets_s() error code is %d", error_code);
ATF_CHECK_MSG(strcmp(message, "gets_s : n > RSIZE_MAX") == 0, "gets_s(): incorrect error message");
}
/* n == 0, handler */
ATF_TC_WITHOUT_HEAD(n_eq_zero_handler);
ATF_TC_BODY(n_eq_zero_handler, tc)
{
char b;
error_code = 0;
message = NULL;
set_constraint_handler_s(h);
ATF_CHECK(gets_s(&b, 0) == NULL);
ATF_CHECK_MSG(error_code > 0, "gets_s() error code is %d", error_code);
ATF_CHECK_MSG(strcmp(message, "gets_s : n == 0") == 0, "gets_s(): incorrect error message");
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, null_ptr);
ATF_TP_ADD_TC(tp, normal);
ATF_TP_ADD_TC(tp, n_gt_rmax);
ATF_TP_ADD_TC(tp, n_eq_zero);
ATF_TP_ADD_TC(tp, n_gt_rmax_handler);
ATF_TP_ADD_TC(tp, n_eq_zero_handler);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/mkostemp_test.c b/lib/libc/tests/stdio/mkostemp_test.c
index 1e3f6dc03768..b31335fed43f 100644
--- a/lib/libc/tests/stdio/mkostemp_test.c
+++ b/lib/libc/tests/stdio/mkostemp_test.c
@@ -1,183 +1,182 @@
/*-
* Copyright (c) 2013 Jilles Tjoelker
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for mkostemp().
*/
-#include <sys/cdefs.h>
#include <sys/stat.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
static const char template[] = "mkostemp.XXXXXXXX";
static int testnum;
#define MISCFLAGS (O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC)
static void
test_one(int oflags)
{
char tmpf[sizeof(template)];
struct stat st1, st2;
int fd;
memcpy(tmpf, template, sizeof(tmpf));
fd = mkostemp(tmpf, oflags);
if (fd < 0) {
printf("not ok %d - oflags=%#x "
"mkostemp() reported failure: %s\n",
testnum++, oflags, strerror(errno));
return;
}
if (memcmp(tmpf, template, sizeof(tmpf) - 8 - 1) != 0) {
printf("not ok %d - oflags=%#x "
"returned pathname does not match template: %s\n",
testnum++, oflags, tmpf);
return;
}
do {
if (fcntl(fd, F_GETFD) !=
(oflags & O_CLOEXEC ? FD_CLOEXEC : 0)) {
printf("not ok %d - oflags=%#x "
"close-on-exec flag incorrect\n",
testnum++, oflags);
break;
}
if ((fcntl(fd, F_GETFL) & MISCFLAGS) != (oflags & MISCFLAGS)) {
printf("not ok %d - oflags=%#x "
"open flags incorrect\n",
testnum++, oflags);
break;
}
if (stat(tmpf, &st1) == -1) {
printf("not ok %d - oflags=%#x "
"cannot stat returned pathname %s: %s\n",
testnum++, oflags, tmpf, strerror(errno));
break;
}
if (fstat(fd, &st2) == -1) {
printf("not ok %d - oflags=%#x "
"cannot fstat returned fd %d: %s\n",
testnum++, oflags, fd, strerror(errno));
break;
}
if (!S_ISREG(st1.st_mode) || (st1.st_mode & 0777) != 0600 ||
st1.st_nlink != 1 || st1.st_size != 0) {
printf("not ok %d - oflags=%#x "
"named file attributes incorrect\n",
testnum++, oflags);
break;
}
if (!S_ISREG(st2.st_mode) || (st2.st_mode & 0777) != 0600 ||
st2.st_nlink != 1 || st2.st_size != 0) {
printf("not ok %d - oflags=%#x "
"opened file attributes incorrect\n",
testnum++, oflags);
break;
}
if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
printf("not ok %d - oflags=%#x "
"named and opened file do not match\n",
testnum++, oflags);
break;
}
(void)unlink(tmpf);
if (fstat(fd, &st2) == -1)
printf("not ok %d - oflags=%#x "
"cannot fstat returned fd %d again: %s\n",
testnum++, oflags, fd, strerror(errno));
else if (st2.st_nlink != 0)
printf("not ok %d - oflags=%#x "
"st_nlink is not 0 after unlink\n",
testnum++, oflags);
else
printf("ok %d - oflags=%#x\n", testnum++, oflags);
(void)close(fd);
return;
} while (0);
(void)close(fd);
(void)unlink(tmpf);
}
ATF_TC_WITHOUT_HEAD(zero);
ATF_TC_BODY(zero, tc)
{
test_one(0);
}
ATF_TC_WITHOUT_HEAD(O_CLOEXEC);
ATF_TC_BODY(O_CLOEXEC, tc)
{
test_one(O_CLOEXEC);
}
ATF_TC_WITHOUT_HEAD(O_APPEND);
ATF_TC_BODY(O_APPEND, tc)
{
test_one(O_APPEND);
}
ATF_TC_WITHOUT_HEAD(O_APPEND__O_CLOEXEC);
ATF_TC_BODY(O_APPEND__O_CLOEXEC, tc)
{
test_one(O_APPEND|O_CLOEXEC);
}
ATF_TC_WITHOUT_HEAD(bad_flags);
ATF_TC_BODY(bad_flags, tc)
{
char tmpf[sizeof(template)];
memcpy(tmpf, template, sizeof(tmpf));
ATF_REQUIRE_MSG(mkostemp(tmpf, O_CREAT) == -1,
"mkostemp(O_CREAT) succeeded unexpectedly");
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, zero);
ATF_TP_ADD_TC(tp, O_CLOEXEC);
ATF_TP_ADD_TC(tp, O_APPEND);
ATF_TP_ADD_TC(tp, O_APPEND__O_CLOEXEC);
ATF_TP_ADD_TC(tp, bad_flags);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/open_memstream2_test.c b/lib/libc/tests/stdio/open_memstream2_test.c
index 513192965c93..c9c6528832d8 100644
--- a/lib/libc/tests/stdio/open_memstream2_test.c
+++ b/lib/libc/tests/stdio/open_memstream2_test.c
@@ -1,199 +1,198 @@
/*-
* Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
static char *buf;
static size_t len;
static void
assert_stream(const char *contents)
{
if (strlen(contents) != len)
printf("bad length %zd for \"%s\"\n", len, contents);
else if (strncmp(buf, contents, strlen(contents)) != 0)
printf("bad buffer \"%s\" for \"%s\"\n", buf, contents);
}
ATF_TC_WITHOUT_HEAD(open_group_test);
ATF_TC_BODY(open_group_test, tc)
{
FILE *fp;
off_t eob;
fp = open_memstream(&buf, &len);
ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed");
fprintf(fp, "hello my world");
fflush(fp);
assert_stream("hello my world");
eob = ftello(fp);
rewind(fp);
fprintf(fp, "good-bye");
fseeko(fp, eob, SEEK_SET);
fclose(fp);
assert_stream("good-bye world");
free(buf);
}
ATF_TC_WITHOUT_HEAD(simple_tests);
ATF_TC_BODY(simple_tests, tc)
{
static const char zerobuf[] =
{ 'f', 'o', 'o', 0, 0, 0, 0, 'b', 'a', 'r', 0 };
char c;
FILE *fp;
fp = open_memstream(&buf, NULL);
ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
ATF_REQUIRE_MSG(errno == EINVAL,
"open_memstream didn't fail with EINVAL");
fp = open_memstream(NULL, &len);
ATF_REQUIRE_MSG(fp == NULL, "open_memstream did not fail");
ATF_REQUIRE_MSG(errno == EINVAL,
"open_memstream didn't fail with EINVAL");
fp = open_memstream(&buf, &len);
ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed; errno=%d", errno);
fflush(fp);
assert_stream("");
if (fwide(fp, 0) >= 0)
printf("stream is not byte-oriented\n");
fprintf(fp, "fo");
fflush(fp);
assert_stream("fo");
fputc('o', fp);
fflush(fp);
assert_stream("foo");
rewind(fp);
fflush(fp);
assert_stream("");
fseek(fp, 0, SEEK_END);
fflush(fp);
assert_stream("foo");
/*
* Test seeking out past the current end. Should zero-fill the
* intermediate area.
*/
fseek(fp, 4, SEEK_END);
fprintf(fp, "bar");
fflush(fp);
/*
* Can't use assert_stream() here since this should contain
* embedded null characters.
*/
if (len != 10)
printf("bad length %zd for zero-fill test\n", len);
else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
printf("bad buffer for zero-fill test\n");
fseek(fp, 3, SEEK_SET);
fprintf(fp, " in ");
fflush(fp);
assert_stream("foo in ");
fseek(fp, 0, SEEK_END);
fflush(fp);
assert_stream("foo in bar");
rewind(fp);
if (fread(&c, sizeof(c), 1, fp) != 0)
printf("fread did not fail\n");
else if (!ferror(fp))
printf("error indicator not set after fread\n");
else
clearerr(fp);
fseek(fp, 4, SEEK_SET);
fprintf(fp, "bar baz");
fclose(fp);
assert_stream("foo bar baz");
free(buf);
}
ATF_TC_WITHOUT_HEAD(seek_tests);
ATF_TC_BODY(seek_tests, tc)
{
FILE *fp;
fp = open_memstream(&buf, &len);
ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed: %d", errno);
#define SEEK_FAIL(offset, whence, error) do { \
errno = 0; \
ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) != 0, \
"fseeko(%s, %s) did not fail, set pos to %jd", \
__STRING(offset), __STRING(whence), \
(intmax_t)ftello(fp)); \
ATF_REQUIRE_MSG(errno == (error), \
"fseeko(%s, %s) failed with %d rather than %s", \
__STRING(offset), __STRING(whence), errno, \
__STRING(error)); \
} while (0)
#define SEEK_OK(offset, whence, result) do { \
ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) == 0, \
"fseeko(%s, %s) failed: %s", \
__STRING(offset), __STRING(whence), strerror(errno)); \
ATF_REQUIRE_MSG(ftello(fp) == (result), \
"fseeko(%s, %s) seeked to %jd rather than %s", \
__STRING(offset), __STRING(whence), \
(intmax_t)ftello(fp), __STRING(result)); \
} while (0)
SEEK_FAIL(-1, SEEK_SET, EINVAL);
SEEK_FAIL(-1, SEEK_CUR, EINVAL);
SEEK_FAIL(-1, SEEK_END, EINVAL);
fprintf(fp, "foo");
SEEK_OK(-1, SEEK_CUR, 2);
SEEK_OK(0, SEEK_SET, 0);
SEEK_OK(-1, SEEK_END, 2);
SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
fclose(fp);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, open_group_test);
ATF_TP_ADD_TC(tp, simple_tests);
ATF_TP_ADD_TC(tp, seek_tests);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/open_wmemstream_test.c b/lib/libc/tests/stdio/open_wmemstream_test.c
index cbe7e4776737..7ab882a4740a 100644
--- a/lib/libc/tests/stdio/open_wmemstream_test.c
+++ b/lib/libc/tests/stdio/open_wmemstream_test.c
@@ -1,199 +1,198 @@
/*-
* Copyright (c) 2013 Hudson River Trading LLC
* Written by: John H. Baldwin <jhb@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
static wchar_t *buf;
static size_t len;
static void
assert_stream(const wchar_t *contents)
{
if (wcslen(contents) != len)
printf("bad length %zd for \"%ls\"\n", len, contents);
else if (wcsncmp(buf, contents, wcslen(contents)) != 0)
printf("bad buffer \"%ls\" for \"%ls\"\n", buf, contents);
}
ATF_TC_WITHOUT_HEAD(open_group_test);
ATF_TC_BODY(open_group_test, tc)
{
FILE *fp;
off_t eob;
fp = open_wmemstream(&buf, &len);
ATF_REQUIRE_MSG(fp != NULL, "open_wmemstream failed");
fwprintf(fp, L"hello my world");
fflush(fp);
assert_stream(L"hello my world");
eob = ftello(fp);
rewind(fp);
fwprintf(fp, L"good-bye");
fseeko(fp, eob, SEEK_SET);
fclose(fp);
assert_stream(L"good-bye world");
free(buf);
}
ATF_TC_WITHOUT_HEAD(simple_tests);
ATF_TC_BODY(simple_tests, tc)
{
static const wchar_t zerobuf[] =
{ L'f', L'o', L'o', 0, 0, 0, 0, L'b', L'a', L'r', 0 };
wchar_t c;
FILE *fp;
fp = open_wmemstream(&buf, NULL);
ATF_REQUIRE_MSG(fp == NULL, "open_wmemstream did not fail");
ATF_REQUIRE_MSG(errno == EINVAL,
"open_wmemstream didn't fail with EINVAL");
fp = open_wmemstream(NULL, &len);
ATF_REQUIRE_MSG(fp == NULL, "open_wmemstream did not fail");
ATF_REQUIRE_MSG(errno == EINVAL,
"open_wmemstream didn't fail with EINVAL");
fp = open_wmemstream(&buf, &len);
ATF_REQUIRE_MSG(fp != NULL, "open_memstream failed; errno=%d", errno);
fflush(fp);
assert_stream(L"");
if (fwide(fp, 0) <= 0)
printf("stream is not wide-oriented\n");
fwprintf(fp, L"fo");
fflush(fp);
assert_stream(L"fo");
fputwc(L'o', fp);
fflush(fp);
assert_stream(L"foo");
rewind(fp);
fflush(fp);
assert_stream(L"");
fseek(fp, 0, SEEK_END);
fflush(fp);
assert_stream(L"foo");
/*
* Test seeking out past the current end. Should zero-fill the
* intermediate area.
*/
fseek(fp, 4, SEEK_END);
fwprintf(fp, L"bar");
fflush(fp);
/*
* Can't use assert_stream() here since this should contain
* embedded null characters.
*/
if (len != 10)
printf("bad length %zd for zero-fill test\n", len);
else if (memcmp(buf, zerobuf, sizeof(zerobuf)) != 0)
printf("bad buffer for zero-fill test\n");
fseek(fp, 3, SEEK_SET);
fwprintf(fp, L" in ");
fflush(fp);
assert_stream(L"foo in ");
fseek(fp, 0, SEEK_END);
fflush(fp);
assert_stream(L"foo in bar");
rewind(fp);
if (fread(&c, sizeof(c), 1, fp) != 0)
printf("fread did not fail\n");
else if (!ferror(fp))
printf("error indicator not set after fread\n");
else
clearerr(fp);
fseek(fp, 4, SEEK_SET);
fwprintf(fp, L"bar baz");
fclose(fp);
assert_stream(L"foo bar baz");
free(buf);
}
ATF_TC_WITHOUT_HEAD(seek_tests);
ATF_TC_BODY(seek_tests, tc)
{
FILE *fp;
fp = open_wmemstream(&buf, &len);
ATF_REQUIRE_MSG(fp != NULL, "open_wmemstream failed; errno=%d", errno);
#define SEEK_FAIL(offset, whence, error) do { \
errno = 0; \
ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) != 0, \
"fseeko(%s, %s) did not fail, set pos to %jd", \
__STRING(offset), __STRING(whence), \
(intmax_t)ftello(fp)); \
ATF_REQUIRE_MSG(errno == (error), \
"fseeko(%s, %s) failed with %d rather than %s", \
__STRING(offset), __STRING(whence), errno, \
__STRING(error)); \
} while (0)
#define SEEK_OK(offset, whence, result) do { \
ATF_REQUIRE_MSG(fseeko(fp, (offset), (whence)) == 0, \
"fseeko(%s, %s) failed: %s", \
__STRING(offset), __STRING(whence), strerror(errno)); \
ATF_REQUIRE_MSG(ftello(fp) == (result), \
"fseeko(%s, %s) seeked to %jd rather than %s", \
__STRING(offset), __STRING(whence), \
(intmax_t)ftello(fp), __STRING(result)); \
} while (0)
SEEK_FAIL(-1, SEEK_SET, EINVAL);
SEEK_FAIL(-1, SEEK_CUR, EINVAL);
SEEK_FAIL(-1, SEEK_END, EINVAL);
fwprintf(fp, L"foo");
SEEK_OK(-1, SEEK_CUR, 2);
SEEK_OK(0, SEEK_SET, 0);
SEEK_OK(-1, SEEK_END, 2);
SEEK_OK(OFF_MAX - 1, SEEK_SET, OFF_MAX - 1);
SEEK_FAIL(2, SEEK_CUR, EOVERFLOW);
fclose(fp);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, open_group_test);
ATF_TP_ADD_TC(tp, simple_tests);
ATF_TP_ADD_TC(tp, seek_tests);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/perror_test.c b/lib/libc/tests/stdio/perror_test.c
index e6d2c0c130a6..f3cb646d094e 100644
--- a/lib/libc/tests/stdio/perror_test.c
+++ b/lib/libc/tests/stdio/perror_test.c
@@ -1,105 +1,104 @@
/*-
* Copyright (c) 2002 Tim J. Robbins
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test program for perror() as specified by IEEE Std. 1003.1-2001 and
* ISO/IEC 9899:1999.
*/
-#include <sys/cdefs.h>
#include <err.h>
#include <errno.h>
#include <limits.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
static char tmpfil[PATH_MAX];
ATF_TC_WITHOUT_HEAD(perror_test);
ATF_TC_BODY(perror_test, tc)
{
char lbuf[512];
int i;
char *s;
strcpy(tmpfil, "perror.XXXXXXXX");
ATF_REQUIRE(mkstemp(tmpfil) >= 0);
/* Reopen stderr on a file descriptor other than 2. */
fclose(stderr);
for (i = 0; i < 3; i++)
dup(0);
ATF_REQUIRE(freopen(tmpfil, "r+", stderr) != NULL);
/*
* Test that perror() doesn't call strerror() (4.4BSD bug),
* the two ways of omitting a program name, and the formatting when
* a program name is specified.
*/
s = strerror(ENOENT);
ATF_REQUIRE_MSG(strcmp(s, "No such file or directory") == 0,
"message obtained was: %s", s);
errno = EPERM;
perror(NULL);
perror("");
perror("perror_test");
ATF_REQUIRE_MSG(strcmp(s, "No such file or directory") == 0,
"message obtained was: %s", s);
/*
* Read it back to check...
*/
rewind(stderr);
s = fgets(lbuf, sizeof(lbuf), stderr);
ATF_REQUIRE(s != NULL);
ATF_REQUIRE_MSG(strcmp(s, "Operation not permitted\n") == 0,
"message obtained was: %s", s);
s = fgets(lbuf, sizeof(lbuf), stderr);
ATF_REQUIRE(s != NULL);
ATF_REQUIRE_MSG(strcmp(s, "Operation not permitted\n") == 0,
"message obtained was: %s", s);
s = fgets(lbuf, sizeof(lbuf), stderr);
ATF_REQUIRE(s != NULL);
ATF_REQUIRE_MSG(
strcmp(s, "perror_test: Operation not permitted\n") == 0,
"message obtained was: %s", s);
s = fgets(lbuf, sizeof(lbuf), stderr);
ATF_REQUIRE(s == NULL);
fclose(stderr);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, perror_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/print_positional_test.c b/lib/libc/tests/stdio/print_positional_test.c
index ba5a7b13135c..f896a30882f4 100644
--- a/lib/libc/tests/stdio/print_positional_test.c
+++ b/lib/libc/tests/stdio/print_positional_test.c
@@ -1,155 +1,154 @@
/* $OpenBSD: sprintf_test.c,v 1.3 2004/09/16 20:22:26 otto Exp $ */
/*
* Copyright (c) 2003 Theo de Raadt
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
const char correct[] =
"|xx 01 02 03 04\n"
"|xx 05 06 07 08\n"
"|xx 09 10 11 12\n"
"|xx 13 14 15 16\n"
"|xx 17 18 19 20\n"
"|xx 21 22 23 24\n"
"|xx 25 26 27 28\n"
"|xx 29 30 31 32\n"
"|xx 33 34 35 36\n"
"|xx 37 38 39 40\n"
"|xx 41 42 43 44\n"
"|xx 45 -1 1 -1 1\n";
const char correct2[] =
"b bs BSD";
static char buf[1024];
static wchar_t wbuf1[1024], wbuf2[1024];
static const char *temp;
ATF_TC_WITHOUT_HEAD(positional_normal);
ATF_TC_BODY(positional_normal, tc)
{
/* Test positional arguments */
snprintf(buf, sizeof buf,
"|xx %1$s %2$s %3$s %4$s\n"
"|xx %5$s %6$s %7$s %8$s\n"
"|xx %9$s %10$s %11$s %12$s\n"
"|xx %13$s %14$s %15$s %16$s\n"
"|xx %17$s %18$s %19$s %20$s\n"
"|xx %21$s %22$s %23$s %24$s\n"
"|xx %25$s %26$s %27$s %28$s\n"
"|xx %29$s %30$s %31$s %32$s\n"
"|xx %33$s %34$s %35$s %36$s\n"
"|xx %37$s %38$s %39$s %40$s\n"
"|xx %41$s %42$s %43$s %44$s\n"
"|xx %45$d %46$ld %47$lld %48$d %49$lld\n",
"01", "02", "03", "04", "05", "06",
"07", "08", "09", "10", "11", "12",
"13", "14", "15", "16", "17", "18",
"19", "20", "21", "22", "23", "24",
"25", "26", "27", "28", "29", "30",
"31", "32", "33", "34", "35", "36",
"37", "38", "39", "40", "41", "42",
"43", "44", 45, -1L, 1LL, -1, 1LL
);
ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
"buffers didn't match");
}
ATF_TC_WITHOUT_HEAD(positional_wide);
ATF_TC_BODY(positional_wide, tc)
{
swprintf(wbuf1, nitems(wbuf1),
L"|xx %1$s %2$s %3$s %4$s\n"
"|xx %5$s %6$s %7$s %8$s\n"
"|xx %9$s %10$s %11$s %12$s\n"
"|xx %13$s %14$s %15$s %16$s\n"
"|xx %17$s %18$s %19$s %20$s\n"
"|xx %21$s %22$s %23$s %24$s\n"
"|xx %25$s %26$s %27$s %28$s\n"
"|xx %29$s %30$s %31$s %32$s\n"
"|xx %33$s %34$s %35$s %36$s\n"
"|xx %37$s %38$s %39$s %40$s\n"
"|xx %41$s %42$s %43$s %44$s\n"
"|xx %45$d %46$ld %47$lld %48$d %49$lld\n",
"01", "02", "03", "04", "05", "06",
"07", "08", "09", "10", "11", "12",
"13", "14", "15", "16", "17", "18",
"19", "20", "21", "22", "23", "24",
"25", "26", "27", "28", "29", "30",
"31", "32", "33", "34", "35", "36",
"37", "38", "39", "40", "41", "42",
"43", "44", 45, -1L, 1LL, -1, 1LL
);
temp = correct;
mbsrtowcs(wbuf2, &temp, nitems(wbuf2), NULL);
ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
"buffers didn't match");
}
ATF_TC_WITHOUT_HEAD(positional_precision);
ATF_TC_BODY(positional_precision, tc)
{
snprintf(buf, sizeof buf, "%2$.*4$s %2$.*3$s %1$s",
"BSD", "bsd", 2, 1);
ATF_REQUIRE_MSG(strcmp(buf, correct2) == 0,
"buffers didn't match");
}
ATF_TC_WITHOUT_HEAD(positional_precision_wide);
ATF_TC_BODY(positional_precision_wide, tc)
{
swprintf(wbuf1, sizeof buf, L"%2$.*4$s %2$.*3$s %1$s",
"BSD", "bsd", 2, 1);
temp = correct2;
mbsrtowcs(wbuf2, &temp, nitems(wbuf2), NULL);
ATF_REQUIRE_MSG(wcscmp(wbuf1, wbuf2) == 0,
"buffers didn't match");
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, positional_normal);
ATF_TP_ADD_TC(tp, positional_wide);
ATF_TP_ADD_TC(tp, positional_precision);
ATF_TP_ADD_TC(tp, positional_precision_wide);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/printbasic_test.c b/lib/libc/tests/stdio/printbasic_test.c
index 5f47979c0ff0..411dff518795 100644
--- a/lib/libc/tests/stdio/printbasic_test.c
+++ b/lib/libc/tests/stdio/printbasic_test.c
@@ -1,160 +1,159 @@
/*-
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Tests for basic and miscellaneous printf() formats.
*/
-#include <sys/cdefs.h>
#include <err.h>
#include <limits.h>
#include <locale.h>
#include <stdio.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
#define S_UINT64MAX "18446744073709551615"
#define S_UINT32MAX "4294967295"
#define S_INT64MIN "-9223372036854775808"
#define S_INT32MIN "-2147483648"
#define S_SIZEMAX (SIZE_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
#define S_ULONGMAX (ULONG_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
#define S_ULLONGMAX (ULLONG_MAX == UINT64_MAX ? S_UINT64MAX : S_UINT32MAX)
static void
smash_stack(void)
{
static uint32_t junk = 0xdeadbeef;
uint32_t buf[512];
int i;
for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++)
buf[i] = junk;
}
#define testfmt(result, fmt, ...) \
_testfmt((result), #__VA_ARGS__, fmt, __VA_ARGS__)
static void
_testfmt(const char *result, const char *argstr, const char *fmt,...)
{
#define BUF 100
wchar_t ws[BUF], wfmt[BUF], wresult[BUF];
char s[BUF];
va_list ap, ap2;
va_start(ap, fmt);
va_copy(ap2, ap);
smash_stack();
vsnprintf(s, sizeof(s), fmt, ap);
ATF_CHECK_MSG(strcmp(result, s) == 0,
"printf(\"%s\", %s) ==> [%s], expected [%s]",
fmt, argstr, s, result);
smash_stack();
mbstowcs(ws, s, BUF - 1);
mbstowcs(wfmt, fmt, BUF - 1);
mbstowcs(wresult, result, BUF - 1);
vswprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, ap2);
ATF_CHECK_MSG(wcscmp(wresult, ws) == 0,
"wprintf(\"%ls\", %s) ==> [%ls], expected [%ls]",
wfmt, argstr, ws, wresult);
va_end(ap);
va_end(ap2);
}
ATF_TC_WITHOUT_HEAD(int_within_limits);
ATF_TC_BODY(int_within_limits, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
/* The test requires these to be true. */
ATF_REQUIRE(UINTMAX_MAX == UINT64_MAX);
ATF_REQUIRE(UINT_MAX == UINT32_MAX);
ATF_REQUIRE(USHRT_MAX == 0xffff);
ATF_REQUIRE(UCHAR_MAX == 0xff);
/* Make sure we handle signed vs. unsigned args correctly. */
testfmt("-1", "%jd", (intmax_t)-1);
testfmt(S_UINT64MAX, "%ju", UINT64_MAX);
if (sizeof(ptrdiff_t) != sizeof(uintmax_t))
atf_tc_expect_fail("the %%t qualifier is broken on 32-bit "
"platforms where there's a mismatch between ptrdiff_t and "
"uintmax_t's type width; bug # 191674");
testfmt("-1", "%td", (ptrdiff_t)-1);
testfmt(S_SIZEMAX, "%tu", (size_t)-1);
testfmt("-1", "%zd", (ssize_t)-1);
testfmt(S_SIZEMAX, "%zu", (ssize_t)-1);
testfmt("-1", "%ld", (long)-1);
testfmt(S_ULONGMAX, "%lu", ULONG_MAX);
testfmt("-1", "%lld", (long long)-1);
testfmt(S_ULLONGMAX, "%llu", ULLONG_MAX);
testfmt("-1", "%d", -1);
testfmt(S_UINT32MAX, "%u", UINT32_MAX);
testfmt("-1", "%hd", -1);
testfmt("65535", "%hu", USHRT_MAX);
testfmt("-1", "%hhd", -1);
testfmt("255", "%hhu", UCHAR_MAX);
}
ATF_TC_WITHOUT_HEAD(int_limits);
ATF_TC_BODY(int_limits, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
/*
* Check that printing the largest negative number does not cause
* overflow when it is negated.
*/
testfmt(S_INT32MIN, "%d", INT_MIN);
testfmt(S_INT64MIN, "%jd", INTMAX_MIN);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, int_within_limits);
ATF_TP_ADD_TC(tp, int_limits);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/printfloat_test.c b/lib/libc/tests/stdio/printfloat_test.c
index aeb4ed43b772..031859124163 100644
--- a/lib/libc/tests/stdio/printfloat_test.c
+++ b/lib/libc/tests/stdio/printfloat_test.c
@@ -1,420 +1,419 @@
/*-
* Copyright (c) 2002-2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for printf() floating point formats.
*/
-#include <sys/cdefs.h>
#include <err.h>
#include <fenv.h>
#include <float.h>
#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
static void
smash_stack(void)
{
static uint32_t junk = 0xdeadbeef;
uint32_t buf[512];
size_t i;
for (i = 0; i < sizeof(buf) / sizeof(buf[0]); i++)
buf[i] = junk;
}
#define testfmt(result, fmt, ...) \
_testfmt((result), #__VA_ARGS__, fmt, __VA_ARGS__)
static void
_testfmt(const char *result, const char *argstr, const char *fmt,...)
{
#define BUF 100
wchar_t ws[BUF], wfmt[BUF], wresult[BUF];
char s[BUF];
va_list ap, ap2;
va_start(ap, fmt);
va_copy(ap2, ap);
smash_stack();
vsnprintf(s, sizeof(s), fmt, ap);
ATF_CHECK_MSG(strcmp(result, s) == 0,
"printf(\"%s\", %s) ==> [%s], expected [%s]",
fmt, argstr, s, result);
smash_stack();
mbstowcs(ws, s, BUF - 1);
mbstowcs(wfmt, fmt, BUF - 1);
mbstowcs(wresult, result, BUF - 1);
vswprintf(ws, sizeof(ws) / sizeof(ws[0]), wfmt, ap2);
ATF_CHECK_MSG(wcscmp(wresult, ws) == 0,
"wprintf(\"%ls\", %s) ==> [%ls], expected [%ls]",
wfmt, argstr, ws, wresult);
va_end(ap);
va_end(ap2);
}
ATF_TC_WITHOUT_HEAD(float_within_limits);
ATF_TC_BODY(float_within_limits, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
/* Basic tests of decimal output functionality. */
testfmt(" 1.000000E+00", "%13E", 1.0);
testfmt(" 1.000000", "%13f", 1.0);
testfmt(" 1", "%13G", 1.0);
testfmt(" 1.000000E+00", "%13LE", 1.0L);
testfmt(" 1.000000", "%13Lf", 1.0L);
testfmt(" 1", "%13LG", 1.0L);
testfmt("2.718282", "%.*f", -2, 2.7182818);
testfmt("1.234568e+06", "%e", 1234567.8);
testfmt("1234567.800000", "%f", 1234567.8);
testfmt("1.23457E+06", "%G", 1234567.8);
testfmt("1.234568e+06", "%Le", 1234567.8L);
testfmt("1234567.800000", "%Lf", 1234567.8L);
testfmt("1.23457E+06", "%LG", 1234567.8L);
#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
testfmt("123456789.864210", "%Lf", 123456789.8642097531L);
testfmt("-1.23457E+08", "%LG", -123456789.8642097531L);
testfmt("123456789.8642097531", "%.10Lf", 123456789.8642097531L);
testfmt(" 3.141592653589793238e-4000", "%L27.18Le",
3.14159265358979323846e-4000L);
#endif
}
ATF_TC_WITHOUT_HEAD(infinities_and_nans);
ATF_TC_BODY(infinities_and_nans, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("nan", "%e", NAN);
testfmt("NAN", "%F", NAN);
testfmt("nan", "%g", NAN);
testfmt("NAN", "%LE", (long double)NAN);
testfmt(" nan", "%05e", NAN);
testfmt("INF", "%E", HUGE_VAL);
testfmt("-inf", "%f", -HUGE_VAL);
testfmt("+inf", "%+g", HUGE_VAL);
testfmt(" inf", "%4.2Le", HUGE_VALL);
testfmt("-inf", "%Lf", -HUGE_VALL);
testfmt(" inf", "%05e", HUGE_VAL);
testfmt(" -inf", "%05e", -HUGE_VAL);
}
ATF_TC_WITHOUT_HEAD(padding);
ATF_TC_BODY(padding, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("0.000000e+00", "%e", 0.0);
testfmt("0.000000", "%F", (double)0.0);
testfmt("0", "%G", 0.0);
testfmt(" 0", "%3.0Lg", 0.0L);
testfmt(" 0", "%5.0f", 0.001);
}
ATF_TC_WITHOUT_HEAD(precision_specifiers);
ATF_TC_BODY(precision_specifiers, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("1.0123e+00", "%.4e", 1.0123456789);
testfmt("1.0123", "%.4f", 1.0123456789);
testfmt("1.012", "%.4g", 1.0123456789);
testfmt("1.2346e-02", "%.4e", 0.0123456789);
testfmt("0.0123", "%.4f", 0.0123456789);
testfmt("0.01235", "%.4g", 0.0123456789);
}
ATF_TC_WITHOUT_HEAD(thousands_separator_and_other_locale_tests);
ATF_TC_BODY(thousands_separator_and_other_locale_tests, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("12345678.0625", "%'.04f", 12345678.0625);
testfmt("0012345678.0625", "%'015.4F", 12345678.0625);
ATF_REQUIRE(setlocale(LC_NUMERIC, "hi_IN.ISCII-DEV")); /* grouping == 2;3 */
testfmt("1,23,45,678.0625", "%'.4f", 12345678.0625);
testfmt("01,23,45,678.0625", "%'017.4F", 12345678.0625);
testfmt(" 9,000", "%'6.0f", 9000.0);
testfmt("9,000.0", "%'.1f", 9000.0);
ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */
testfmt("3,1415", "%g", 3.1415);
/* thousands=. decimalpoint=, grouping=3;3 */
ATF_REQUIRE(setlocale(LC_NUMERIC, "el_GR.ISO8859-7")); /* decimalpoint==, */
testfmt("1.234,00", "%'.2f", 1234.00);
testfmt("123.456,789", "%'.3f", 123456.789);
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("12345678.062500", "%'f", 12345678.0625);
testfmt("9000.000000", "%'f", 9000.0);
}
ATF_TC_WITHOUT_HEAD(signed_conversions);
ATF_TC_BODY(signed_conversions, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("+2.500000e-01", "%+e", 0.25);
testfmt("+0.000000", "%+F", 0.0);
testfmt("-1", "%+g", -1.0);
testfmt("-1.000000e+00", "% e", -1.0);
testfmt("+1.000000", "% +f", 1.0);
testfmt(" 1", "% g", 1.0);
testfmt(" 0", "% g", 0.0);
}
ATF_TC_WITHOUT_HEAD(alternate_form);
ATF_TC_BODY(alternate_form, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("1.250e+00", "%#.3e", 1.25);
testfmt("123.000000", "%#f", 123.0);
testfmt(" 12345.", "%#7.5g", 12345.0);
testfmt(" 1.00000", "%#8g", 1.0);
testfmt("0.0", "%#.2g", 0.0);
}
ATF_TC_WITHOUT_HEAD(padding_and_decimal_point_placement);
ATF_TC_BODY(padding_and_decimal_point_placement, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
testfmt("03.2E+00", "%08.1E", 3.25);
testfmt("003.25", "%06.2F", 3.25);
testfmt("0003.25", "%07.4G", 3.25);
testfmt("3.14159e-05", "%g", 3.14159e-5);
testfmt("0.000314159", "%g", 3.14159e-4);
testfmt("3.14159e+06", "%g", 3.14159e6);
testfmt("314159", "%g", 3.14159e5);
testfmt("314159.", "%#g", 3.14159e5);
testfmt(" 9.000000e+03", "%13e", 9000.0);
testfmt(" 9000.000000", "%12f", 9000.0);
testfmt(" 9000", "%5g", 9000.0);
testfmt(" 900000.", "%#8g", 900000.0);
testfmt(" 9e+06", "%6g", 9000000.0);
testfmt(" 9.000000e-04", "%13e", 0.0009);
testfmt(" 0.000900", "%9f", 0.0009);
testfmt(" 0.0009", "%7g", 0.0009);
testfmt(" 9e-05", "%6g", 0.00009);
testfmt(" 9.00000e-05", "%#12g", 0.00009);
testfmt(" 9.e-05", "%#7.1g", 0.00009);
testfmt(" 0.0", "%4.1f", 0.0);
testfmt("90.0", "%4.1f", 90.0);
testfmt(" 100", "%4.0f", 100.0);
testfmt("9.0e+01", "%4.1e", 90.0);
testfmt("1e+02", "%4.0e", 100.0);
}
ATF_TC_WITHOUT_HEAD(decimal_rounding);
ATF_TC_BODY(decimal_rounding, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
fesetround(FE_DOWNWARD);
testfmt("4.437", "%.3f", 4.4375);
testfmt("-4.438", "%.3f", -4.4375);
testfmt("4.437", "%.3Lf", 4.4375L);
testfmt("-4.438", "%.3Lf", -4.4375L);
fesetround(FE_UPWARD);
testfmt("4.438", "%.3f", 4.4375);
testfmt("-4.437", "%.3f", -4.4375);
testfmt("4.438", "%.3Lf", 4.4375L);
testfmt("-4.437", "%.3Lf", -4.4375L);
fesetround(FE_TOWARDZERO);
testfmt("4.437", "%.3f", 4.4375);
testfmt("-4.437", "%.3f", -4.4375);
testfmt("4.437", "%.3Lf", 4.4375L);
testfmt("-4.437", "%.3Lf", -4.4375L);
fesetround(FE_TONEAREST);
testfmt("4.438", "%.3f", 4.4375);
testfmt("-4.438", "%.3f", -4.4375);
testfmt("4.438", "%.3Lf", 4.4375L);
testfmt("-4.438", "%.3Lf", -4.4375L);
}
ATF_TC_WITHOUT_HEAD(hexadecimal_floating_point);
ATF_TC_BODY(hexadecimal_floating_point, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
/*
* Hexadecimal floating point (%a, %A) tests. Some of these
* are only valid if the implementation converts to hex digits
* on nibble boundaries.
*/
testfmt("0x0p+0", "%a", 0x0.0p0);
testfmt("0X0.P+0", "%#LA", 0x0.0p0L);
testfmt("inf", "%La", (long double)INFINITY);
testfmt("+INF", "%+A", INFINITY);
testfmt("nan", "%La", (long double)NAN);
testfmt("NAN", "%A", NAN);
testfmt(" 0x1.23p+0", "%10a", 0x1.23p0);
testfmt(" 0x1.23p-500", "%12a", 0x1.23p-500);
testfmt(" 0x1.2p+40", "%10.1a", 0x1.23p40);
testfmt(" 0X1.230000000000000000000000P-4", "%32.24A", 0x1.23p-4);
testfmt("0x1p-1074", "%a", 0x1p-1074);
testfmt("0x1.2345p-1024", "%a", 0x1.2345p-1024);
#if (LDBL_MANT_DIG == 64)
testfmt("0x1.921fb54442d18468p+1", "%La", 0x3.243f6a8885a308dp0L);
testfmt("0x1p-16445", "%La", 0x1p-16445L);
testfmt("0x1.30ecap-16381", "%La", 0x9.8765p-16384L);
#elif (LDBL_MANT_DIG == 113)
testfmt("0x1.921fb54442d18469898cc51701b8p+1", "%La",
0x3.243f6a8885a308d313198a2e037p0L);
testfmt("0x1p-16494", "%La", 0x1p-16494L);
testfmt("0x1.2345p-16384", "%La", 0x1.2345p-16384L);
#else
testfmt("0x1.921fb54442d18p+1", "%La", 0x3.243f6a8885a31p0L);
testfmt("0x1p-1074", "%La", 0x1p-1074L);
testfmt("0x1.30ecap-1021", "%La", 0x9.8765p-1024L);
#endif
}
ATF_TC_WITHOUT_HEAD(hexadecimal_rounding);
ATF_TC_BODY(hexadecimal_rounding, tc)
{
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
fesetround(FE_TOWARDZERO);
testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0);
testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0);
testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0);
fesetround(FE_DOWNWARD);
testfmt("0X1.23456789ABCP+0", "%.11A", 0x1.23456789abcdep0);
testfmt("-0x1.23457p+0", "%.5a", -0x1.23456789abcdep0);
testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
testfmt("0x1.234567p+0", "%.6a", 0x1.23456789abcdep0);
testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0);
fesetround(FE_UPWARD);
testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0);
testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
testfmt("0x1.23457p+0", "%.5a", 0x1.23456789abcdep0);
testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0);
testfmt("-0x1.234566p+0", "%.6a", -0x1.23456689abcdep0);
fesetround(FE_TONEAREST);
testfmt("0x1.23456789abcdep+4", "%a", 0x1.23456789abcdep4);
testfmt("0X1.23456789ABDP+0", "%.11A", 0x1.23456789abcdep0);
testfmt("-0x1.23456p+0", "%.5a", -0x1.23456789abcdep0);
testfmt("0x1.23456p+0", "%.5a", 0x1.23456789abcdep0);
testfmt("0x1.234568p+0", "%.6a", 0x1.23456789abcdep0);
testfmt("-0x1.234567p+0", "%.6a", -0x1.23456689abcdep0);
testfmt("0x1.00p-1029", "%.2a", 0x1.fffp-1030);
testfmt("0x1.00p-1026", "%.2a", 0xf.fffp-1030);
testfmt("0x1.83p+0", "%.2a", 1.51);
}
ATF_TC_WITHOUT_HEAD(subnormal_double);
ATF_TC_BODY(subnormal_double, tc)
{
/* Regression test for https://bugs.freebsd.org/253847 */
double positive = __DBL_DENORM_MIN__;
testfmt("4.9406564584124654418e-324", "%20.20g", positive);
testfmt("4.9406564584124654418E-324", "%20.20G", positive);
testfmt("0x1p-1074", "%a", positive);
testfmt("0X1P-1074", "%A", positive);
double negative = -__DBL_DENORM_MIN__;
testfmt("-4.9406564584124654418e-324", "%20.20g", negative);
testfmt("-4.9406564584124654418E-324", "%20.20G", negative);
testfmt("-0x1p-1074", "%a", negative);
testfmt("-0X1P-1074", "%A", negative);
}
ATF_TC_WITHOUT_HEAD(subnormal_float);
ATF_TC_BODY(subnormal_float, tc)
{
float positive = __FLT_DENORM_MIN__;
testfmt("1.4012984643248170709e-45", "%20.20g", positive);
testfmt("1.4012984643248170709E-45", "%20.20G", positive);
testfmt("0x1p-149", "%a", positive);
testfmt("0X1P-149", "%A", positive);
float negative = -__FLT_DENORM_MIN__;
testfmt("-1.4012984643248170709e-45", "%20.20g", negative);
testfmt("-1.4012984643248170709E-45", "%20.20G", negative);
testfmt("-0x1p-149", "%a", negative);
testfmt("-0X1P-149", "%A", negative);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, float_within_limits);
ATF_TP_ADD_TC(tp, infinities_and_nans);
ATF_TP_ADD_TC(tp, padding);
ATF_TP_ADD_TC(tp, precision_specifiers);
ATF_TP_ADD_TC(tp, thousands_separator_and_other_locale_tests);
ATF_TP_ADD_TC(tp, signed_conversions);
ATF_TP_ADD_TC(tp, alternate_form);
ATF_TP_ADD_TC(tp, padding_and_decimal_point_placement);
ATF_TP_ADD_TC(tp, decimal_rounding);
ATF_TP_ADD_TC(tp, hexadecimal_floating_point);
ATF_TP_ADD_TC(tp, hexadecimal_rounding);
ATF_TP_ADD_TC(tp, subnormal_double);
ATF_TP_ADD_TC(tp, subnormal_float);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdio/scanfloat_test.c b/lib/libc/tests/stdio/scanfloat_test.c
index 473565b25747..a93238504dd1 100644
--- a/lib/libc/tests/stdio/scanfloat_test.c
+++ b/lib/libc/tests/stdio/scanfloat_test.c
@@ -1,314 +1,313 @@
/*-
* Copyright (C) 2003, 2005 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for scanf() floating point formats.
*/
-#include <sys/cdefs.h>
#include <fenv.h>
#include <float.h>
#include <locale.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
#define eq(type, a, b) _eq(type##_EPSILON, (a), (b))
static int
_eq(long double epsilon, long double a, long double b)
{
long double delta;
delta = fabsl(a - b);
return (delta <= epsilon);
}
ATF_TC_WITHOUT_HEAD(normalized_numbers);
ATF_TC_BODY(normalized_numbers, tc)
{
char buf[128];
long double ld = 0.0;
double d = 0.0;
float f = 0.0;
buf[0] = '\0';
ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
sscanf("3.141592", "%e", &f);
ATF_REQUIRE(eq(FLT, f, 3.141592));
sscanf("3.141592653589793", "%lf", &d);
ATF_REQUIRE(eq(DBL, d, 3.141592653589793));
sscanf("1.234568e+06", "%E", &f);
ATF_REQUIRE(eq(FLT, f, 1.234568e+06));
sscanf("-1.234568e6", "%lF", &d);
ATF_REQUIRE(eq(DBL, d, -1.234568e6));
sscanf("+1.234568e-52", "%LG", &ld);
ATF_REQUIRE(eq(LDBL, ld, 1.234568e-52L));
sscanf("0.1", "%la", &d);
ATF_REQUIRE(eq(DBL, d, 0.1));
sscanf("00.2", "%lA", &d);
ATF_REQUIRE(eq(DBL, d, 0.2));
sscanf("123456", "%5le%s", &d, buf);
ATF_REQUIRE(eq(DBL, d, 12345.));
ATF_REQUIRE(strcmp(buf, "6") == 0);
sscanf("1.0Q", "%*5le%s", buf);
ATF_REQUIRE(strcmp(buf, "Q") == 0);
sscanf("-1.23e", "%e%s", &f, buf);
ATF_REQUIRE(eq(FLT, f, -1.23));
ATF_REQUIRE(strcmp(buf, "e") == 0);
sscanf("1.25e+", "%le%s", &d, buf);
ATF_REQUIRE(eq(DBL, d, 1.25));
ATF_REQUIRE(strcmp(buf, "e+") == 0);
sscanf("1.23E4E5", "%le%s", &d, buf);
ATF_REQUIRE(eq(DBL, d, 1.23e4));
ATF_REQUIRE(strcmp(buf, "E5") == 0);
sscanf("12e6", "%le", &d);
ATF_REQUIRE(eq(DBL, d, 12e6));
sscanf("1.a", "%le%s", &d, buf);
ATF_REQUIRE(eq(DBL, d, 1.0));
ATF_REQUIRE(strcmp(buf, "a") == 0);
sscanf(".0p4", "%le%s", &d, buf);
ATF_REQUIRE(eq(DBL, d, 0.0));
ATF_REQUIRE(strcmp(buf, "p4") == 0);
d = 0.25;
ATF_REQUIRE(sscanf(".", "%le", &d) == 0);
ATF_REQUIRE(d == 0.25);
sscanf("0x08", "%le", &d);
ATF_REQUIRE(d == 0x8p0);
sscanf("0x90a.bcdefP+09a", "%le%s", &d, buf);
ATF_REQUIRE(d == 0x90a.bcdefp+09);
ATF_REQUIRE(strcmp(buf, "a") == 0);
#if (LDBL_MANT_DIG > DBL_MANT_DIG) && !defined(__i386__)
sscanf("3.14159265358979323846", "%Lg", &ld);
ATF_REQUIRE(eq(LDBL, ld, 3.14159265358979323846L));
sscanf(" 0X.0123456789abcdefffp-3g", "%Le%s", &ld, buf);
ATF_REQUIRE(ld == 0x0.0123456789abcdefffp-3L);
ATF_REQUIRE(strcmp(buf, "g") == 0);
#endif
sscanf("0xg", "%le%s", &d, buf);
ATF_REQUIRE(d == 0.0);
ATF_REQUIRE(strcmp(buf, "xg") == 0);
ATF_REQUIRE(setlocale(LC_NUMERIC, "ru_RU.ISO8859-5")); /* decimalpoint==, */
sscanf("1.23", "%le%s", &d, buf);
ATF_REQUIRE(d == 1.0);
ATF_REQUIRE(strcmp(buf, ".23") == 0);
sscanf("1,23", "%le", &d);
ATF_REQUIRE(d == 1.23);
ATF_REQUIRE(setlocale(LC_NUMERIC, ""));
}
ATF_TC_WITHOUT_HEAD(infinities_and_nans);
ATF_TC_BODY(infinities_and_nans, tc)
{
char buf[128];
long double ld = 0.0;
double d = 0.0;
float f = 0.0;
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
sscanf("-Inf", "%le", &d);
ATF_REQUIRE(d < 0.0 && isinf(d));
sscanf("iNfInItY and beyond", "%le%s", &d, buf);
ATF_REQUIRE(d > 0.0 && isinf(d));
ATF_REQUIRE(strcmp(buf, " and beyond"));
sscanf("NaN", "%le", &d);
ATF_REQUIRE(isnan(d));
sscanf("NAN(123Y", "%le%s", &d, buf);
ATF_REQUIRE(isnan(d));
ATF_REQUIRE(strcmp(buf, "(123Y") == 0);
sscanf("nan(f00f)plugh", "%le%s", &d, buf);
ATF_REQUIRE(isnan(d));
ATF_REQUIRE(strcmp(buf, "plugh") == 0);
sscanf("-nan", "%le", &d);
ATF_REQUIRE(isnan(d));
/* Only quiet NaNs should be returned. */
sscanf("NaN", "%e", &f);
sscanf("nan", "%le", &d);
sscanf("nan", "%Le", &ld);
feclearexcept(FE_ALL_EXCEPT);
ATF_REQUIRE(f != f);
ATF_REQUIRE(d != d);
ATF_REQUIRE(ld != ld);
ATF_REQUIRE(fetestexcept(FE_INVALID) == 0);
sscanf("nan(1234)", "%e", &f);
sscanf("nan(1234)", "%le", &d);
sscanf("nan(1234)", "%Le", &ld);
feclearexcept(FE_ALL_EXCEPT);
ATF_REQUIRE(f != f);
ATF_REQUIRE(d != d);
ATF_REQUIRE(ld != ld);
/* POSIX says we should only generate quiet NaNs. */
ATF_REQUIRE(fetestexcept(FE_INVALID) == 0);
}
ATF_TC_WITHOUT_HEAD(rounding_tests);
ATF_TC_BODY(rounding_tests, tc)
{
long double ld = 0.0;
double d = 0.0;
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
fesetround(FE_DOWNWARD);
sscanf("1.999999999999999999999999999999999", "%le", &d);
ATF_REQUIRE(d < 2.0);
sscanf("0x1.ffffffffffffffp0", "%le", &d);
ATF_REQUIRE(d < 2.0);
sscanf("1.999999999999999999999999999999999", "%Le", &ld);
ATF_REQUIRE(ld < 2.0);
sscanf("1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
sscanf("-1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == -0x1.0ea3f4af0dc5ap0);
sscanf("1.0571892669084010", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
sscanf("0x1.23p-5000", "%le", &d);
ATF_REQUIRE(d == 0.0);
sscanf("0x1.2345678p-1050", "%le", &d);
ATF_REQUIRE(d == 0x1.234567p-1050);
fesetround(FE_UPWARD);
sscanf("1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
sscanf("-1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
sscanf("1.0571892669084010", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
sscanf("0x1.23p-5000", "%le", &d);
ATF_REQUIRE(d == 0x1p-1074);
sscanf("0x1.2345678p-1050", "%le", &d);
ATF_REQUIRE(d == 0x1.234568p-1050);
fesetround(FE_TOWARDZERO);
sscanf("1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
sscanf("-1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
sscanf("1.0571892669084010", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5ap0);
sscanf("0x1.23p-5000", "%le", &d);
ATF_REQUIRE(d == 0.0);
sscanf("0x1.2345678p-1050", "%le", &d);
ATF_REQUIRE(d == 0x1.234567p-1050);
fesetround(FE_TONEAREST);
/* 1.0571892669084007 is slightly closer to 0x1.0ea3f4af0dc59p0 */
sscanf("1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc59p0);
sscanf("-1.0571892669084007", "%le", &d);
ATF_REQUIRE(d == -0x1.0ea3f4af0dc59p0);
sscanf("1.0571892669084010", "%le", &d);
ATF_REQUIRE(d == 0x1.0ea3f4af0dc5bp0);
/* strtod() should round small numbers to 0. */
sscanf("0x1.23p-5000", "%le", &d);
ATF_REQUIRE(d == 0.0);
/* Extra digits in a denormal shouldn't break anything. */
sscanf("0x1.2345678p-1050", "%le", &d);
ATF_REQUIRE(d == 0x1.234568p-1050);
}
ATF_TC_WITHOUT_HEAD(strtod);
ATF_TC_BODY(strtod, tc)
{
char *endp;
ATF_REQUIRE(setlocale(LC_NUMERIC, "C"));
ATF_REQUIRE(strtod("0xy", &endp) == 0);
ATF_REQUIRE(strcmp("xy", endp) == 0);
/* This used to cause an infinite loop and round the wrong way. */
fesetround(FE_DOWNWARD);
ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
fesetround(FE_UPWARD);
ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
fesetround(FE_TOWARDZERO);
ATF_REQUIRE(strtof("3.5e38", &endp) == FLT_MAX);
ATF_REQUIRE(strtod("2e308", &endp) == DBL_MAX);
fesetround(FE_TONEAREST);
ATF_REQUIRE(strtof("3.5e38", &endp) == INFINITY);
ATF_REQUIRE(strtod("2e308", &endp) == INFINITY);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, normalized_numbers);
ATF_TP_ADD_TC(tp, infinities_and_nans);
ATF_TP_ADD_TC(tp, rounding_tests);
ATF_TP_ADD_TC(tp, strtod);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/clearenv_test.c b/lib/libc/tests/stdlib/clearenv_test.c
index 369d64b2e3b4..003535a00060 100644
--- a/lib/libc/tests/stdlib/clearenv_test.c
+++ b/lib/libc/tests/stdlib/clearenv_test.c
@@ -1,174 +1,173 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2021 Mariusz Zaborski <oshogbo@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for clearenv(3) routine.
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#include <stdio.h>
#include <stdlib.h>
#define TEST_VARIABLE "TEST_VAR"
#define TEST_SYSTEM_VARIABLE "PWD"
extern char **environ;
void
create_multiple_variables(int num)
{
char name[64];
char value[64];
int i;
for (i = 0; i < num; i++) {
snprintf(name, sizeof(name), "%s_%d", TEST_VARIABLE, i);
snprintf(value, sizeof(value), "%d", i);
ATF_CHECK(getenv(name) == NULL);
ATF_CHECK(setenv(name, value, 0) != -1);
ATF_CHECK_STREQ(getenv(name), value);
}
}
void
check_if_nulled_variables(int num)
{
char name[64];
int i;
for (i = 0; i < num; i++) {
snprintf(name, sizeof(name), "%s_%d", TEST_VARIABLE, i);
ATF_CHECK(getenv(name) == NULL);
}
}
ATF_TC_WITHOUT_HEAD(clearenv__single_var_test);
ATF_TC_BODY(clearenv__single_var_test, tc)
{
ATF_CHECK(setenv(TEST_VARIABLE, "true", 0) != -1);
ATF_CHECK_STREQ(getenv(TEST_VARIABLE), "true");
ATF_CHECK(clearenv() == 0);
ATF_CHECK(getenv(TEST_VARIABLE) == NULL);
}
ATF_TC_WITHOUT_HEAD(clearenv__multiple_vars_test);
ATF_TC_BODY(clearenv__multiple_vars_test, tc)
{
create_multiple_variables(10);
ATF_CHECK(clearenv() == 0);
check_if_nulled_variables(10);
}
ATF_TC_WITHOUT_HEAD(clearenv__recreated_vars_test);
ATF_TC_BODY(clearenv__recreated_vars_test, tc)
{
create_multiple_variables(10);
ATF_CHECK(clearenv() == 0);
check_if_nulled_variables(10);
create_multiple_variables(10);
}
ATF_TC_WITHOUT_HEAD(clearenv__system_var_test);
ATF_TC_BODY(clearenv__system_var_test, tc)
{
ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) != NULL);
ATF_CHECK(clearenv() == 0);
ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) == NULL);
}
ATF_TC_WITHOUT_HEAD(clearenv__recreated_system_var_test);
ATF_TC_BODY(clearenv__recreated_system_var_test, tc)
{
ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) != NULL);
ATF_CHECK(clearenv() == 0);
ATF_CHECK(getenv(TEST_SYSTEM_VARIABLE) == NULL);
ATF_CHECK(setenv(TEST_SYSTEM_VARIABLE, "test", 0) != -1);
ATF_CHECK_STREQ(getenv(TEST_SYSTEM_VARIABLE), "test");
}
ATF_TC_WITHOUT_HEAD(clearenv__double_clear_vars);
ATF_TC_BODY(clearenv__double_clear_vars, tc)
{
create_multiple_variables(10);
ATF_CHECK(clearenv() == 0);
check_if_nulled_variables(10);
ATF_CHECK(clearenv() == 0);
check_if_nulled_variables(10);
create_multiple_variables(10);
}
ATF_TC_WITHOUT_HEAD(clearenv__environ_null);
ATF_TC_BODY(clearenv__environ_null, tc)
{
ATF_CHECK(clearenv() == 0);
ATF_CHECK(environ != NULL);
}
ATF_TC_WITHOUT_HEAD(clearenv__putenv_vars);
ATF_TC_BODY(clearenv__putenv_vars, tc)
{
char buf[64], ref[64];
snprintf(buf, sizeof(buf), "%s=1", TEST_VARIABLE);
strcpy(ref, buf);
ATF_CHECK(getenv(TEST_VARIABLE) == NULL);
ATF_CHECK(putenv(buf) != -1);
ATF_CHECK(strcmp(getenv(TEST_VARIABLE), "1") == 0);
ATF_CHECK(clearenv() == 0);
ATF_CHECK(getenv(TEST_VARIABLE) == NULL);
ATF_CHECK(strcmp(buf, ref) == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, clearenv__single_var_test);
ATF_TP_ADD_TC(tp, clearenv__multiple_vars_test);
ATF_TP_ADD_TC(tp, clearenv__recreated_vars_test);
ATF_TP_ADD_TC(tp, clearenv__system_var_test);
ATF_TP_ADD_TC(tp, clearenv__recreated_system_var_test);
ATF_TP_ADD_TC(tp, clearenv__double_clear_vars);
ATF_TP_ADD_TC(tp, clearenv__environ_null);
ATF_TP_ADD_TC(tp, clearenv__putenv_vars);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc b/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc
index 8f9c6348e0b0..0b3b9497a6bd 100644
--- a/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc
+++ b/lib/libc/tests/stdlib/cxa_thread_atexit_nothr_test.cc
@@ -1,100 +1,99 @@
/*-
* Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
* Copyright (c) 2016 The FreeBSD Foundation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <dlfcn.h>
#include <atf-c++.hpp>
#include <cstdio>
#include <cstdlib>
static FILE *output = NULL;
struct Foo {
Foo() { ATF_REQUIRE(fprintf(output, "Created\n") > 0); }
~Foo() { ATF_REQUIRE(fprintf(output, "Destroyed\n") > 0); }
void use() { ATF_REQUIRE(fprintf(output, "Used\n") > 0); }
};
static thread_local Foo f;
/*
* This test must not be linked to libpthread.
*/
ATF_TEST_CASE_WITHOUT_HEAD(cxx__nothr);
ATF_TEST_CASE_BODY(cxx__nothr)
{
void *libthr_handle;
/* Avoid coredump during f construction. */
output = stderr;
libthr_handle = dlopen("libthr.so.3", RTLD_LAZY | RTLD_GLOBAL |
RTLD_NOLOAD);
ATF_REQUIRE(libthr_handle == NULL);
}
static void
check_local_main(void)
{
static const char out_log[] = "Created\nUsed\nDestroyed\n";
fflush(output);
ATF_REQUIRE(atf::utils::compare_file("test_main.txt", out_log));
}
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_main);
ATF_TEST_CASE_BODY(cxx__thread_local_main)
{
ATF_REQUIRE((output = fopen("test_main.txt", "w")) != NULL);
f.use();
atexit(check_local_main);
}
extern "C" int __cxa_thread_atexit(void (*)(void *), void *, void *);
static void
again(void *arg)
{
__cxa_thread_atexit(again, arg, &output);
}
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_inf_dtors);
ATF_TEST_CASE_BODY(cxx__thread_inf_dtors)
{
again(NULL);
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, cxx__nothr);
ATF_ADD_TEST_CASE(tcs, cxx__thread_local_main);
ATF_ADD_TEST_CASE(tcs, cxx__thread_inf_dtors);
}
diff --git a/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc b/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc
index d2e1369c91dd..628a70b510d1 100644
--- a/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc
+++ b/lib/libc/tests/stdlib/cxa_thread_atexit_test.cc
@@ -1,178 +1,177 @@
/*-
* Copyright (c) 2016 Mahdi Mokhtari <mokhi64@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <dlfcn.h>
#include <atf-c++.hpp>
#include <cstdio>
#include <cstdlib>
#include <thread>
static FILE *output = NULL;
struct Foo {
Foo() { ATF_REQUIRE(fprintf(output, "Created\n") > 0); }
~Foo() { ATF_REQUIRE(fprintf(output, "Destroyed\n") > 0); }
void use() { ATF_REQUIRE(fprintf(output, "Used\n") > 0); }
};
struct Bar {
Bar() {}
~Bar() {
thread_local static Foo foo;
ATF_REQUIRE(fprintf(output, "DIED\n") > 0);
}
void use() {}
};
extern "C" int __cxa_thread_atexit(void (*)(void *), void *, void *);
static void
again(void *arg)
{
__cxa_thread_atexit(again, arg, &output);
}
struct Baz {
Baz() {}
~Baz() {
again(NULL);
}
void use() {}
};
static thread_local Foo f;
static thread_local Foo g;
static thread_local Bar h;
static thread_local Baz e;
/*
* This test must be linked to libpthread.
*/
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thr);
ATF_TEST_CASE_BODY(cxx__thr)
{
void *libthr_handle;
/* Avoid coredump during f construction. */
output = stderr;
libthr_handle = dlopen("libthr.so.3", RTLD_LAZY | RTLD_GLOBAL |
RTLD_NOLOAD);
ATF_REQUIRE(libthr_handle != NULL);
dlclose(libthr_handle);
}
/*
* In this test f.use() will test cxa_thread_atexit() in non-threaded mode.
* After f.use() main will be threaded and we'll have one additional thread
* with its own TLS data.
*/
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_before);
ATF_TEST_CASE_BODY(cxx__thread_local_before)
{
static const char out_log[] = "Created\nCreated\nUsed\nCreated\n"
"Created\nUsed\nCreated\nDIED\nDestroyed\nDestroyed\nDestroyed\n";
ATF_REQUIRE((output = fopen("test_before.txt", "w")) != NULL);
f.use();
std::thread t([]() { f.use(); });
t.join();
fflush(output);
ATF_REQUIRE(atf::utils::compare_file("test_before.txt", out_log));
}
/*
* In this test, f.use() will test __cxa_thread_atexit()
* in threaded mode (but still in main-threaed).
*/
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_after);
ATF_TEST_CASE_BODY(cxx__thread_local_after)
{
static const char out_log[] = "Created\nCreated\nUsed\nCreated\n"
"DIED\nDestroyed\nDestroyed\nDestroyed\nCreated\nCreated\nUsed\n";
ATF_REQUIRE((output = fopen("test_after.txt", "w")) != NULL);
std::thread t([]() { g.use(); });
t.join();
sleep(1);
g.use();
fflush(output);
ATF_REQUIRE(atf::utils::compare_file("test_after.txt", out_log));
}
/*
* In this test, we register a new dtor while dtors are being run
* in __cxa_thread_atexit().
*/
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_local_add_while_calling_dtors);
ATF_TEST_CASE_BODY(cxx__thread_local_add_while_calling_dtors)
{
static const char out_log[] = "Created\nCreated\nCreated\nDIED\n"
"Destroyed\nDestroyed\nDestroyed\n";
ATF_REQUIRE((output = fopen("test_add_meanwhile.txt", "w")) != NULL);
std::thread t([]() { h.use(); });
t.join();
sleep(1);
fflush(output);
ATF_REQUIRE(atf::utils::compare_file("test_add_meanwhile.txt", out_log));
}
ATF_TEST_CASE_WITHOUT_HEAD(cxx__thread_inf_dtors);
ATF_TEST_CASE_BODY(cxx__thread_inf_dtors)
{
/*
* Only added to make isolated run of this test not
* coredumping. Construction of Foo objects require filled
* output.
*/
output = stderr;
std::thread t([]() { e.use(); });
t.join();
}
ATF_INIT_TEST_CASES(tcs)
{
ATF_ADD_TEST_CASE(tcs, cxx__thr);
ATF_ADD_TEST_CASE(tcs, cxx__thread_local_before);
ATF_ADD_TEST_CASE(tcs, cxx__thread_local_after);
ATF_ADD_TEST_CASE(tcs, cxx__thread_local_add_while_calling_dtors);
ATF_ADD_TEST_CASE(tcs, cxx__thread_inf_dtors);
}
diff --git a/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c b/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c
index 21c9e19d4468..eccffcd0bd49 100644
--- a/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c
+++ b/lib/libc/tests/stdlib/dynthr_mod/dynthr_mod.c
@@ -1,72 +1,71 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2019 Andrew Gierth
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Though this file is initially distributed under the 2-clause BSD license,
* the author grants permission for its redistribution under alternative
* licenses as set forth at <https://rhodiumtoad.github.io/RELICENSE.txt>.
* This paragraph and the RELICENSE.txt file are not part of the license and
* may be omitted in redistributions.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
void mod_main(int op);
static pthread_t thr;
static void *
mod_thread(void *ptr __unused)
{
char *volatile dummy;
dummy = malloc(500);
*dummy = 'a';
return (NULL);
}
void
mod_main(int op)
{
int rc;
switch (op) {
case 1:
rc = pthread_create(&thr, NULL, mod_thread, NULL);
if (rc != 0)
_exit(1);
break;
case 0:
pthread_join(thr, NULL);
break;
}
}
diff --git a/lib/libc/tests/stdlib/dynthr_test.c b/lib/libc/tests/stdlib/dynthr_test.c
index 7c22499c7567..5b0af718afc7 100644
--- a/lib/libc/tests/stdlib/dynthr_test.c
+++ b/lib/libc/tests/stdlib/dynthr_test.c
@@ -1,91 +1,90 @@
/*
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (C) 2019 Andrew Gierth
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* Though this file is initially distributed under the 2-clause BSD license,
* the author grants permission for its redistribution under alternative
* licenses as set forth at <https://rhodiumtoad.github.io/RELICENSE.txt>.
* This paragraph and the RELICENSE.txt file are not part of the license and
* may be omitted in redistributions.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <unistd.h>
#include <dlfcn.h>
#include <atf-c.h>
typedef void (modfunc_t)(int op);
/*
* Minimal test case for PR 235158; mutual dependencies between jemalloc and
* libthr causing issues in thread creation. Specifically to this case, libthr
* uses calloc to initialize pthread mutexes, and jemalloc uses pthread mutexes.
*
* Deferred initialization provided by jemalloc proved to be fragile, causing
* issues like in the referenced PR where thread creation in a shared object
* loaded via dlopen(3) would stall unless the calling application also linked
* against pthread.
*/
ATF_TC(maintc);
ATF_TC_HEAD(maintc, tc)
{
atf_tc_set_md_var(tc, "timeout", "3");
}
ATF_TC_BODY(maintc, tc)
{
char *libpath;
modfunc_t *func;
void *mod_handle;
const char *srcdir;
dlfunc_t rawfunc;
srcdir = atf_tc_get_config_var(tc, "srcdir");
if (asprintf(&libpath, "%s/dynthr_mod.so", srcdir) < 0)
atf_tc_fail("failed to construct path to libthr");
mod_handle = dlopen(libpath, RTLD_LOCAL);
free(libpath);
if (mod_handle == NULL)
atf_tc_fail("failed to open dynthr_mod.so: %s", dlerror());
rawfunc = dlfunc(mod_handle, "mod_main");
if (rawfunc == NULL)
atf_tc_fail("failed to resolve function mod_main");
func = (modfunc_t *)rawfunc;
func(1);
func(0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, maintc);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/heapsort_test.c b/lib/libc/tests/stdlib/heapsort_test.c
index 875326354e0f..b6747ff5d3aa 100644
--- a/lib/libc/tests/stdlib/heapsort_test.c
+++ b/lib/libc/tests/stdlib/heapsort_test.c
@@ -1,69 +1,68 @@
/*-
* Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for heapsort() routine.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "test-sort.h"
ATF_TC_WITHOUT_HEAD(heapsort_test);
ATF_TC_BODY(heapsort_test, tc)
{
int sresvector[IVEC_LEN];
int testvector[IVEC_LEN];
int i, j;
for (j = 2; j < IVEC_LEN; j++) {
/* Populate test vectors */
for (i = 0; i < j; i++)
testvector[i] = sresvector[i] = initvector[i];
/* Sort using heapsort(3) */
heapsort(testvector, j, sizeof(testvector[0]), sorthelp);
/* Sort using reference slow sorting routine */
ssort(sresvector, j);
/* Compare results */
for (i = 0; i < j; i++)
ATF_CHECK_MSG(testvector[i] == sresvector[i],
"item at index %d didn't match: %d != %d",
i, testvector[i], sresvector[i]);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, heapsort_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/mergesort_test.c b/lib/libc/tests/stdlib/mergesort_test.c
index e57def84e3ab..156d6bb7c2c3 100644
--- a/lib/libc/tests/stdlib/mergesort_test.c
+++ b/lib/libc/tests/stdlib/mergesort_test.c
@@ -1,69 +1,68 @@
/*-
* Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for mergesort() routine.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "test-sort.h"
ATF_TC_WITHOUT_HEAD(mergesort_test);
ATF_TC_BODY(mergesort_test, tc)
{
int sresvector[IVEC_LEN];
int testvector[IVEC_LEN];
int i, j;
for (j = 2; j < IVEC_LEN; j++) {
/* Populate test vectors */
for (i = 0; i < j; i++)
testvector[i] = sresvector[i] = initvector[i];
/* Sort using mergesort(3) */
mergesort(testvector, j, sizeof(testvector[0]), sorthelp);
/* Sort using reference slow sorting routine */
ssort(sresvector, j);
/* Compare results */
for (i = 0; i < j; i++)
ATF_CHECK_MSG(testvector[i] == sresvector[i],
"item at index %d didn't match: %d != %d",
i, testvector[i], sresvector[i]);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, mergesort_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/qsort_r_compat_test.c b/lib/libc/tests/stdlib/qsort_r_compat_test.c
index d2734c8678de..d7b06615292e 100644
--- a/lib/libc/tests/stdlib/qsort_r_compat_test.c
+++ b/lib/libc/tests/stdlib/qsort_r_compat_test.c
@@ -1,90 +1,89 @@
/*-
* Copyright (C) 2020 Edward Tomasz Napierala <trasz@FreeBSD.org>
* Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for historical qsort_r(3) routine.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include "test-sort.h"
#define THUNK 42
static int
sorthelp_r(void *thunk, const void *a, const void *b)
{
const int *oa, *ob;
ATF_REQUIRE_EQ(*(int *)thunk, THUNK);
oa = a;
ob = b;
/* Don't use "return *oa - *ob" since it's easy to cause overflow! */
if (*oa > *ob)
return (1);
if (*oa < *ob)
return (-1);
return (0);
}
ATF_TC_WITHOUT_HEAD(qsort_r_compat_test);
ATF_TC_BODY(qsort_r_compat_test, tc)
{
int testvector[IVEC_LEN];
int sresvector[IVEC_LEN];
int i, j;
int thunk = THUNK;
for (j = 2; j < IVEC_LEN; j++) {
/* Populate test vectors */
for (i = 0; i < j; i++)
testvector[i] = sresvector[i] = initvector[i];
/* Sort using qsort_r(3) */
qsort_r(testvector, j, sizeof(testvector[0]), &thunk,
sorthelp_r);
/* Sort using reference slow sorting routine */
ssort(sresvector, j);
/* Compare results */
for (i = 0; i < j; i++)
ATF_CHECK_MSG(testvector[i] == sresvector[i],
"item at index %d didn't match: %d != %d",
i, testvector[i], sresvector[i]);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, qsort_r_compat_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/qsort_r_test.c b/lib/libc/tests/stdlib/qsort_r_test.c
index 962a3792beb4..446d63279fbf 100644
--- a/lib/libc/tests/stdlib/qsort_r_test.c
+++ b/lib/libc/tests/stdlib/qsort_r_test.c
@@ -1,90 +1,89 @@
/*-
* Copyright (C) 2020 Edward Tomasz Napierala <trasz@FreeBSD.org>
* Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for qsort_r(3) routine.
*/
-#include <sys/cdefs.h>
#include <stdio.h>
#include <stdlib.h>
#include "test-sort.h"
#define THUNK 42
static int
sorthelp_r(const void *a, const void *b, void *thunk)
{
const int *oa, *ob;
ATF_REQUIRE_EQ(*(int *)thunk, THUNK);
oa = a;
ob = b;
/* Don't use "return *oa - *ob" since it's easy to cause overflow! */
if (*oa > *ob)
return (1);
if (*oa < *ob)
return (-1);
return (0);
}
ATF_TC_WITHOUT_HEAD(qsort_r_test);
ATF_TC_BODY(qsort_r_test, tc)
{
int testvector[IVEC_LEN];
int sresvector[IVEC_LEN];
int i, j;
int thunk = THUNK;
for (j = 2; j < IVEC_LEN; j++) {
/* Populate test vectors */
for (i = 0; i < j; i++)
testvector[i] = sresvector[i] = initvector[i];
/* Sort using qsort_r(3) */
qsort_r(testvector, j, sizeof(testvector[0]), sorthelp_r,
&thunk);
/* Sort using reference slow sorting routine */
ssort(sresvector, j);
/* Compare results */
for (i = 0; i < j; i++)
ATF_CHECK_MSG(testvector[i] == sresvector[i],
"item at index %d didn't match: %d != %d",
i, testvector[i], sresvector[i]);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, qsort_r_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/qsort_s_test.c b/lib/libc/tests/stdlib/qsort_s_test.c
index 9682d447edb7..c3210caf24e1 100644
--- a/lib/libc/tests/stdlib/qsort_s_test.c
+++ b/lib/libc/tests/stdlib/qsort_s_test.c
@@ -1,255 +1,254 @@
/*-
* Copyright (C) 2020 Edward Tomasz Napierala <trasz@FreeBSD.org>
* Copyright (c) 2017 Juniper Networks. All rights reserved.
* Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for qsort_s(3) routine.
*/
-#include <sys/cdefs.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#define THUNK 42
#include "test-sort.h"
static errno_t e;
static int
sorthelp_s(const void *a, const void *b, void *thunk)
{
const int *oa, *ob;
ATF_REQUIRE_EQ(*(int *)thunk, THUNK);
oa = a;
ob = b;
/* Don't use "return *oa - *ob" since it's easy to cause overflow! */
if (*oa > *ob)
return (1);
if (*oa < *ob)
return (-1);
return (0);
}
void
h(const char * restrict msg __unused, void * restrict ptr __unused, errno_t error)
{
e = error;
}
/* nmemb < 0 */
ATF_TC_WITHOUT_HEAD(qsort_s_nmemb_lt_zero);
ATF_TC_BODY(qsort_s_nmemb_lt_zero, tc)
{
int thunk = THUNK;
int b;
ATF_CHECK(qsort_s(&b, -1, sizeof(int), sorthelp_s, &thunk) != 0);
}
/* nmemb > rmax */
ATF_TC_WITHOUT_HEAD(qsort_s_nmemb_gt_rmax);
ATF_TC_BODY(qsort_s_nmemb_gt_rmax, tc)
{
int thunk = THUNK;
int b;
ATF_CHECK(qsort_s(&b, RSIZE_MAX + 1, sizeof(int), sorthelp_s, &thunk) != 0);
}
/* size < 0 */
ATF_TC_WITHOUT_HEAD(qsort_s_size_lt_zero);
ATF_TC_BODY(qsort_s_size_lt_zero, tc)
{
int thunk = THUNK;
int b;
ATF_CHECK(qsort_s(&b, 1, -1, sorthelp_s, &thunk) != 0);
}
/* size > rmax */
ATF_TC_WITHOUT_HEAD(qsort_s_size_gt_rmax);
ATF_TC_BODY(qsort_s_size_gt_rmax, tc)
{
int thunk = THUNK;
int b;
ATF_CHECK(qsort_s(&b, 1, RSIZE_MAX + 1, sorthelp_s, &thunk) != 0);
}
/* NULL compar */
ATF_TC_WITHOUT_HEAD(qsort_s_null_compar);
ATF_TC_BODY(qsort_s_null_compar, tc)
{
int thunk = THUNK;
int b;
ATF_CHECK(qsort_s(&b, 1, sizeof(int), NULL, &thunk) != 0);
}
/* nmemb < 0, handler */
ATF_TC_WITHOUT_HEAD(qsort_s_nmemb_lt_zero_h);
ATF_TC_BODY(qsort_s_nmemb_lt_zero_h, tc)
{
int thunk = THUNK;
int b[] = {81, 4, 7};
e = 0;
set_constraint_handler_s(h);
ATF_CHECK(qsort_s(&b, -1, sizeof(int), sorthelp_s, &thunk) != 0);
ATF_CHECK(e > 0);
ATF_CHECK_EQ(b[0], 81);
ATF_CHECK_EQ(b[1], 4);
ATF_CHECK_EQ(b[2], 7);
}
/* nmemb > rmax, handler */
ATF_TC_WITHOUT_HEAD(qsort_s_nmemb_gt_rmax_h);
ATF_TC_BODY(qsort_s_nmemb_gt_rmax_h, tc)
{
int thunk = THUNK;
int b[] = {81, 4, 7};
e = 0;
set_constraint_handler_s(h);
ATF_CHECK(qsort_s(&b, RSIZE_MAX + 1, sizeof(int), sorthelp_s, &thunk) != 0);
ATF_CHECK(e > 0);
ATF_CHECK_EQ(b[0], 81);
ATF_CHECK_EQ(b[1], 4);
ATF_CHECK_EQ(b[2], 7);
}
/* size < 0, handler */
ATF_TC_WITHOUT_HEAD(qsort_s_size_lt_zero_h);
ATF_TC_BODY(qsort_s_size_lt_zero_h, tc)
{
int thunk = THUNK;
int b[] = {81, 4, 7};
e = 0;
set_constraint_handler_s(h);
ATF_CHECK(qsort_s(&b, nitems(b), -1, sorthelp_s, &thunk) != 0);
ATF_CHECK(e > 0);
ATF_CHECK_EQ(b[0], 81);
ATF_CHECK_EQ(b[1], 4);
ATF_CHECK_EQ(b[2], 7);
}
/* size > rmax, handler */
ATF_TC_WITHOUT_HEAD(qsort_s_size_gt_rmax_h);
ATF_TC_BODY(qsort_s_size_gt_rmax_h, tc)
{
int thunk = THUNK;
int b[] = {81, 4, 7};
e = 0;
set_constraint_handler_s(h);
ATF_CHECK(qsort_s(&b, nitems(b), RSIZE_MAX + 1, sorthelp_s, &thunk) != 0);
ATF_CHECK(e > 0);
ATF_CHECK_EQ(b[0], 81);
ATF_CHECK_EQ(b[1], 4);
ATF_CHECK_EQ(b[2], 7);
}
/* NULL compar, handler */
ATF_TC_WITHOUT_HEAD(qsort_s_null_compar_h);
ATF_TC_BODY(qsort_s_null_compar_h, tc)
{
int thunk = THUNK;
int b[] = {81, 4, 7};
e = 0;
set_constraint_handler_s(h);
ATF_CHECK(qsort_s(&b, nitems(b), sizeof(int), NULL, &thunk) != 0);
ATF_CHECK(e > 0);
ATF_CHECK_EQ(b[0], 81);
ATF_CHECK_EQ(b[1], 4);
ATF_CHECK_EQ(b[2], 7);
}
ATF_TC_WITHOUT_HEAD(qsort_s_h);
ATF_TC_BODY(qsort_s_h, tc)
{
int thunk = THUNK;
int b[] = {81, 4, 7};
e = 0;
set_constraint_handler_s(h);
ATF_CHECK(qsort_s(&b, nitems(b), sizeof(int), sorthelp_s, &thunk) == 0);
ATF_CHECK(e == 0);
ATF_CHECK_EQ(b[0], 4);
ATF_CHECK_EQ(b[1], 7);
ATF_CHECK_EQ(b[2], 81);
}
ATF_TC_WITHOUT_HEAD(qsort_s_test);
ATF_TC_BODY(qsort_s_test, tc)
{
int testvector[IVEC_LEN];
int sresvector[IVEC_LEN];
int i, j;
int thunk = THUNK;
for (j = 2; j < IVEC_LEN; j++) {
/* Populate test vectors */
for (i = 0; i < j; i++)
testvector[i] = sresvector[i] = initvector[i];
/* Sort using qsort_s(3) */
qsort_s(testvector, j, sizeof(testvector[0]),
sorthelp_s, &thunk);
/* Sort using reference slow sorting routine */
ssort(sresvector, j);
/* Compare results */
for (i = 0; i < j; i++)
ATF_CHECK_MSG(testvector[i] == sresvector[i],
"item at index %d didn't match: %d != %d",
i, testvector[i], sresvector[i]);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, qsort_s_nmemb_lt_zero);
ATF_TP_ADD_TC(tp, qsort_s_nmemb_gt_rmax);
ATF_TP_ADD_TC(tp, qsort_s_size_lt_zero);
ATF_TP_ADD_TC(tp, qsort_s_size_gt_rmax);
ATF_TP_ADD_TC(tp, qsort_s_null_compar);
ATF_TP_ADD_TC(tp, qsort_s_nmemb_lt_zero_h);
ATF_TP_ADD_TC(tp, qsort_s_nmemb_gt_rmax_h);
ATF_TP_ADD_TC(tp, qsort_s_size_lt_zero_h);
ATF_TP_ADD_TC(tp, qsort_s_size_gt_rmax_h);
ATF_TP_ADD_TC(tp, qsort_s_null_compar_h);
ATF_TP_ADD_TC(tp, qsort_s_h);
ATF_TP_ADD_TC(tp, qsort_s_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/qsort_test.c b/lib/libc/tests/stdlib/qsort_test.c
index 1a0587a94ade..a6202e55fd62 100644
--- a/lib/libc/tests/stdlib/qsort_test.c
+++ b/lib/libc/tests/stdlib/qsort_test.c
@@ -1,69 +1,68 @@
/*-
* Copyright (C) 2004 Maxim Sobolev <sobomax@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Test for qsort() routine.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "test-sort.h"
ATF_TC_WITHOUT_HEAD(qsort_test);
ATF_TC_BODY(qsort_test, tc)
{
int testvector[IVEC_LEN];
int sresvector[IVEC_LEN];
int i, j;
for (j = 2; j < IVEC_LEN; j++) {
/* Populate test vectors */
for (i = 0; i < j; i++)
testvector[i] = sresvector[i] = initvector[i];
/* Sort using qsort(3) */
qsort(testvector, j, sizeof(testvector[0]), sorthelp);
/* Sort using reference slow sorting routine */
ssort(sresvector, j);
/* Compare results */
for (i = 0; i < j; i++)
ATF_CHECK_MSG(testvector[i] == sresvector[i],
"item at index %d didn't match: %d != %d",
i, testvector[i], sresvector[i]);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, qsort_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/set_constraint_handler_s_test.c b/lib/libc/tests/stdlib/set_constraint_handler_s_test.c
index b718b4fc11fd..87db1f71ed4d 100644
--- a/lib/libc/tests/stdlib/set_constraint_handler_s_test.c
+++ b/lib/libc/tests/stdlib/set_constraint_handler_s_test.c
@@ -1,61 +1,60 @@
/*-
* Copyright (c) 2017 Juniper Networks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdlib.h>
#include <atf-c.h>
/* null */
ATF_TC_WITHOUT_HEAD(null_handler);
ATF_TC_BODY(null_handler, tc)
{
assert(set_constraint_handler_s(abort_handler_s) == NULL);
}
/* abort handler */
ATF_TC_WITHOUT_HEAD(abort_handler);
ATF_TC_BODY(abort_handler, tc)
{
set_constraint_handler_s(abort_handler_s);
assert(set_constraint_handler_s(ignore_handler_s) == abort_handler_s);
}
/* ignore handler */
ATF_TC_WITHOUT_HEAD(ignore_handler);
ATF_TC_BODY(ignore_handler, tc)
{
set_constraint_handler_s(ignore_handler_s);
assert(set_constraint_handler_s(abort_handler_s) == ignore_handler_s);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, null_handler);
ATF_TP_ADD_TC(tp, abort_handler);
ATF_TP_ADD_TC(tp, ignore_handler);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/strfmon_test.c b/lib/libc/tests/stdlib/strfmon_test.c
index f092c071724a..86f6256dba0b 100644
--- a/lib/libc/tests/stdlib/strfmon_test.c
+++ b/lib/libc/tests/stdlib/strfmon_test.c
@@ -1,253 +1,252 @@
/*-
* Copyright (C) 2018 Conrad Meyer <cem@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <locale.h>
#include <monetary.h>
#include <stdio.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(strfmon_locale_thousands);
ATF_TC_BODY(strfmon_locale_thousands, tc)
{
char actual[40], expected[40];
struct lconv *lc;
const char *ts;
double n;
setlocale(LC_MONETARY, "sv_SE.UTF-8");
lc = localeconv();
ts = lc->mon_thousands_sep;
if (strlen(ts) == 0)
ts = lc->thousands_sep;
if (strlen(ts) < 2)
atf_tc_skip("multi-byte thousands-separator not found");
n = 1234.56;
strfmon(actual, sizeof(actual) - 1, "%i", n);
strcpy(expected, "1");
strlcat(expected, ts, sizeof(expected));
strlcat(expected, "234", sizeof(expected));
/* We're just testing the thousands separator, not all of strfmon. */
actual[strlen(expected)] = '\0';
ATF_CHECK_STREQ(expected, actual);
}
ATF_TC_WITHOUT_HEAD(strfmon_examples);
ATF_TC_BODY(strfmon_examples, tc)
{
const struct {
const char *format;
const char *expected;
} tests[] = {
{ "%n", "[$123.45] [-$123.45] [$3,456.78]" },
{ "%11n", "[ $123.45] [ -$123.45] [ $3,456.78]" },
{ "%#5n", "[ $ 123.45] [-$ 123.45] [ $ 3,456.78]" },
{ "%=*#5n", "[ $***123.45] [-$***123.45] [ $*3,456.78]" },
{ "%=0#5n", "[ $000123.45] [-$000123.45] [ $03,456.78]" },
{ "%^#5n", "[ $ 123.45] [-$ 123.45] [ $ 3456.78]" },
{ "%^#5.0n", "[ $ 123] [-$ 123] [ $ 3457]" },
{ "%^#5.4n", "[ $ 123.4500] [-$ 123.4500] [ $ 3456.7810]" },
{ "%(#5n", "[ $ 123.45 ] [($ 123.45)] [ $ 3,456.78 ]" },
{ "%!(#5n", "[ 123.45 ] [( 123.45)] [ 3,456.78 ]" },
{ "%-14#5.4n", "[ $ 123.4500 ] [-$ 123.4500 ] [ $ 3,456.7810 ]" },
{ "%14#5.4n", "[ $ 123.4500] [ -$ 123.4500] [ $ 3,456.7810]" },
};
size_t i;
char actual[100], format[50];
if (setlocale(LC_MONETARY, "en_US.UTF-8") == NULL)
atf_tc_skip("unable to setlocale()");
for (i = 0; i < nitems(tests); ++i) {
snprintf(format, sizeof(format), "[%s] [%s] [%s]",
tests[i].format, tests[i].format, tests[i].format);
strfmon(actual, sizeof(actual) - 1, format,
123.45, -123.45, 3456.781);
ATF_CHECK_STREQ_MSG(tests[i].expected, actual,
"[%s]", tests[i].format);
}
}
ATF_TC(strfmon_cs_precedes_0);
ATF_TC_HEAD(strfmon_cs_precedes_0, tc)
{
atf_tc_set_md_var(tc, "descr",
"sep_by_space x sign_posn when cs_precedes = 0");
}
ATF_TC_BODY(strfmon_cs_precedes_0, tc)
{
const struct {
const char *expected;
} tests[] = {
/* sep_by_space x sign_posn */
{ "[(123.00$)] [-123.00$] [123.00$-] [123.00-$] [123.00$-]" },
{ "[(123.00 $)] [-123.00 $] [123.00 $-] [123.00 -$] [123.00 $-]" },
{ "[(123.00$)] [- 123.00$] [123.00$ -] [123.00- $] [123.00$ -]" },
};
size_t i, j;
struct lconv *lc;
char actual[100], buf[100];
if (setlocale(LC_MONETARY, "en_US.UTF-8") == NULL)
atf_tc_skip("unable to setlocale()");
lc = localeconv();
lc->n_cs_precedes = 0;
for (i = 0; i < nitems(tests); ++i) {
actual[0] = '\0';
lc->n_sep_by_space = i;
for (j = 0; j < 5; ++j) {
lc->n_sign_posn = j;
strfmon(buf, sizeof(buf) - 1, "[%n] ", -123.0);
strlcat(actual, buf, sizeof(actual));
}
actual[strlen(actual) - 1] = '\0';
ATF_CHECK_STREQ_MSG(tests[i].expected, actual,
"sep_by_space = %zu", i);
}
}
ATF_TC(strfmon_cs_precedes_1);
ATF_TC_HEAD(strfmon_cs_precedes_1, tc)
{
atf_tc_set_md_var(tc, "descr",
"sep_by_space x sign_posn when cs_precedes = 1");
}
ATF_TC_BODY(strfmon_cs_precedes_1, tc)
{
const struct {
const char *expected;
} tests[] = {
/* sep_by_space x sign_posn */
{ "[($123.00)] [-$123.00] [$123.00-] [-$123.00] [$-123.00]" },
{ "[($ 123.00)] [-$ 123.00] [$ 123.00-] [-$ 123.00] [$- 123.00]" },
{ "[($123.00)] [- $123.00] [$123.00 -] [- $123.00] [$ -123.00]" },
};
size_t i, j;
struct lconv *lc;
char actual[100], buf[100];
if (setlocale(LC_MONETARY, "en_US.UTF-8") == NULL)
atf_tc_skip("unable to setlocale()");
lc = localeconv();
lc->n_cs_precedes = 1;
for (i = 0; i < nitems(tests); ++i) {
actual[0] = '\0';
lc->n_sep_by_space = i;
for (j = 0; j < 5; ++j) {
lc->n_sign_posn = j;
strfmon(buf, sizeof(buf) - 1, "[%n] ", -123.0);
strlcat(actual, buf, sizeof(actual));
}
actual[strlen(actual) - 1] = '\0';
ATF_CHECK_STREQ_MSG(tests[i].expected, actual,
"sep_by_space = %zu", i);
}
}
ATF_TC_WITHOUT_HEAD(strfmon_international_currency_code);
ATF_TC_BODY(strfmon_international_currency_code, tc)
{
const struct {
const char *locale;
const char *expected;
} tests[] = {
{ "en_US.UTF-8", "[USD123.45]" },
{ "de_DE.UTF-8", "[123,45 EUR]" },
{ "C", "[123.45]" },
};
size_t i;
char actual[100];
for (i = 0; i < nitems(tests); ++i) {
if (setlocale(LC_MONETARY, tests[i].locale) == NULL)
atf_tc_skip("unable to setlocale()");
strfmon(actual, sizeof(actual) - 1, "[%i]", 123.45);
ATF_CHECK_STREQ(tests[i].expected, actual);
}
}
ATF_TC(strfmon_l);
ATF_TC_HEAD(strfmon_l, tc)
{
atf_tc_set_md_var(tc, "descr",
"checks strfmon_l under different locales");
}
ATF_TC_BODY(strfmon_l, tc)
{
const struct {
const char *locale;
const char *expected;
} tests[] = {
{ "C", "[ **1234.57 ] [ **1234.57 ]" },
{ "de_DE.UTF-8", "[ **1234,57 €] [ **1.234,57 EUR]" },
{ "en_GB.UTF-8", "[ £**1234.57] [ GBP**1,234.57]" },
};
locale_t loc;
size_t i;
char buf[100];
for (i = 0; i < nitems(tests); ++i) {
loc = newlocale(LC_MONETARY_MASK, tests[i].locale, NULL);
ATF_REQUIRE(loc != NULL);
strfmon_l(buf, sizeof(buf) - 1, loc, "[%^=*#6n] [%=*#6i]",
1234.567, 1234.567);
ATF_REQUIRE_STREQ(tests[i].expected, buf);
freelocale(loc);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, strfmon_locale_thousands);
ATF_TP_ADD_TC(tp, strfmon_examples);
ATF_TP_ADD_TC(tp, strfmon_cs_precedes_0);
ATF_TP_ADD_TC(tp, strfmon_cs_precedes_1);
ATF_TP_ADD_TC(tp, strfmon_international_currency_code);
ATF_TP_ADD_TC(tp, strfmon_l);
return (atf_no_error());
}
diff --git a/lib/libc/tests/stdlib/tsearch_test.c b/lib/libc/tests/stdlib/tsearch_test.c
index 6dc53b3f6f81..ee9deec588cb 100644
--- a/lib/libc/tests/stdlib/tsearch_test.c
+++ b/lib/libc/tests/stdlib/tsearch_test.c
@@ -1,157 +1,156 @@
/*-
* Copyright (c) 2015 Nuxi, https://nuxi.nl/
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#define _SEARCH_PRIVATE
#include <search.h>
#include <stdbool.h>
#include <stdlib.h>
#include <stdio.h>
static int n_nodes = 0;
static int n_seen = 0;
/* Validates the integrity of an AVL tree. */
static inline unsigned int
tnode_assert(const posix_tnode *n)
{
unsigned int height_left, height_right;
int balance;
if (n == NULL)
return 0;
height_left = tnode_assert(n->llink);
height_right = tnode_assert(n->rlink);
balance = (int)height_left - (int)height_right;
ATF_CHECK(balance >= -1);
ATF_CHECK(balance <= 1);
ATF_CHECK_EQ(balance, n->balance);
return (height_left > height_right ? height_left : height_right) + 1;
}
static int
compar(const void *a, const void *b)
{
return *(int *)a - *(int *)b;
}
static void
treewalk(const posix_tnode *node, VISIT v, int level)
{
if (v == postorder || v == leaf)
n_seen++;
}
ATF_TC_WITHOUT_HEAD(tsearch_test);
ATF_TC_BODY(tsearch_test, tc)
{
/*
* Run the test below in a deterministic fashion to prevent this
* test from potentially flapping. We assume that this provides
* enough coverage.
*/
#if 0
unsigned short random_state[3];
arc4random_buf(random_state, sizeof(random_state));
#else
unsigned short random_state[3] = { 26554, 13330, 3246 };
#endif
#define NKEYS 1000
/* Create 1000 possible keys. */
int keys[NKEYS];
for (int i = 0; i < NKEYS; ++i)
keys[i] = i;
/* Apply random operations on a binary tree and check the results. */
posix_tnode *root = NULL;
bool present[NKEYS] = {};
for (int i = 0; i < NKEYS * 10; ++i) {
int key = nrand48(random_state) % NKEYS;
int sample = i;
/*
* Ensure each case is tested at least 10 times, plus a
* random sampling.
*/
if ((sample % NKEYS) > 3)
sample = nrand48(random_state) % 3;
switch (sample) {
case 0: /* tdelete(). */
if (present[key]) {
ATF_CHECK(tdelete(&key, &root, compar) != NULL);
present[key] = false;
ATF_CHECK(n_nodes > 0);
n_nodes--;
} else {
ATF_CHECK_EQ(NULL,
tdelete(&key, &root, compar));
}
break;
case 1: /* tfind(). */
if (present[key]) {
ATF_CHECK_EQ(&keys[key],
*(int **)tfind(&key, &root, compar));
} else {
ATF_CHECK_EQ(NULL, tfind(&key, &root, compar));
}
break;
case 2: /* tsearch(). */
if (present[key]) {
ATF_CHECK_EQ(&keys[key],
*(int **)tsearch(&key, &root, compar));
} else {
ATF_CHECK_EQ(&keys[key], *(int **)tsearch(
&keys[key], &root, compar));
present[key] = true;
n_nodes++;
}
break;
}
tnode_assert(root);
}
/* Walk the tree. */
twalk(root, treewalk);
ATF_CHECK_EQ(n_nodes, n_seen);
/* Remove all entries from the tree. */
for (int key = 0; key < NKEYS; ++key)
if (present[key])
ATF_CHECK(tdelete(&key, &root, compar) != NULL);
ATF_CHECK_EQ(NULL, root);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, tsearch_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/ffs_test.c b/lib/libc/tests/string/ffs_test.c
index aea61254482e..4b59385d712e 100644
--- a/lib/libc/tests/string/ffs_test.c
+++ b/lib/libc/tests/string/ffs_test.c
@@ -1,88 +1,87 @@
/*-
* Copyright (c) 2023 The FreeBSD Foundation
*
* This software was developed by Robert Clausecker <fuz@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#include <limits.h>
#include <stdint.h>
#include <strings.h>
#ifndef FFS
# define FFS ffs
# define TYPE int
# define TYPE_MIN INT_MIN
#endif
ATF_TC_WITHOUT_HEAD(zero);
ATF_TC_BODY(zero, tc)
{
ATF_CHECK_EQ((TYPE)0, FFS(0));
}
ATF_TC_WITHOUT_HEAD(twobit);
ATF_TC_BODY(twobit, tc)
{
const TYPE one = 1;
TYPE x;
const int n = sizeof(TYPE) * CHAR_BIT;
int i, j;
for (i = 0; i < n - 1; i++)
for (j = 0; j <= i; j++) {
x = one << i | one << j;
ATF_CHECK_EQ_MSG(j + 1, FFS(x),
"%s(%#jx) == %d != %d", __STRING(FFS), (intmax_t)x, FFS(x), j + 1);
}
}
ATF_TC_WITHOUT_HEAD(twobitneg);
ATF_TC_BODY(twobitneg, tc)
{
const TYPE one = 1;
TYPE x;
const int n = sizeof(TYPE) * CHAR_BIT;
int i, j;
for (i = 0; i < n - 1; i++)
for (j = 0; j <= i; j++) {
x = one << i | one << j | TYPE_MIN;
ATF_CHECK_EQ_MSG(j + 1, FFS(x),
"%s(%#jx) == %d != %d", __STRING(FFS), (intmax_t)x, FFS(x), j + 1);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, zero);
ATF_TP_ADD_TC(tp, twobit);
ATF_TP_ADD_TC(tp, twobitneg);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/fls_test.c b/lib/libc/tests/string/fls_test.c
index 847977d260c9..55691b36617c 100644
--- a/lib/libc/tests/string/fls_test.c
+++ b/lib/libc/tests/string/fls_test.c
@@ -1,88 +1,87 @@
/*-
* Copyright (c) 2023 The FreeBSD Foundation
*
* This software was developed by Robert Clausecker <fuz@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#include <limits.h>
#include <stdint.h>
#include <strings.h>
#ifndef FLS
# define FLS fls
# define TYPE int
# define TYPE_MIN INT_MIN
#endif
ATF_TC_WITHOUT_HEAD(zero);
ATF_TC_BODY(zero, tc)
{
ATF_CHECK_EQ((TYPE)0, FLS(0));
}
ATF_TC_WITHOUT_HEAD(twobit);
ATF_TC_BODY(twobit, tc)
{
const TYPE one = 1;
TYPE x;
const int n = sizeof(TYPE) * CHAR_BIT;
int i, j;
for (i = 0; i < n - 1; i++)
for (j = 0; j <= i; j++) {
x = one << i | one << j;
ATF_CHECK_EQ_MSG(i + 1, FLS(x),
"%s(%#jx) == %d != %d", __STRING(FLS), (intmax_t)x, FLS(x), i + 1);
}
}
ATF_TC_WITHOUT_HEAD(twobitneg);
ATF_TC_BODY(twobitneg, tc)
{
const TYPE one = 1;
TYPE x;
const int n = sizeof(TYPE) * CHAR_BIT;
int i, j;
for (i = 0; i < n - 1; i++)
for (j = 0; j <= i; j++) {
x = one << i | one << j | TYPE_MIN;
ATF_CHECK_EQ_MSG(n, FLS(x),
"%s(%#jx) == %d != %d", __STRING(FLS), (intmax_t)x, FLS(x), n);
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, zero);
ATF_TP_ADD_TC(tp, twobit);
ATF_TP_ADD_TC(tp, twobitneg);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/memcmp_test.c b/lib/libc/tests/string/memcmp_test.c
index 487abe68f421..5286a0b994f3 100644
--- a/lib/libc/tests/string/memcmp_test.c
+++ b/lib/libc/tests/string/memcmp_test.c
@@ -1,161 +1,160 @@
/*-
* Copyright (c) 2016 Jilles Tjoelker <jilles@FreeBSD.org>
* Copyright (c) 2023 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Robert Clausecker
* <fuz@FreeBSD.org> under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
#ifndef MEMCMP
#define MEMCMP memcmp
#endif
/*
* On FreeBSD we demand that memcmp returns the difference between the
* characters at the first site of mismatch. However, ISO/IEC 9899:1990
* only specifies that a number greater than, equal to, or less than
* zero shall be returned. If a unit test for this less strict
* behaviour is desired, define RES(x) to be (((x) > 0) - ((x) < 0)).
*/
#ifndef RES
#define RES(x) (x)
#endif
static int (*memcmp_fn)(const void *, const void *, size_t);
static void
check_memcmp(const char *a, const char *b, size_t len, int expected)
{
int got;
got = memcmp_fn(a, b, len);
ATF_CHECK_EQ_MSG(RES(expected), RES(got),
"%s(%p, %p, %zu) gave %d, but wanted %d",
__XSTRING(MEMCMP), a, b, len, got, expected);
}
ATF_TC_WITHOUT_HEAD(zero);
ATF_TC_BODY(zero, tc)
{
check_memcmp("a", "b", 0, 0);
check_memcmp("", "", 0, 0);
}
ATF_TC_WITHOUT_HEAD(eq);
ATF_TC_BODY(eq, tc)
{
unsigned char data1[256], data2[256];
int i;
for (i = 0; i < 256; i++)
data1[i] = data2[i] = i ^ 0x55;
for (i = 1; i < 256; i++)
check_memcmp(data1, data2, i, 0);
for (i = 1; i < 256; i++)
check_memcmp(data1 + i, data2 + i, 256 - i, 0);
}
ATF_TC_WITHOUT_HEAD(neq);
ATF_TC_BODY(neq, tc)
{
unsigned char data1[256], data2[256];
int i;
for (i = 0; i < 256; i++) {
data1[i] = i;
data2[i] = i ^ 0x55;
}
for (i = 1; i < 256; i++)
check_memcmp(data1, data2, i, -0x55);
for (i = 1; i < 256; i++)
check_memcmp(data1 + i, data2 + i, 256 - i, i - (i ^ 0x55));
}
ATF_TC_WITHOUT_HEAD(diff);
ATF_TC_BODY(diff, tc)
{
unsigned char data1[256], data2[256];
int i;
memset(data1, 'a', sizeof(data1));
memset(data2, 'a', sizeof(data2));
data1[128] = 255;
data2[128] = 0;
for (i = 1; i < 66; i++) {
check_memcmp(data1 + 128, data2 + 128, i, 255);
check_memcmp(data2 + 128, data1 + 128, i, -255);
check_memcmp(data1 + 129 - i, data2 + 129 - i, i, 255);
check_memcmp(data2 + 129 - i, data1 + 129 - i, i, -255);
check_memcmp(data1 + 129 - i, data2 + 129 - i, i * 2, 255);
check_memcmp(data2 + 129 - i, data1 + 129 - i, i * 2, -255);
}
data1[128] = 'c';
data2[128] = 'e';
for (i = 1; i < 66; i++) {
check_memcmp(data1 + 128, data2 + 128, i, -2);
check_memcmp(data2 + 128, data1 + 128, i, 2);
check_memcmp(data1 + 129 - i, data2 + 129 - i, i, -2);
check_memcmp(data2 + 129 - i, data1 + 129 - i, i, 2);
check_memcmp(data1 + 129 - i, data2 + 129 - i, i * 2, -2);
check_memcmp(data2 + 129 - i, data1 + 129 - i, i * 2, 2);
}
memset(data1 + 129, 'A', sizeof(data1) - 129);
memset(data2 + 129, 'Z', sizeof(data2) - 129);
for (i = 1; i < 66; i++) {
check_memcmp(data1 + 128, data2 + 128, i, -2);
check_memcmp(data2 + 128, data1 + 128, i, 2);
check_memcmp(data1 + 129 - i, data2 + 129 - i, i, -2);
check_memcmp(data2 + 129 - i, data1 + 129 - i, i, 2);
check_memcmp(data1 + 129 - i, data2 + 129 - i, i * 2, -2);
check_memcmp(data2 + 129 - i, data1 + 129 - i, i * 2, 2);
}
}
ATF_TP_ADD_TCS(tp)
{
void *dl_handle;
dl_handle = dlopen(NULL, RTLD_LAZY);
memcmp_fn = dlsym(dl_handle, "test_" __XSTRING(MEMCMP));
if (memcmp_fn == NULL)
memcmp_fn = MEMCMP;
ATF_TP_ADD_TC(tp, zero);
ATF_TP_ADD_TC(tp, eq);
ATF_TP_ADD_TC(tp, neq);
ATF_TP_ADD_TC(tp, diff);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/memset_s_test.c b/lib/libc/tests/string/memset_s_test.c
index 90a6958cb369..c822a2ee4554 100644
--- a/lib/libc/tests/string/memset_s_test.c
+++ b/lib/libc/tests/string/memset_s_test.c
@@ -1,198 +1,197 @@
/*-
* Copyright (c) 2017 Juniper Networks. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
static errno_t e;
static const char * restrict m;
void
h(const char * restrict msg, void * restrict ptr __unused, errno_t error)
{
e = error;
m = msg;
}
/* null ptr */
ATF_TC_WITHOUT_HEAD(null_ptr);
ATF_TC_BODY(null_ptr, tc)
{
assert(memset_s(0, 1, 1, 1) != 0);
}
/* smax > rmax */
ATF_TC_WITHOUT_HEAD(smax_gt_rmax);
ATF_TC_BODY(smax_gt_rmax, tc)
{
char b;
assert(memset_s(&b, RSIZE_MAX + 1, 1, 1) != 0);
}
/* smax < 0 */
ATF_TC_WITHOUT_HEAD(smax_lt_zero);
ATF_TC_BODY(smax_lt_zero, tc)
{
char b;
assert(memset_s(&b, -1, 1, 1) != 0);
}
/* normal */
ATF_TC_WITHOUT_HEAD(normal);
ATF_TC_BODY(normal, tc)
{
char b;
b = 3;
assert(memset_s(&b, 1, 5, 1) == 0);
assert(b == 5);
}
/* n > rmax */
ATF_TC_WITHOUT_HEAD(n_gt_rmax);
ATF_TC_BODY(n_gt_rmax, tc)
{
char b;
assert(memset_s(&b, 1, 1, RSIZE_MAX + 1) != 0);
}
/* n < 0 */
ATF_TC_WITHOUT_HEAD(n_lt_zero);
ATF_TC_BODY(n_lt_zero, tc)
{
char b;
assert(memset_s(&b, 1, 1, -1) != 0);
}
/* n < smax */
ATF_TC_WITHOUT_HEAD(n_lt_smax);
ATF_TC_BODY(n_lt_smax, tc)
{
char b[3] = {1, 2, 3};
assert(memset_s(&b[0], 3, 9, 1) == 0);
assert(b[0] == 9);
assert(b[1] == 2);
assert(b[2] == 3);
}
/* n > smax, handler */
ATF_TC_WITHOUT_HEAD(n_gt_smax);
ATF_TC_BODY(n_gt_smax, tc)
{
char b[3] = {1, 2, 3};
e = 0;
m = NULL;
set_constraint_handler_s(h);
assert(memset_s(&b[0], 1, 9, 3) != 0);
assert(e > 0);
assert(strcmp(m, "memset_s : n > smax") == 0);
assert(b[0] == 9);
assert(b[1] == 2);
assert(b[2] == 3);
}
/* smax > rmax, handler */
ATF_TC_WITHOUT_HEAD(smax_gt_rmax_handler);
ATF_TC_BODY(smax_gt_rmax_handler, tc)
{
char b;
e = 0;
m = NULL;
set_constraint_handler_s(h);
assert(memset_s(&b, RSIZE_MAX + 1, 1, 1) != 0);
assert(e > 0);
assert(strcmp(m, "memset_s : smax > RSIZE_MAX") == 0);
}
/* smax < 0, handler */
ATF_TC_WITHOUT_HEAD(smax_lt_zero_handler);
ATF_TC_BODY(smax_lt_zero_handler, tc)
{
char b;
e = 0;
m = NULL;
set_constraint_handler_s(h);
assert(memset_s(&b, -1, 1, 1) != 0);
assert(e > 0);
assert(strcmp(m, "memset_s : smax > RSIZE_MAX") == 0);
}
/* n > rmax, handler */
ATF_TC_WITHOUT_HEAD(n_gt_rmax_handler);
ATF_TC_BODY(n_gt_rmax_handler, tc)
{
char b;
e = 0;
m = NULL;
set_constraint_handler_s(h);
assert(memset_s(&b, 1, 1, RSIZE_MAX + 1) != 0);
assert(e > 0);
assert(strcmp(m, "memset_s : n > RSIZE_MAX") == 0);
}
/* n < 0, handler */
ATF_TC_WITHOUT_HEAD(n_lt_zero_handler);
ATF_TC_BODY(n_lt_zero_handler, tc)
{
char b;
e = 0;
m = NULL;
set_constraint_handler_s(h);
assert(memset_s(&b, 1, 1, -1) != 0);
assert(e > 0);
assert(strcmp(m, "memset_s : n > RSIZE_MAX") == 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, null_ptr);
ATF_TP_ADD_TC(tp, smax_gt_rmax);
ATF_TP_ADD_TC(tp, smax_lt_zero);
ATF_TP_ADD_TC(tp, normal);
ATF_TP_ADD_TC(tp, n_gt_rmax);
ATF_TP_ADD_TC(tp, n_lt_zero);
ATF_TP_ADD_TC(tp, n_gt_smax);
ATF_TP_ADD_TC(tp, n_lt_smax);
ATF_TP_ADD_TC(tp, smax_gt_rmax_handler);
ATF_TP_ADD_TC(tp, smax_lt_zero_handler);
ATF_TP_ADD_TC(tp, n_gt_rmax_handler);
ATF_TP_ADD_TC(tp, n_lt_zero_handler);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/stpncpy_test.c b/lib/libc/tests/string/stpncpy_test.c
index 6602bda0c2a9..8154237eb8c2 100644
--- a/lib/libc/tests/string/stpncpy_test.c
+++ b/lib/libc/tests/string/stpncpy_test.c
@@ -1,111 +1,110 @@
/*-
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <atf-c.h>
static char *
makebuf(size_t len, int guard_at_end)
{
char *buf;
size_t alloc_size, page_size;
page_size = getpagesize();
alloc_size = roundup2(len, page_size) + page_size;
buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
assert(buf);
if (guard_at_end) {
assert(munmap(buf + alloc_size - page_size, page_size) == 0);
return (buf + alloc_size - page_size - len);
} else {
assert(munmap(buf, page_size) == 0);
return (buf + page_size);
}
}
static void
test_stpncpy(const char *s)
{
char *src, *dst;
size_t size, len, bufsize, x;
int i, j;
size = strlen(s) + 1;
for (i = 0; i <= 1; i++) {
for (j = 0; j <= 1; j++) {
for (bufsize = 0; bufsize <= size + 10; bufsize++) {
src = makebuf(size, i);
memcpy(src, s, size);
dst = makebuf(bufsize, j);
memset(dst, 'X', bufsize);
len = (bufsize < size) ? bufsize : size - 1;
assert(stpncpy(dst, src, bufsize) == dst+len);
assert(memcmp(src, dst, len) == 0);
for (x = len; x < bufsize; x++)
assert(dst[x] == '\0');
}
}
}
}
ATF_TC_WITHOUT_HEAD(nul);
ATF_TC_BODY(nul, tc)
{
test_stpncpy("");
}
ATF_TC_WITHOUT_HEAD(foo);
ATF_TC_BODY(foo, tc)
{
test_stpncpy("foo");
}
ATF_TC_WITHOUT_HEAD(glorp);
ATF_TC_BODY(glorp, tc)
{
test_stpncpy("glorp");
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, nul);
ATF_TP_ADD_TC(tp, foo);
ATF_TP_ADD_TC(tp, glorp);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/strcspn_test.c b/lib/libc/tests/string/strcspn_test.c
index 722d20025535..6cb2a04d3e64 100644
--- a/lib/libc/tests/string/strcspn_test.c
+++ b/lib/libc/tests/string/strcspn_test.c
@@ -1,221 +1,220 @@
/*-
* Copyright (c) 2023 The FreeBSD Foundation
*
* This software was developed by Robert Clausecker <fuz@FreeBSD.org>
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ''AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE
*/
-#include <sys/cdefs.h>
#include <atf-c.h>
#include <assert.h>
#include <limits.h>
#include <stdbool.h>
#include <stddef.h>
#include <string.h>
enum {
MAXALIGN = 16, /* test all offsets from this alignment */
MAXBUF = 64, /* test up to this buffer length */
};
enum { NOMATCH, MATCH };
#ifdef STRSPN
#define STRXSPN strspn
#else
#define STRXSPN strcspn
#endif
static void
testcase(char *buf, size_t buflen, char *set, size_t setlen, int want_match)
{
size_t i, outcome, expected;
assert(setlen < UCHAR_MAX - 2);
for (i = 0; i < buflen; i++)
#ifdef STRSPN
buf[i] = UCHAR_MAX - i % (setlen > 0 ? setlen : 1);
#else /* strcspn */
buf[i] = 1 + i % (UCHAR_MAX - setlen - 1);
#endif
buf[i] = '\0';
for (i = 0; i < setlen; i++)
set[i] = UCHAR_MAX - i;
set[i] = '\0';
#ifdef STRSPN
if (setlen == 0)
expected = 0;
else if (want_match == MATCH && buflen > 0) {
buf[buflen - 1] = 1;
expected = buflen - 1;
} else
expected = buflen;
#else /* strcspn */
if (want_match == MATCH && buflen > 0 && setlen > 0) {
buf[buflen - 1] = UCHAR_MAX;
expected = buflen - 1;
} else
expected = buflen;
#endif
outcome = STRXSPN(buf, set);
ATF_CHECK_EQ_MSG(expected, outcome, "%s(%p[%zu], %p[%zu]) = %zu != %zu",
__XSTRING(STRXSPN), buf, buflen, set, setlen, outcome, expected);
}
/* test set with all alignments and lengths of buf */
static void
test_buf_alignments(char *set, size_t setlen, int want_match)
{
char buf[MAXALIGN + MAXBUF + 1];
size_t i, j;
for (i = 0; i < MAXALIGN; i++)
for (j = 0; j <= MAXBUF; j++)
testcase(buf + i, j, set, setlen, want_match);
}
/* test buf with all alignments and lengths of set */
static void
test_set_alignments(char *buf, size_t buflen, int want_match)
{
char set[MAXALIGN + MAXBUF + 1];
size_t i, j;
for (i = 0; i < MAXALIGN; i++)
for (j = 0; j <= MAXBUF; j++)
testcase(buf, buflen, set + i, j, want_match);
}
ATF_TC_WITHOUT_HEAD(buf_alignments);
ATF_TC_BODY(buf_alignments, tc)
{
char set[41];
test_buf_alignments(set, 0, MATCH);
test_buf_alignments(set, 1, MATCH);
test_buf_alignments(set, 5, MATCH);
test_buf_alignments(set, 20, MATCH);
test_buf_alignments(set, 40, MATCH);
test_buf_alignments(set, 0, NOMATCH);
test_buf_alignments(set, 1, NOMATCH);
test_buf_alignments(set, 5, NOMATCH);
test_buf_alignments(set, 20, NOMATCH);
test_buf_alignments(set, 40, NOMATCH);
}
ATF_TC_WITHOUT_HEAD(set_alignments);
ATF_TC_BODY(set_alignments, tc)
{
char buf[31];
test_set_alignments(buf, 0, MATCH);
test_set_alignments(buf, 10, MATCH);
test_set_alignments(buf, 20, MATCH);
test_set_alignments(buf, 30, MATCH);
test_set_alignments(buf, 0, NOMATCH);
test_set_alignments(buf, 10, NOMATCH);
test_set_alignments(buf, 20, NOMATCH);
test_set_alignments(buf, 30, NOMATCH);
}
#ifndef STRSPN
/* test all positions in which set could match buf */
static void
test_match_positions(char *buf, char *set, size_t buflen, size_t setlen)
{
size_t i, j, outcome;
memset(buf, '-', buflen);
for (i = 0; i < setlen; i++)
set[i] = 'A' + i;
buf[buflen] = '\0';
set[setlen] = '\0';
/*
* Check for (mis)match at buffer position i
* against set position j.
*/
for (i = 0; i < buflen; i++) {
for (j = 0; j < setlen; j++) {
buf[i] = set[j];
outcome = strcspn(buf, set);
ATF_CHECK_EQ_MSG(i, outcome,
"strcspn(\"%s\", \"%s\") = %zu != %zu",
buf, set, outcome, i);
}
buf[i] = '-';
}
}
ATF_TC_WITHOUT_HEAD(match_positions);
ATF_TC_BODY(match_positions, tc)
{
char buf[129], set[65];
test_match_positions(buf, set, 128, 64);
test_match_positions(buf, set, 64, 64);
test_match_positions(buf, set, 32, 64);
test_match_positions(buf, set, 16, 64);
test_match_positions(buf, set, 8, 64);
test_match_positions(buf, set, 128, 32);
test_match_positions(buf, set, 64, 32);
test_match_positions(buf, set, 32, 32);
test_match_positions(buf, set, 16, 32);
test_match_positions(buf, set, 8, 32);
test_match_positions(buf, set, 128, 16);
test_match_positions(buf, set, 64, 16);
test_match_positions(buf, set, 32, 16);
test_match_positions(buf, set, 16, 16);
test_match_positions(buf, set, 8, 16);
test_match_positions(buf, set, 128, 8);
test_match_positions(buf, set, 64, 8);
test_match_positions(buf, set, 32, 8);
test_match_positions(buf, set, 16, 8);
test_match_positions(buf, set, 8, 8);
}
#endif /* !defined(STRSPN) */
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, buf_alignments);
ATF_TP_ADD_TC(tp, set_alignments);
#ifndef STRSPN
ATF_TP_ADD_TC(tp, match_positions);
#endif
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/strxfrm_test.c b/lib/libc/tests/string/strxfrm_test.c
index 3c2ab58cb72b..becc620ba79c 100644
--- a/lib/libc/tests/string/strxfrm_test.c
+++ b/lib/libc/tests/string/strxfrm_test.c
@@ -1,49 +1,48 @@
/*-
* Copyright (c) 2016 Baptiste Daroussin <bapt@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <string.h>
#include <locale.h>
#include <stdio.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(iso_8859_5);
ATF_TC_BODY(iso_8859_5, tc)
{
char s1[8];
const char s2[] = { 0xa1, 0 };
setlocale(LC_ALL, "ru_RU.ISO8859-5");
strxfrm(s1, s2, 0x8);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, iso_8859_5);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/wcscasecmp_test.c b/lib/libc/tests/string/wcscasecmp_test.c
index 5927345e7f4a..9a47c0d91b31 100644
--- a/lib/libc/tests/string/wcscasecmp_test.c
+++ b/lib/libc/tests/string/wcscasecmp_test.c
@@ -1,126 +1,125 @@
/*-
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <assert.h>
#include <locale.h>
#include <stdio.h>
#include <stdlib.h>
#include <wchar.h>
#include <wctype.h>
#include <atf-c.h>
ATF_TC_WITHOUT_HEAD(nul);
ATF_TC_BODY(nul, tc)
{
ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
ATF_CHECK(wcscasecmp(L"", L"") == 0);
ATF_CHECK(wcsncasecmp(L"", L"", 50) == 0);
ATF_CHECK(wcsncasecmp(L"", L"", 0) == 0);
}
ATF_TC_WITHOUT_HEAD(wcscasecmp_equal);
ATF_TC_BODY(wcscasecmp_equal, tc)
{
ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
ATF_CHECK(wcscasecmp(L"abc", L"abc") == 0);
ATF_CHECK(wcscasecmp(L"ABC", L"ABC") == 0);
ATF_CHECK(wcscasecmp(L"abc", L"ABC") == 0);
ATF_CHECK(wcscasecmp(L"ABC", L"abc") == 0);
}
ATF_TC_WITHOUT_HEAD(wcscasecmp_same_len_buffers);
ATF_TC_BODY(wcscasecmp_same_len_buffers, tc)
{
ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
ATF_CHECK(wcscasecmp(L"abc", L"xyz") < 0);
ATF_CHECK(wcscasecmp(L"ABC", L"xyz") < 0);
ATF_CHECK(wcscasecmp(L"abc", L"XYZ") < 0);
ATF_CHECK(wcscasecmp(L"ABC", L"XYZ") < 0);
ATF_CHECK(wcscasecmp(L"xyz", L"abc") > 0);
ATF_CHECK(wcscasecmp(L"XYZ", L"abc") > 0);
ATF_CHECK(wcscasecmp(L"xyz", L"ABC") > 0);
ATF_CHECK(wcscasecmp(L"XYZ", L"ABC") > 0);
}
ATF_TC_WITHOUT_HEAD(wcscasecmp_mismatched_len_buffers);
ATF_TC_BODY(wcscasecmp_mismatched_len_buffers, tc)
{
ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
ATF_CHECK(wcscasecmp(L"abc", L"ABCD") < 0);
ATF_CHECK(wcscasecmp(L"ABC", L"abcd") < 0);
ATF_CHECK(wcscasecmp(L"abcd", L"ABC") > 0);
ATF_CHECK(wcscasecmp(L"ABCD", L"abc") > 0);
}
ATF_TC_WITHOUT_HEAD(wcsncasecmp);
ATF_TC_BODY(wcsncasecmp, tc)
{
ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
ATF_CHECK(wcsncasecmp(L"abc", L"ABCD", 4) < 0);
ATF_CHECK(wcsncasecmp(L"ABC", L"abcd", 4) < 0);
ATF_CHECK(wcsncasecmp(L"abcd", L"ABC", 4) > 0);
ATF_CHECK(wcsncasecmp(L"ABCD", L"abc", 4) > 0);
ATF_CHECK(wcsncasecmp(L"abc", L"ABCD", 3) == 0);
ATF_CHECK(wcsncasecmp(L"ABC", L"abcd", 3) == 0);
}
ATF_TC_WITHOUT_HEAD(wcscasecmp_greek);
ATF_TC_BODY(wcscasecmp_greek, tc)
{
ATF_REQUIRE(setlocale(LC_CTYPE, "C") != NULL);
ATF_CHECK(wcscasecmp(L"λ", L"Λ") != 0);
ATF_REQUIRE(setlocale(LC_CTYPE, "el_GR.UTF-8") != NULL);
ATF_CHECK(wcscasecmp(L"λ", L"Λ") == 0);
ATF_CHECK(wcscasecmp(L"λ", L"Ω") < 0);
ATF_CHECK(wcscasecmp(L"Ω", L"λ") > 0);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, nul);
ATF_TP_ADD_TC(tp, wcscasecmp_equal);
ATF_TP_ADD_TC(tp, wcscasecmp_same_len_buffers);
ATF_TP_ADD_TC(tp, wcscasecmp_mismatched_len_buffers);
ATF_TP_ADD_TC(tp, wcsncasecmp);
ATF_TP_ADD_TC(tp, wcscasecmp_greek);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/wcscoll_test.c b/lib/libc/tests/string/wcscoll_test.c
index d64e03f0605a..2ce85bbb986b 100644
--- a/lib/libc/tests/string/wcscoll_test.c
+++ b/lib/libc/tests/string/wcscoll_test.c
@@ -1,154 +1,153 @@
/*-
* Copyright (c) 2016 Baptiste Daroussin <bapt@FreeBSD.org>
* Copyright 2016 Tom Lane <tgl@sss.pgh.pa.us>
* Copyright 2017 Nexenta Systems, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <wchar.h>
#include <locale.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <atf-c.h>
static int
cmp(const void *a, const void *b)
{
const wchar_t wa[2] = { *(const wchar_t *)a, 0 };
const wchar_t wb[2] = { *(const wchar_t *)b, 0 };
return (wcscoll(wa, wb));
}
ATF_TC_WITHOUT_HEAD(russian_collation);
ATF_TC_BODY(russian_collation, tc)
{
wchar_t c[] = L"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё";
wchar_t res[] = L"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZаАбБвВгГдДеЕёЁжЖзЗиИйЙкКлЛмМнНоОпПрРсСтТуУфФхХцЦчЧшШщЩъЪыЫьЬэЭюЮяЯ";
ATF_CHECK_MSG(setlocale(LC_ALL, "ru_RU.UTF-8") != NULL,
"Fail to set locale to \"ru_RU.UTF-8\"");
qsort(c, wcslen(c), sizeof(wchar_t), cmp);
ATF_CHECK_MSG(wcscmp(c, res) == 0,
"Bad collation, expected: '%ls' got '%ls'", res, c);
}
#define NSTRINGS 2000
#define MAXSTRLEN 20
#define MAXXFRMLEN (MAXSTRLEN * 20)
typedef struct {
char sval[MAXSTRLEN];
char xval[MAXXFRMLEN];
} cstr;
ATF_TC_WITHOUT_HEAD(strcoll_vs_strxfrm);
ATF_TC_BODY(strcoll_vs_strxfrm, tc)
{
cstr data[NSTRINGS];
char *curloc;
int i, j;
curloc = setlocale(LC_ALL, "en_US.UTF-8");
ATF_CHECK_MSG(curloc != NULL, "Fail to set locale");
/* Ensure new random() values on every run */
srandom((unsigned int) time(NULL));
/* Generate random UTF8 strings of length less than MAXSTRLEN bytes */
for (i = 0; i < NSTRINGS; i++) {
char *p;
int len;
again:
p = data[i].sval;
len = 1 + (random() % (MAXSTRLEN - 1));
while (len > 0) {
int c;
/*
* Generate random printable char in ISO8859-1 range.
* Bias towards producing a lot of spaces.
*/
if ((random() % 16) < 3) {
c = ' ';
} else {
do {
c = random() & 0xFF;
} while (!((c >= ' ' && c <= 127) ||
(c >= 0xA0 && c <= 0xFF)));
}
if (c <= 127) {
*p++ = c;
len--;
} else {
if (len < 2)
break;
/* Poor man's utf8-ification */
*p++ = 0xC0 + (c >> 6);
len--;
*p++ = 0x80 + (c & 0x3F);
len--;
}
}
*p = '\0';
/* strxfrm() each string as we produce it */
errno = 0;
ATF_CHECK_MSG(strxfrm(data[i].xval, data[i].sval,
MAXXFRMLEN) < MAXXFRMLEN, "strxfrm() result for %d-length "
" string exceeded %d bytes", (int)strlen(data[i].sval),
MAXXFRMLEN);
/*
* Amend strxfrm() failing on certain characters to be fixed and
* test later
*/
if (errno != 0)
goto again;
}
for (i = 0; i < NSTRINGS; i++) {
for (j = 0; j < NSTRINGS; j++) {
int sr = strcoll(data[i].sval, data[j].sval);
int sx = strcmp(data[i].xval, data[j].xval);
ATF_CHECK_MSG(!((sr * sx < 0) ||
(sr * sx == 0 && sr + sx != 0)),
"%s: diff for \"%s\" and \"%s\"",
curloc, data[i].sval, data[j].sval);
}
}
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, russian_collation);
ATF_TP_ADD_TC(tp, strcoll_vs_strxfrm);
return (atf_no_error());
}
diff --git a/lib/libc/tests/string/wcsnlen_test.c b/lib/libc/tests/string/wcsnlen_test.c
index 56a2ef1e3623..ba2e1c8d7c57 100644
--- a/lib/libc/tests/string/wcsnlen_test.c
+++ b/lib/libc/tests/string/wcsnlen_test.c
@@ -1,105 +1,104 @@
/*-
* Copyright (c) 2009 David Schultz <das@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <atf-c.h>
static void *
makebuf(size_t len, int guard_at_end)
{
char *buf;
size_t alloc_size, page_size;
page_size = getpagesize();
alloc_size = roundup2(len, page_size) + page_size;
buf = mmap(NULL, alloc_size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
ATF_CHECK(buf);
if (guard_at_end) {
ATF_CHECK(munmap(buf + alloc_size - page_size, page_size) == 0);
return (buf + alloc_size - page_size - len);
} else {
ATF_CHECK(munmap(buf, page_size) == 0);
return (buf + page_size);
}
}
static void
test_wcsnlen(const wchar_t *s)
{
wchar_t *s1;
size_t size, len, bufsize;
int i;
size = wcslen(s) + 1;
for (i = 0; i <= 1; i++) {
for (bufsize = 0; bufsize <= size + 10; bufsize++) {
s1 = makebuf(bufsize * sizeof(wchar_t), i);
wmemcpy(s1, s, bufsize <= size ? bufsize : size);
len = (size > bufsize) ? bufsize : size - 1;
ATF_CHECK(wcsnlen(s1, bufsize) == len);
}
}
}
ATF_TC_WITHOUT_HEAD(nul);
ATF_TC_BODY(nul, tc)
{
test_wcsnlen(L"");
}
ATF_TC_WITHOUT_HEAD(foo);
ATF_TC_BODY(foo, tc)
{
test_wcsnlen(L"foo");
}
ATF_TC_WITHOUT_HEAD(glorp);
ATF_TC_BODY(glorp, tc)
{
test_wcsnlen(L"glorp");
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, nul);
ATF_TP_ADD_TC(tp, foo);
ATF_TP_ADD_TC(tp, glorp);
return (atf_no_error());
}
diff --git a/lib/libc/tests/sys/brk_test.c b/lib/libc/tests/sys/brk_test.c
index 38093b4cbd29..2d8c7af38ff7 100644
--- a/lib/libc/tests/sys/brk_test.c
+++ b/lib/libc/tests/sys/brk_test.c
@@ -1,147 +1,146 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2018 Mark Johnston <markj@FreeBSD.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
ATF_TC(brk_basic);
ATF_TC_HEAD(brk_basic, tc)
{
atf_tc_set_md_var(tc, "descr", "Verify basic brk() functionality");
}
ATF_TC_BODY(brk_basic, tc)
{
void *oldbrk, *newbrk;
int error;
/* Reset the break. */
error = brk(0);
ATF_REQUIRE_MSG(error == 0, "brk: %s", strerror(errno));
oldbrk = sbrk(0);
ATF_REQUIRE(oldbrk != (void *)-1);
/* Try to allocate a page. */
error = brk((void *)((intptr_t)oldbrk + PAGE_SIZE * 2));
ATF_REQUIRE_MSG(error == 0, "brk: %s", strerror(errno));
/*
* Attempt to set the break below minbrk. This should have no effect.
*/
error = brk((void *)((intptr_t)oldbrk - 1));
ATF_REQUIRE_MSG(error == 0, "brk: %s", strerror(errno));
newbrk = sbrk(0);
ATF_REQUIRE_MSG(newbrk != (void *)-1, "sbrk: %s", strerror(errno));
ATF_REQUIRE(newbrk == oldbrk);
}
ATF_TC(sbrk_basic);
ATF_TC_HEAD(sbrk_basic, tc)
{
atf_tc_set_md_var(tc, "descr", "Verify basic sbrk() functionality");
}
ATF_TC_BODY(sbrk_basic, tc)
{
void *newbrk, *oldbrk;
int *p;
oldbrk = sbrk(0);
ATF_REQUIRE_MSG(oldbrk != (void *)-1, "sbrk: %s", strerror(errno));
p = sbrk(sizeof(*p));
*p = 0;
ATF_REQUIRE(oldbrk == p);
newbrk = sbrk(-sizeof(*p));
ATF_REQUIRE_MSG(newbrk != (void *)-1, "sbrk: %s", strerror(errno));
ATF_REQUIRE(oldbrk == sbrk(0));
oldbrk = sbrk(PAGE_SIZE * 2 + 1);
ATF_REQUIRE_MSG(oldbrk != (void *)-1, "sbrk: %s", strerror(errno));
memset(oldbrk, 0, PAGE_SIZE * 2 + 1);
newbrk = sbrk(-(PAGE_SIZE * 2 + 1));
ATF_REQUIRE_MSG(newbrk != (void *)-1, "sbrk: %s", strerror(errno));
ATF_REQUIRE(sbrk(0) == oldbrk);
}
ATF_TC(mlockfuture);
ATF_TC_HEAD(mlockfuture, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that mlockall(MCL_FUTURE) applies to the data segment");
}
ATF_TC_BODY(mlockfuture, tc)
{
void *oldbrk, *n, *newbrk;
int error;
char v;
error = mlockall(MCL_FUTURE);
ATF_REQUIRE_MSG(error == 0,
"mlockall: %s", strerror(errno));
/*
* Advance the break so that at least one page is added to the data
* segment. This page should be automatically faulted in to the address
* space.
*/
oldbrk = sbrk(0);
ATF_REQUIRE(oldbrk != (void *)-1);
newbrk = sbrk(PAGE_SIZE * 2);
ATF_REQUIRE(newbrk != (void *)-1);
n = (void *)(((uintptr_t)oldbrk + PAGE_SIZE) & ~PAGE_SIZE);
v = 0;
error = mincore(n, PAGE_SIZE, &v);
ATF_REQUIRE_MSG(error == 0,
"mincore: %s", strerror(errno));
ATF_REQUIRE_MSG((v & MINCORE_INCORE) != 0,
"unexpected page flags %#x", v);
error = brk(oldbrk);
ATF_REQUIRE(error == 0);
error = munlockall();
ATF_REQUIRE_MSG(error == 0,
"munlockall: %s", strerror(errno));
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, brk_basic);
ATF_TP_ADD_TC(tp, sbrk_basic);
ATF_TP_ADD_TC(tp, mlockfuture);
return (atf_no_error());
}
diff --git a/lib/libc/tests/sys/mlock_helper.c b/lib/libc/tests/sys/mlock_helper.c
index 31471b2b281c..e7a3d5e39c3f 100644
--- a/lib/libc/tests/sys/mlock_helper.c
+++ b/lib/libc/tests/sys/mlock_helper.c
@@ -1,112 +1,111 @@
/*-
* Copyright (C) 2016 Bryan Drewery <bdrewery@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* Helper for mlock(3) to avoid EAGAIN errors
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <atf-c.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#define VM_MAX_WIRED "vm.max_user_wired"
static void
vm_max_wired_sysctl(u_long *old_value, u_long *new_value)
{
size_t old_len;
size_t new_len = (new_value == NULL ? 0 : sizeof(*new_value));
if (old_value == NULL)
printf("Setting the new value to %lu\n", *new_value);
else {
ATF_REQUIRE_MSG(sysctlbyname(VM_MAX_WIRED, NULL, &old_len,
new_value, new_len) == 0,
"sysctlbyname(%s) failed: %s", VM_MAX_WIRED, strerror(errno));
}
ATF_REQUIRE_MSG(sysctlbyname(VM_MAX_WIRED, old_value, &old_len,
new_value, new_len) == 0,
"sysctlbyname(%s) failed: %s", VM_MAX_WIRED, strerror(errno));
if (old_value != NULL)
printf("Saved the old value (%lu)\n", *old_value);
}
void
set_vm_max_wired(u_long new_value)
{
FILE *fp;
u_long old_value;
fp = fopen(VM_MAX_WIRED, "w");
if (fp == NULL) {
atf_tc_skip("could not open %s for writing: %s",
VM_MAX_WIRED, strerror(errno));
return;
}
vm_max_wired_sysctl(&old_value, NULL);
ATF_REQUIRE_MSG(fprintf(fp, "%lu", old_value) > 0,
"saving %s failed", VM_MAX_WIRED);
fclose(fp);
vm_max_wired_sysctl(NULL, &new_value);
}
void
restore_vm_max_wired(void)
{
FILE *fp;
u_long saved_max_wired;
fp = fopen(VM_MAX_WIRED, "r");
if (fp == NULL) {
perror("fopen failed\n");
return;
}
if (fscanf(fp, "%lu", &saved_max_wired) != 1) {
perror("fscanf failed\n");
fclose(fp);
return;
}
fclose(fp);
printf("old value in %s: %lu\n", VM_MAX_WIRED, saved_max_wired);
if (saved_max_wired == 0) /* This will cripple the test host */
return;
vm_max_wired_sysctl(NULL, &saved_max_wired);
}
diff --git a/lib/libc/tests/sys/queue_test.c b/lib/libc/tests/sys/queue_test.c
index 8db5b5cae7b6..cfe9ac934cbd 100644
--- a/lib/libc/tests/sys/queue_test.c
+++ b/lib/libc/tests/sys/queue_test.c
@@ -1,235 +1,234 @@
/*-
* Copyright (c) 2015 EMC Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/queue.h>
#include <stdio.h>
#include <stdlib.h>
#include <atf-c.h>
ATF_TC(slist_test);
ATF_TC_HEAD(slist_test, tc)
{
atf_tc_set_md_var(tc, "descr", "SLIST macro feature tests");
}
ATF_TC_BODY(slist_test, tc)
{
SLIST_HEAD(stailhead, entry) head = SLIST_HEAD_INITIALIZER(head);
struct entry {
SLIST_ENTRY(entry) entries;
int i;
} *n1, *n2, *n3, *np;
int i, j, length;
SLIST_INIT(&head);
printf("Ensuring SLIST_EMPTY works\n");
ATF_REQUIRE(SLIST_EMPTY(&head));
i = length = 0;
SLIST_FOREACH(np, &head, entries) {
length++;
}
ATF_REQUIRE_EQ(length, 0);
printf("Ensuring SLIST_INSERT_HEAD works\n");
n1 = malloc(sizeof(struct entry));
ATF_REQUIRE(n1 != NULL);
n1->i = i++;
SLIST_INSERT_HEAD(&head, n1, entries);
printf("Ensuring SLIST_FIRST returns element 1\n");
ATF_REQUIRE_EQ(SLIST_FIRST(&head), n1);
j = length = 0;
SLIST_FOREACH(np, &head, entries) {
ATF_REQUIRE_EQ_MSG(np->i, j,
"%d (entry counter) != %d (counter)", np->i, j);
j++;
length++;
}
ATF_REQUIRE_EQ(length, 1);
printf("Ensuring SLIST_INSERT_AFTER works\n");
n2 = malloc(sizeof(struct entry));
ATF_REQUIRE(n2 != NULL);
n2->i = i++;
SLIST_INSERT_AFTER(n1, n2, entries);
n3 = malloc(sizeof(struct entry));
ATF_REQUIRE(n3 != NULL);
n3->i = i++;
SLIST_INSERT_AFTER(n2, n3, entries);
j = length = 0;
SLIST_FOREACH(np, &head, entries) {
ATF_REQUIRE_EQ_MSG(np->i, j,
"%d (entry counter) != %d (counter)", np->i, j);
j++;
length++;
}
ATF_REQUIRE_EQ(length, 3);
printf("Ensuring SLIST_REMOVE_HEAD works\n");
printf("Ensuring SLIST_FIRST returns element 1\n");
ATF_REQUIRE_EQ(SLIST_FIRST(&head), n1);
SLIST_REMOVE_HEAD(&head, entries);
printf("Ensuring SLIST_FIRST now returns element 2\n");
ATF_REQUIRE_EQ(SLIST_FIRST(&head), n2);
j = 1; /* Starting point's 1 this time */
length = 0;
SLIST_FOREACH(np, &head, entries) {
ATF_REQUIRE_EQ_MSG(np->i, j,
"%d (entry counter) != %d (counter)", np->i, j);
j++;
length++;
}
ATF_REQUIRE_EQ(length, 2);
printf("Ensuring SLIST_REMOVE_AFTER works by removing the tail\n");
SLIST_REMOVE_AFTER(n2, entries);
j = 1; /* Starting point's 1 this time */
length = 0;
SLIST_FOREACH(np, &head, entries) {
ATF_REQUIRE_EQ_MSG(np->i, j,
"%d (entry counter) != %d (counter)", np->i, j);
j++;
length++;
}
ATF_REQUIRE_EQ(length, 1);
printf("Ensuring SLIST_FIRST returns element 2\n");
ATF_REQUIRE_EQ(SLIST_FIRST(&head), n2);
}
ATF_TC(stailq_test);
ATF_TC_HEAD(stailq_test, tc)
{
atf_tc_set_md_var(tc, "descr", "STAILQ macro feature tests");
}
ATF_TC_BODY(stailq_test, tc)
{
STAILQ_HEAD(stailhead, entry) head = STAILQ_HEAD_INITIALIZER(head);
struct entry {
STAILQ_ENTRY(entry) entries;
int i;
} *n1, *n2, *n3, *np;
int i, j, length;
printf("Ensuring empty STAILQs are treated properly\n");
STAILQ_INIT(&head);
ATF_REQUIRE(STAILQ_EMPTY(&head));
i = length = 0;
STAILQ_FOREACH(np, &head, entries) {
length++;
}
ATF_REQUIRE_EQ(length, 0);
printf("Ensuring STAILQ_INSERT_HEAD works\n");
n1 = malloc(sizeof(struct entry));
ATF_REQUIRE(n1 != NULL);
n1->i = i++;
STAILQ_INSERT_HEAD(&head, n1, entries);
j = length = 0;
STAILQ_FOREACH(np, &head, entries) {
ATF_REQUIRE_EQ_MSG(np->i, j,
"%d (entry counter) != %d (counter)", np->i, j);
j++;
length++;
}
ATF_REQUIRE_EQ(length, 1);
printf("Ensuring STAILQ_INSERT_TAIL works\n");
n2 = malloc(sizeof(struct entry));
ATF_REQUIRE(n2 != NULL);
n2->i = i++;
STAILQ_INSERT_TAIL(&head, n2, entries);
n3 = malloc(sizeof(struct entry));
ATF_REQUIRE(n3 != NULL);
n3->i = i++;
STAILQ_INSERT_TAIL(&head, n3, entries);
j = length = 0;
STAILQ_FOREACH(np, &head, entries) {
ATF_REQUIRE_EQ_MSG(np->i, j,
"%d (entry counter) != %d (counter)", np->i, j);
j++;
length++;
}
ATF_REQUIRE_EQ(length, 3);
printf("Ensuring STAILQ_REMOVE_HEAD works\n");
STAILQ_REMOVE_HEAD(&head, entries);
j = 1; /* Starting point's 1 this time */
length = 0;
STAILQ_FOREACH(np, &head, entries) {
ATF_REQUIRE_EQ_MSG(np->i, j,
"%d (entry counter) != %d (counter)", np->i, j);
j++;
length++;
}
ATF_REQUIRE_EQ(length, 2);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, slist_test);
ATF_TP_ADD_TC(tp, stailq_test);
return (atf_no_error());
}
diff --git a/lib/libc/tests/sys/sendfile_test.c b/lib/libc/tests/sys/sendfile_test.c
index cfa885d1e8e3..d46e7b0cb186 100644
--- a/lib/libc/tests/sys/sendfile_test.c
+++ b/lib/libc/tests/sys/sendfile_test.c
@@ -1,1209 +1,1208 @@
/*-
* Copyright (c) 2018 Enji Cooper.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <sys/mman.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <sys/uio.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <atf-c.h>
const char DETERMINISTIC_PATTERN[] =
"The past is already gone, the future is not yet here. There's only one moment for you to live.\n";
#define SOURCE_FILE "source"
#define DESTINATION_FILE "dest"
#define PORTRANGE_FIRST "net.inet.ip.portrange.first"
#define PORTRANGE_LAST "net.inet.ip.portrange.last"
static int portrange_first, portrange_last;
static int
get_int_via_sysctlbyname(const char *oidname)
{
size_t oldlen;
int int_value;
oldlen = sizeof(int_value);
ATF_REQUIRE_EQ_MSG(sysctlbyname(oidname, &int_value, &oldlen, NULL, 0),
0, "sysctlbyname(%s, ...) failed: %s", oidname, strerror(errno));
ATF_REQUIRE_EQ_MSG(sizeof(int_value), oldlen, "sanity check failed");
return (int_value);
}
static int
generate_random_port(int seed)
{
int random_port;
printf("Generating a random port with seed=%d\n", seed);
if (portrange_first == 0) {
portrange_first = get_int_via_sysctlbyname(PORTRANGE_FIRST);
printf("Port range lower bound: %d\n", portrange_first);
}
if (portrange_last == 0) {
portrange_last = get_int_via_sysctlbyname(PORTRANGE_LAST);
printf("Port range upper bound: %d\n", portrange_last);
}
srand((unsigned)seed);
random_port = rand() % (portrange_last - portrange_first) +
portrange_first;
printf("Random port generated: %d\n", random_port);
return (random_port);
}
static void
resolve_localhost(struct addrinfo **res, int domain, int type, int port)
{
const char *host;
char *serv;
struct addrinfo hints;
int error;
switch (domain) {
case AF_INET:
host = "127.0.0.1";
break;
case AF_INET6:
host = "::1";
break;
default:
atf_tc_fail("unhandled domain: %d", domain);
}
ATF_REQUIRE_MSG(asprintf(&serv, "%d", port) >= 0,
"asprintf failed: %s", strerror(errno));
memset(&hints, 0, sizeof(hints));
hints.ai_family = domain;
hints.ai_flags = AI_ADDRCONFIG|AI_NUMERICSERV|AI_NUMERICHOST;
hints.ai_socktype = type;
error = getaddrinfo(host, serv, &hints, res);
ATF_REQUIRE_EQ_MSG(error, 0,
"getaddrinfo failed: %s", gai_strerror(error));
free(serv);
}
static int
make_socket(int domain, int type, int protocol)
{
int sock;
sock = socket(domain, type, protocol);
ATF_REQUIRE_MSG(sock != -1, "socket(%d, %d, 0) failed: %s",
domain, type, strerror(errno));
return (sock);
}
static int
setup_client(int domain, int type, int port)
{
struct addrinfo *res;
char host[NI_MAXHOST+1];
int error, sock;
resolve_localhost(&res, domain, type, port);
error = getnameinfo(
(const struct sockaddr*)res->ai_addr, res->ai_addrlen,
host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST);
ATF_REQUIRE_EQ_MSG(error, 0,
"getnameinfo failed: %s", gai_strerror(error));
printf(
"Will try to connect to host='%s', address_family=%d, "
"socket_type=%d\n",
host, res->ai_family, res->ai_socktype);
/* Avoid a double print when forked by flushing. */
fflush(stdout);
sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
error = connect(sock, (struct sockaddr*)res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
ATF_REQUIRE_EQ_MSG(error, 0, "connect failed: %s", strerror(errno));
return (sock);
}
/*
* XXX: use linear probing to find a free port and eliminate `port` argument as
* a [const] int (it will need to be a pointer so it can be passed back out of
* the function and can influence which port `setup_client(..)` connects on.
*/
static int
setup_server(int domain, int type, int port)
{
struct addrinfo *res;
char host[NI_MAXHOST+1];
int error, sock;
resolve_localhost(&res, domain, type, port);
sock = make_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
error = getnameinfo(
(const struct sockaddr*)res->ai_addr, res->ai_addrlen,
host, nitems(host) - 1, NULL, 0, NI_NUMERICHOST);
ATF_REQUIRE_EQ_MSG(error, 0,
"getnameinfo failed: %s", gai_strerror(error));
printf(
"Will try to bind socket to host='%s', address_family=%d, "
"socket_type=%d\n",
host, res->ai_family, res->ai_socktype);
/* Avoid a double print when forked by flushing. */
fflush(stdout);
error = bind(sock, res->ai_addr, res->ai_addrlen);
freeaddrinfo(res);
ATF_REQUIRE_EQ_MSG(error, 0, "bind failed: %s", strerror(errno));
error = listen(sock, 1);
ATF_REQUIRE_EQ_MSG(error, 0, "listen failed: %s", strerror(errno));
return (sock);
}
/*
* This function is a helper routine for taking data being sent by `sendfile` via
* `server_sock`, and pushing the received stream out to a file, denoted by
* `dest_filename`.
*/
static void
server_cat(const char *dest_filename, int server_sock, size_t len)
{
char *buffer, *buf_window_ptr;
int recv_sock;
size_t buffer_size;
ssize_t received_bytes, recv_ret;
/*
* Ensure that there isn't excess data sent across the wire by
* capturing 10 extra bytes (plus 1 for nul).
*/
buffer_size = len + 10 + 1;
buffer = calloc(buffer_size, sizeof(char));
if (buffer == NULL)
err(1, "malloc failed");
recv_sock = accept(server_sock, NULL, 0);
if (recv_sock == -1)
err(1, "accept failed");
buf_window_ptr = buffer;
received_bytes = 0;
do {
recv_ret = recv(recv_sock, buf_window_ptr,
buffer_size - received_bytes, 0);
if (recv_ret <= 0)
break;
buf_window_ptr += recv_ret;
received_bytes += recv_ret;
} while (received_bytes < buffer_size);
atf_utils_create_file(dest_filename, "%s", buffer);
(void)close(recv_sock);
(void)close(server_sock);
free(buffer);
if (received_bytes != len)
errx(1, "received unexpected data: %zd != %zd", received_bytes,
len);
}
static int
setup_tcp_server(int domain, int port)
{
return (setup_server(domain, SOCK_STREAM, port));
}
static int
setup_tcp_client(int domain, int port)
{
return (setup_client(domain, SOCK_STREAM, port));
}
static off_t
file_size_from_fd(int fd)
{
struct stat st;
ATF_REQUIRE_EQ_MSG(0, fstat(fd, &st),
"fstat failed: %s", strerror(errno));
return (st.st_size);
}
/*
* NB: `nbytes` == 0 has special connotations given the sendfile(2) API
* contract. In short, "send the whole file" (paraphrased).
*/
static void
verify_source_and_dest(const char* dest_filename, int src_fd, off_t offset,
size_t nbytes)
{
char *dest_pointer, *src_pointer;
off_t dest_file_size, src_file_size;
size_t length;
int dest_fd;
atf_utils_cat_file(dest_filename, "dest_file: ");
dest_fd = open(dest_filename, O_RDONLY);
ATF_REQUIRE_MSG(dest_fd != -1, "open failed");
dest_file_size = file_size_from_fd(dest_fd);
src_file_size = file_size_from_fd(src_fd);
/*
* Per sendfile(2), "send the whole file" (paraphrased). This means
* that we need to grab the file size, as passing in length = 0 with
* mmap(2) will result in a failure with EINVAL (length = 0 is invalid).
*/
length = (nbytes == 0) ? (size_t)(src_file_size - offset) : nbytes;
ATF_REQUIRE_EQ_MSG(dest_file_size, length,
"number of bytes written out to %s (%ju) doesn't match the "
"expected number of bytes (%zu)", dest_filename, dest_file_size,
length);
ATF_REQUIRE_EQ_MSG(0, lseek(src_fd, offset, SEEK_SET),
"lseek failed: %s", strerror(errno));
dest_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, dest_fd, 0);
ATF_REQUIRE_MSG(dest_pointer != MAP_FAILED, "mmap failed: %s",
strerror(errno));
printf("Will mmap in the source file from offset=%jd to length=%zu\n",
offset, length);
src_pointer = mmap(NULL, length, PROT_READ, MAP_PRIVATE, src_fd, offset);
ATF_REQUIRE_MSG(src_pointer != MAP_FAILED, "mmap failed: %s",
strerror(errno));
ATF_REQUIRE_EQ_MSG(0, memcmp(src_pointer, dest_pointer, length),
"Contents of source and destination do not match. '%s' != '%s'",
src_pointer, dest_pointer);
(void)munmap(src_pointer, length);
(void)munmap(dest_pointer, length);
(void)close(dest_fd);
}
static void
fd_positive_file_test(int domain)
{
off_t offset;
size_t nbytes, pattern_size;
int client_sock, error, fd, port, server_sock;
pid_t server_pid;
pattern_size = strlen(DETERMINISTIC_PATTERN);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock, pattern_size);
_exit(0);
} else
(void)close(server_sock);
nbytes = 0;
offset = 0;
error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
SF_FLAGS(0, 0));
ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
(void)close(fd);
}
ATF_TC(fd_positive_file_v4);
ATF_TC_HEAD(fd_positive_file_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify regular file as file descriptor support (IPv4)");
}
ATF_TC_BODY(fd_positive_file_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
fd_positive_file_test(AF_INET);
}
ATF_TC(fd_positive_file_v6);
ATF_TC_HEAD(fd_positive_file_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify regular file as file descriptor support (IPv6)");
}
ATF_TC_BODY(fd_positive_file_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
fd_positive_file_test(AF_INET6);
}
static void
fd_positive_shm_test(int domain)
{
char *shm_pointer;
off_t offset;
size_t nbytes, pattern_size;
pid_t server_pid;
int client_sock, error, fd, port, server_sock;
pattern_size = strlen(DETERMINISTIC_PATTERN);
printf("pattern size: %zu\n", pattern_size);
fd = shm_open(SHM_ANON, O_RDWR|O_CREAT, 0600);
ATF_REQUIRE_MSG(fd != -1, "shm_open failed: %s", strerror(errno));
ATF_REQUIRE_EQ_MSG(0, ftruncate(fd, pattern_size),
"ftruncate failed: %s", strerror(errno));
shm_pointer = mmap(NULL, pattern_size, PROT_READ|PROT_WRITE,
MAP_SHARED, fd, 0);
ATF_REQUIRE_MSG(shm_pointer != MAP_FAILED,
"mmap failed: %s", strerror(errno));
memcpy(shm_pointer, DETERMINISTIC_PATTERN, pattern_size);
ATF_REQUIRE_EQ_MSG(0,
memcmp(shm_pointer, DETERMINISTIC_PATTERN, pattern_size),
"memcmp showed data mismatch: '%s' != '%s'",
DETERMINISTIC_PATTERN, shm_pointer);
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock, pattern_size);
_exit(0);
} else
(void)close(server_sock);
nbytes = 0;
offset = 0;
error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
SF_FLAGS(0, 0));
ATF_REQUIRE_EQ_MSG(0, error, "sendfile failed: %s", strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
(void)munmap(shm_pointer, sizeof(DETERMINISTIC_PATTERN));
(void)close(fd);
}
ATF_TC(fd_positive_shm_v4);
ATF_TC_HEAD(fd_positive_shm_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify shared memory as file descriptor support (IPv4)");
}
ATF_TC_BODY(fd_positive_shm_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
fd_positive_shm_test(AF_INET);
}
ATF_TC(fd_positive_shm_v6);
ATF_TC_HEAD(fd_positive_shm_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify shared memory as file descriptor support (IPv6))");
}
ATF_TC_BODY(fd_positive_shm_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
fd_positive_shm_test(AF_INET6);
}
static void
fd_negative_bad_fd_test(int domain)
{
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
fd = -1;
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EBADF, error == -1);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(fd_negative_bad_fd_v4);
ATF_TC_HEAD(fd_negative_bad_fd_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify bad file descriptor returns EBADF (IPv4)");
}
ATF_TC_BODY(fd_negative_bad_fd_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
fd_negative_bad_fd_test(AF_INET);
}
ATF_TC(fd_negative_bad_fd_v6);
ATF_TC_HEAD(fd_negative_bad_fd_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify bad file descriptor returns EBADF (IPv6)");
}
ATF_TC_BODY(fd_negative_bad_fd_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
fd_negative_bad_fd_test(AF_INET6);
}
static void
flags_test(int domain)
{
off_t offset;
size_t nbytes, pattern_size;
int client_sock, error, fd, i, port, server_sock;
pid_t server_pid;
int16_t number_pages = 10;
pattern_size = strlen(DETERMINISTIC_PATTERN);
struct testcase {
int16_t readahead_pages, flags;
} testcases[] = {
/* This is covered in `:fd_positive_file` */
#if 0
{
.readahead_pages = 0,
.flags = 0
},
#endif
{
.readahead_pages = 0,
.flags = SF_NOCACHE
},
#ifdef SF_USER_READAHEAD
{
.readahead_pages = 0,
.flags = SF_NOCACHE|SF_USER_READAHEAD
},
{
.readahead_pages = 0,
.flags = SF_USER_READAHEAD
},
#endif
{
.readahead_pages = number_pages,
.flags = 0
},
{
.readahead_pages = number_pages,
.flags = SF_NOCACHE
},
#ifdef SF_USER_READAHEAD
{
.readahead_pages = number_pages,
.flags = SF_NOCACHE|SF_USER_READAHEAD
},
#endif
{
.readahead_pages = number_pages,
.flags = SF_NOCACHE
},
{
.readahead_pages = number_pages,
.flags = SF_NODISKIO
}
};
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
for (i = 0; i < nitems(testcases); i++) {
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
port = generate_random_port(i * __LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock, pattern_size);
_exit(0);
} else
(void)close(server_sock);
nbytes = 0;
offset = 0;
error = sendfile(fd, client_sock, offset, nbytes, NULL, NULL,
SF_FLAGS(testcases[i].readahead_pages, testcases[i].flags));
ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s",
i, strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd, offset, nbytes);
(void)close(fd);
}
}
ATF_TC(flags_v4);
ATF_TC_HEAD(flags_v4, tc)
{
atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv4)");
}
ATF_TC_BODY(flags_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
flags_test(AF_INET);
}
ATF_TC(flags_v6);
ATF_TC_HEAD(flags_v6, tc)
{
atf_tc_set_md_var(tc, "descr", "Verify flags functionality (IPv6)");
}
ATF_TC_BODY(flags_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
flags_test(AF_INET6);
}
static void
hdtr_positive_test(int domain)
{
struct iovec headers[1], trailers[1];
struct testcase {
bool include_headers, include_trailers;
} testcases[] = {
/* This is covered in `:fd_positive_file` */
#if 0
{
.include_headers = false,
.include_trailers = false
},
#endif
{
.include_headers = true,
.include_trailers = false
},
{
.include_headers = false,
.include_trailers = true
},
{
.include_headers = true,
.include_trailers = true
}
};
off_t offset;
size_t nbytes;
int client_sock, error, fd, fd2, i, port, rc, server_sock;
pid_t server_pid;
headers[0].iov_base = "This is a header";
headers[0].iov_len = strlen(headers[0].iov_base);
trailers[0].iov_base = "This is a trailer";
trailers[0].iov_len = strlen(trailers[0].iov_base);
offset = 0;
nbytes = 0;
for (i = 0; i < nitems(testcases); i++) {
struct sf_hdtr hdtr;
char *pattern;
if (testcases[i].include_headers) {
hdtr.headers = headers;
hdtr.hdr_cnt = nitems(headers);
} else {
hdtr.headers = NULL;
hdtr.hdr_cnt = 0;
}
if (testcases[i].include_trailers) {
hdtr.trailers = trailers;
hdtr.trl_cnt = nitems(trailers);
} else {
hdtr.trailers = NULL;
hdtr.trl_cnt = 0;
}
port = generate_random_port(i * __LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
rc = asprintf(&pattern, "%s%s%s",
testcases[i].include_headers ? (char *)headers[0].iov_base : "",
DETERMINISTIC_PATTERN,
testcases[i].include_trailers ? (char *)trailers[0].iov_base : "");
ATF_REQUIRE_MSG(rc != -1, "asprintf failed: %s", strerror(errno));
atf_utils_create_file(SOURCE_FILE ".full", "%s", pattern);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
fd2 = open(SOURCE_FILE ".full", O_RDONLY);
ATF_REQUIRE_MSG(fd2 != -1, "open failed: %s", strerror(errno));
server_pid = atf_utils_fork();
if (server_pid == 0) {
(void)close(client_sock);
server_cat(DESTINATION_FILE, server_sock,
strlen(pattern));
_exit(0);
} else
(void)close(server_sock);
error = sendfile(fd, client_sock, offset, nbytes, &hdtr,
NULL, SF_FLAGS(0, 0));
ATF_CHECK_EQ_MSG(error, 0, "sendfile testcase #%d failed: %s",
i, strerror(errno));
(void)close(client_sock);
atf_utils_wait(server_pid, 0, "", "");
verify_source_and_dest(DESTINATION_FILE, fd2, offset, nbytes);
(void)close(fd);
(void)close(fd2);
free(pattern);
pattern = NULL;
}
}
ATF_TC(hdtr_positive_v4);
ATF_TC_HEAD(hdtr_positive_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive hdtr functionality (IPv4)");
}
ATF_TC_BODY(hdtr_positive_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
hdtr_positive_test(AF_INET);
}
ATF_TC(hdtr_positive_v6);
ATF_TC_HEAD(hdtr_positive_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive hdtr functionality (IPv6)");
}
ATF_TC_BODY(hdtr_positive_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
hdtr_positive_test(AF_INET);
}
static void
hdtr_negative_bad_pointers_test(int domain)
{
int client_sock, error, fd, port, server_sock;
struct sf_hdtr *hdtr1, hdtr2, hdtr3;
port = generate_random_port(__LINE__ + domain);
hdtr1 = (struct sf_hdtr*)-1;
memset(&hdtr2, 0, sizeof(hdtr2));
hdtr2.hdr_cnt = 1;
hdtr2.headers = (struct iovec*)-1;
memset(&hdtr3, 0, sizeof(hdtr3));
hdtr3.trl_cnt = 1;
hdtr3.trailers = (struct iovec*)-1;
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
error = sendfile(fd, client_sock, 0, 0, hdtr1, NULL, SF_FLAGS(0, 0));
ATF_CHECK_ERRNO(EFAULT, error == -1);
error = sendfile(fd, client_sock, 0, 0, &hdtr2, NULL, SF_FLAGS(0, 0));
ATF_CHECK_ERRNO(EFAULT, error == -1);
error = sendfile(fd, client_sock, 0, 0, &hdtr3, NULL, SF_FLAGS(0, 0));
ATF_CHECK_ERRNO(EFAULT, error == -1);
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(hdtr_negative_bad_pointers_v4);
ATF_TC_HEAD(hdtr_negative_bad_pointers_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that bad pointers for hdtr storage result in EFAULT (IPv4)");
}
ATF_TC_BODY(hdtr_negative_bad_pointers_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
hdtr_negative_bad_pointers_test(AF_INET);
}
ATF_TC(hdtr_negative_bad_pointers_v6);
ATF_TC_HEAD(hdtr_negative_bad_pointers_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that bad pointers for hdtr storage result in EFAULT (IPv6)");
}
ATF_TC_BODY(hdtr_negative_bad_pointers_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
hdtr_negative_bad_pointers_test(AF_INET6);
}
static void
offset_negative_value_less_than_zero_test(int domain)
{
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, -1, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(offset_negative_value_less_than_zero_v4);
ATF_TC_HEAD(offset_negative_value_less_than_zero_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a negative offset results in EINVAL (IPv4)");
}
ATF_TC_BODY(offset_negative_value_less_than_zero_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
offset_negative_value_less_than_zero_test(AF_INET);
}
ATF_TC(offset_negative_value_less_than_zero_v6);
ATF_TC_HEAD(offset_negative_value_less_than_zero_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a negative offset results in EINVAL (IPv6)");
}
ATF_TC_BODY(offset_negative_value_less_than_zero_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
offset_negative_value_less_than_zero_test(AF_INET6);
}
static void
sbytes_positive_test(int domain)
{
size_t pattern_size = strlen(DETERMINISTIC_PATTERN);
off_t sbytes;
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, &sbytes, SF_FLAGS(0, 0));
ATF_CHECK_EQ_MSG(error, 0, "sendfile failed: %s", strerror(errno));
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
ATF_CHECK_EQ_MSG(pattern_size, sbytes,
"the value returned by sbytes does not match the expected pattern "
"size");
}
ATF_TC(sbytes_positive_v4);
ATF_TC_HEAD(sbytes_positive_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive `sbytes` functionality (IPv4)");
}
ATF_TC_BODY(sbytes_positive_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
sbytes_positive_test(AF_INET);
}
ATF_TC(sbytes_positive_v6);
ATF_TC_HEAD(sbytes_positive_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify positive `sbytes` functionality (IPv6)");
}
ATF_TC_BODY(sbytes_positive_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
sbytes_positive_test(AF_INET6);
}
static void
sbytes_negative_test(int domain)
{
off_t *sbytes_p = (off_t*)-1;
int client_sock, error, fd, port, server_sock;
port = generate_random_port(__LINE__ + domain);
server_sock = setup_tcp_server(domain, port);
client_sock = setup_tcp_client(domain, port);
atf_utils_create_file(SOURCE_FILE, "%s", DETERMINISTIC_PATTERN);
fd = open(SOURCE_FILE, O_RDONLY);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
atf_tc_expect_fail(
"bug 232210: EFAULT assert fails because copyout(9) call is not checked");
error = sendfile(fd, client_sock, 0, 0, NULL, sbytes_p, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EFAULT, error == -1);
(void)close(fd);
(void)close(client_sock);
(void)close(server_sock);
}
ATF_TC(sbytes_negative_v4);
ATF_TC_HEAD(sbytes_negative_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify negative `sbytes` functionality (IPv4)");
}
ATF_TC_BODY(sbytes_negative_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
sbytes_negative_test(AF_INET);
}
ATF_TC(sbytes_negative_v6);
ATF_TC_HEAD(sbytes_negative_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify negative `sbytes` functionality (IPv6)");
}
ATF_TC_BODY(sbytes_negative_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
sbytes_negative_test(AF_INET6);
}
static void
s_negative_not_connected_socket_test(int domain)
{
int client_sock, error, fd, port;
port = generate_random_port(__LINE__ + domain);
client_sock = setup_tcp_server(domain, port);
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(ENOTCONN, error == -1);
(void)close(fd);
(void)close(client_sock);
}
ATF_TC(s_negative_not_connected_socket_v4);
ATF_TC_HEAD(s_negative_not_connected_socket_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv4)");
}
ATF_TC_BODY(s_negative_not_connected_socket_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
s_negative_not_connected_socket_test(AF_INET);
}
ATF_TC(s_negative_not_connected_socket_v6);
ATF_TC_HEAD(s_negative_not_connected_socket_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-connected SOCK_STREAM socket results in ENOTCONN (IPv6)");
}
ATF_TC_BODY(s_negative_not_connected_socket_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
s_negative_not_connected_socket_test(AF_INET6);
}
ATF_TC(s_negative_not_descriptor);
ATF_TC_HEAD(s_negative_not_descriptor, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that an invalid file descriptor, e.g., -1, fails with EBADF");
}
ATF_TC_BODY(s_negative_not_descriptor, tc)
{
int client_sock, error, fd;
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
client_sock = -1;
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EBADF, error == -1);
(void)close(fd);
}
ATF_TC(s_negative_not_socket_file_descriptor);
ATF_TC_HEAD(s_negative_not_socket_file_descriptor, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-socket file descriptor fails with ENOTSOCK");
}
ATF_TC_BODY(s_negative_not_socket_file_descriptor, tc)
{
int client_sock, error, fd;
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
client_sock = open(_PATH_DEVNULL, O_WRONLY);
ATF_REQUIRE_MSG(client_sock != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(ENOTSOCK, error == -1);
(void)close(fd);
(void)close(client_sock);
}
static void
s_negative_udp_socket_test(int domain)
{
int client_sock, error, fd, port;
port = generate_random_port(__LINE__ + domain);
client_sock = setup_client(domain, SOCK_DGRAM, port);
fd = open(SOURCE_FILE, O_CREAT|O_RDWR, 0600);
ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno));
error = sendfile(fd, client_sock, 0, 0, NULL, NULL, SF_FLAGS(0, 0));
ATF_REQUIRE_ERRNO(EINVAL, error == -1);
(void)close(fd);
(void)close(client_sock);
}
ATF_TC(s_negative_udp_socket_v4);
ATF_TC_HEAD(s_negative_udp_socket_v4, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv4)");
}
ATF_TC_BODY(s_negative_udp_socket_v4, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
s_negative_udp_socket_test(AF_INET);
}
ATF_TC(s_negative_udp_socket_v6);
ATF_TC_HEAD(s_negative_udp_socket_v6, tc)
{
atf_tc_set_md_var(tc, "descr",
"Verify that a non-SOCK_STREAM type socket results in EINVAL (IPv6)");
}
ATF_TC_BODY(s_negative_udp_socket_v6, tc)
{
if (atf_tc_get_config_var_as_bool_wd(tc, "qemu", false))
atf_tc_skip("Sendfile(4) unimplemented. https://github.com/qemu-bsd-user/qemu-bsd-user/issues/25");
s_negative_udp_socket_test(AF_INET6);
}
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, fd_positive_file_v4);
ATF_TP_ADD_TC(tp, fd_positive_file_v6);
ATF_TP_ADD_TC(tp, fd_positive_shm_v4);
ATF_TP_ADD_TC(tp, fd_positive_shm_v6);
ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v4);
ATF_TP_ADD_TC(tp, fd_negative_bad_fd_v6);
ATF_TP_ADD_TC(tp, flags_v4);
ATF_TP_ADD_TC(tp, flags_v6);
/*
* TODO: the negative case for SF_NODISKIO (returns EBUSY if file in
* use) is not covered yet.
*
* Need to lock a file in a subprocess in write mode, then try and
* send the data in read mode with sendfile.
*
* This should work with FFS/UFS, but there are no guarantees about
* other filesystem implementations of sendfile(2), e.g., ZFS.
*/
ATF_TP_ADD_TC(tp, hdtr_positive_v4);
ATF_TP_ADD_TC(tp, hdtr_positive_v6);
ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v4);
ATF_TP_ADD_TC(tp, hdtr_negative_bad_pointers_v6);
ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v4);
ATF_TP_ADD_TC(tp, offset_negative_value_less_than_zero_v6);
ATF_TP_ADD_TC(tp, sbytes_positive_v4);
ATF_TP_ADD_TC(tp, sbytes_positive_v6);
ATF_TP_ADD_TC(tp, sbytes_negative_v4);
ATF_TP_ADD_TC(tp, sbytes_negative_v6);
ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v4);
ATF_TP_ADD_TC(tp, s_negative_not_connected_socket_v6);
ATF_TP_ADD_TC(tp, s_negative_not_descriptor);
ATF_TP_ADD_TC(tp, s_negative_not_socket_file_descriptor);
ATF_TP_ADD_TC(tp, s_negative_udp_socket_v4);
ATF_TP_ADD_TC(tp, s_negative_udp_socket_v6);
return (atf_no_error());
}
diff --git a/lib/libc/uuid/uuid_stream.c b/lib/libc/uuid/uuid_stream.c
index 996b74de3250..cd5a35655f0f 100644
--- a/lib/libc/uuid/uuid_stream.c
+++ b/lib/libc/uuid/uuid_stream.c
@@ -1,113 +1,112 @@
/* $NetBSD: uuid_stream.c,v 1.3 2008/04/19 18:21:38 plunky Exp $ */
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2002 Marcel Moolenaar
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/endian.h>
#include <uuid.h>
/*
* Encode/Decode UUID into octet-stream.
* http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | time_low |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | time_mid | time_hi_and_version |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* |clk_seq_hi_res | clk_seq_low | node (0-1) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | node (2-5) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*
* NOTE: These routines are not part of the DCE RPC API. They are
* provided for convenience.
*/
void
uuid_enc_le(void *buf, const uuid_t *uuid)
{
uint8_t *p = buf;
int i;
le32enc(p, uuid->time_low);
le16enc(p + 4, uuid->time_mid);
le16enc(p + 6, uuid->time_hi_and_version);
p[8] = uuid->clock_seq_hi_and_reserved;
p[9] = uuid->clock_seq_low;
for (i = 0; i < _UUID_NODE_LEN; i++)
p[10 + i] = uuid->node[i];
}
void
uuid_dec_le(const void *buf, uuid_t *uuid)
{
const uint8_t *p = buf;
int i;
uuid->time_low = le32dec(p);
uuid->time_mid = le16dec(p + 4);
uuid->time_hi_and_version = le16dec(p + 6);
uuid->clock_seq_hi_and_reserved = p[8];
uuid->clock_seq_low = p[9];
for (i = 0; i < _UUID_NODE_LEN; i++)
uuid->node[i] = p[10 + i];
}
void
uuid_enc_be(void *buf, const uuid_t *uuid)
{
uint8_t *p = buf;
int i;
be32enc(p, uuid->time_low);
be16enc(p + 4, uuid->time_mid);
be16enc(p + 6, uuid->time_hi_and_version);
p[8] = uuid->clock_seq_hi_and_reserved;
p[9] = uuid->clock_seq_low;
for (i = 0; i < _UUID_NODE_LEN; i++)
p[10 + i] = uuid->node[i];
}
void
uuid_dec_be(const void *buf, uuid_t *uuid)
{
const uint8_t *p = buf;
int i;
uuid->time_low = be32dec(p);
uuid->time_mid = be16dec(p + 4);
uuid->time_hi_and_version = be16dec(p + 6);
uuid->clock_seq_hi_and_reserved = p[8];
uuid->clock_seq_low = p[9];
for (i = 0; i < _UUID_NODE_LEN; i++)
uuid->node[i] = p[10 + i];
}
diff --git a/lib/libc/x86/gen/getcontextx.c b/lib/libc/x86/gen/getcontextx.c
index d50180a8ac6c..7373ae7395b9 100644
--- a/lib/libc/x86/gen/getcontextx.c
+++ b/lib/libc/x86/gen/getcontextx.c
@@ -1,138 +1,137 @@
/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/ucontext.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <x86/ifunc.h>
#include <x86/fpu.h>
#if defined __i386__
#define X86_GET_XFPUSTATE I386_GET_XFPUSTATE
typedef struct savexmm savex86_t ;
typedef struct i386_get_xfpustate x86_get_xfpustate_t;
#elif defined __amd64__
#define X86_GET_XFPUSTATE AMD64_GET_XFPUSTATE
typedef struct savefpu savex86_t;
typedef struct amd64_get_xfpustate x86_get_xfpustate_t;
#else
#error "Wrong arch"
#endif
static int xstate_sz = 0;
static int
__getcontextx_size_xfpu(void)
{
return (sizeof(ucontext_t) + xstate_sz);
}
DEFINE_UIFUNC(, int, __getcontextx_size, (void))
{
u_int p[4];
if ((cpu_feature2 & CPUID2_OSXSAVE) != 0) {
cpuid_count(0xd, 0x0, p);
xstate_sz = p[1] - sizeof(savex86_t);
}
return (__getcontextx_size_xfpu);
}
static int
__fillcontextx2_xfpu(char *ctx)
{
x86_get_xfpustate_t xfpu;
ucontext_t *ucp;
ucp = (ucontext_t *)ctx;
xfpu.addr = (char *)(ucp + 1);
xfpu.len = xstate_sz;
if (sysarch(X86_GET_XFPUSTATE, &xfpu) == -1)
return (-1);
ucp->uc_mcontext.mc_xfpustate = (__register_t)xfpu.addr;
ucp->uc_mcontext.mc_xfpustate_len = xstate_sz;
ucp->uc_mcontext.mc_flags |= _MC_HASFPXSTATE;
return (0);
}
static int
__fillcontextx2_noxfpu(char *ctx)
{
ucontext_t *ucp;
ucp = (ucontext_t *)ctx;
ucp->uc_mcontext.mc_xfpustate = 0;
ucp->uc_mcontext.mc_xfpustate_len = 0;
return (0);
}
DEFINE_UIFUNC(, int, __fillcontextx2, (char *))
{
return ((cpu_feature2 & CPUID2_OSXSAVE) != 0 ? __fillcontextx2_xfpu :
__fillcontextx2_noxfpu);
}
int
__fillcontextx(char *ctx)
{
ucontext_t *ucp;
ucp = (ucontext_t *)ctx;
if (getcontext(ucp) == -1)
return (-1);
__fillcontextx2(ctx);
return (0);
}
__weak_reference(__getcontextx, getcontextx);
ucontext_t *
__getcontextx(void)
{
char *ctx;
int error;
ctx = malloc(__getcontextx_size());
if (ctx == NULL)
return (NULL);
if (__fillcontextx(ctx) == -1) {
error = errno;
free(ctx);
errno = error;
return (NULL);
}
return ((ucontext_t *)ctx);
}
diff --git a/lib/libc/x86/sys/__vdso_gettc.c b/lib/libc/x86/sys/__vdso_gettc.c
index 11632677e577..ea05f5abf62a 100644
--- a/lib/libc/x86/sys/__vdso_gettc.c
+++ b/lib/libc/x86/sys/__vdso_gettc.c
@@ -1,454 +1,453 @@
/*-
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
* Copyright (c) 2016, 2017, 2019 The FreeBSD Foundation
* All rights reserved.
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include "namespace.h"
#include <sys/capsicum.h>
#include <sys/elf.h>
#include <sys/fcntl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/vdso.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include "un-namespace.h"
#include <machine/atomic.h>
#include <machine/cpufunc.h>
#include <machine/pvclock.h>
#include <machine/specialreg.h>
#include <dev/acpica/acpi_hpet.h>
#ifdef WANT_HYPERV
#include <dev/hyperv/hyperv.h>
#endif
#include <x86/ifunc.h>
#include "libc_private.h"
static inline u_int
rdtsc_low(const struct vdso_timehands *th)
{
u_int rv;
__asm __volatile("rdtsc; shrd %%cl, %%edx, %0"
: "=a" (rv) : "c" (th->th_x86_shift) : "edx");
return (rv);
}
static inline u_int
rdtscp_low(const struct vdso_timehands *th)
{
u_int rv;
__asm __volatile("rdtscp; movl %%edi,%%ecx; shrd %%cl, %%edx, %0"
: "=a" (rv) : "D" (th->th_x86_shift) : "ecx", "edx");
return (rv);
}
static u_int
rdtsc_low_mb_lfence(const struct vdso_timehands *th)
{
lfence();
return (rdtsc_low(th));
}
static u_int
rdtsc_low_mb_mfence(const struct vdso_timehands *th)
{
mfence();
return (rdtsc_low(th));
}
static u_int
rdtsc_low_mb_none(const struct vdso_timehands *th)
{
return (rdtsc_low(th));
}
static u_int
rdtsc32_mb_lfence(void)
{
lfence();
return (rdtsc32());
}
static uint64_t
rdtsc_mb_lfence(void)
{
lfence();
return (rdtsc());
}
static u_int
rdtsc32_mb_mfence(void)
{
mfence();
return (rdtsc32());
}
static uint64_t
rdtsc_mb_mfence(void)
{
mfence();
return (rdtsc());
}
static u_int
rdtsc32_mb_none(void)
{
return (rdtsc32());
}
static uint64_t
rdtsc_mb_none(void)
{
return (rdtsc());
}
static u_int
rdtscp32_(void)
{
return (rdtscp32());
}
static uint64_t
rdtscp_(void)
{
return (rdtscp());
}
struct tsc_selector_tag {
u_int (*ts_rdtsc32)(void);
uint64_t (*ts_rdtsc)(void);
u_int (*ts_rdtsc_low)(const struct vdso_timehands *);
};
static const struct tsc_selector_tag tsc_selector[] = {
[0] = { /* Intel, LFENCE */
.ts_rdtsc32 = rdtsc32_mb_lfence,
.ts_rdtsc = rdtsc_mb_lfence,
.ts_rdtsc_low = rdtsc_low_mb_lfence,
},
[1] = { /* AMD, MFENCE */
.ts_rdtsc32 = rdtsc32_mb_mfence,
.ts_rdtsc = rdtsc_mb_mfence,
.ts_rdtsc_low = rdtsc_low_mb_mfence,
},
[2] = { /* No SSE2 */
.ts_rdtsc32 = rdtsc32_mb_none,
.ts_rdtsc = rdtsc_mb_none,
.ts_rdtsc_low = rdtsc_low_mb_none,
},
[3] = { /* RDTSCP */
.ts_rdtsc32 = rdtscp32_,
.ts_rdtsc = rdtscp_,
.ts_rdtsc_low = rdtscp_low,
},
};
static int
tsc_selector_idx(u_int cpu_feature)
{
u_int amd_feature, cpu_exthigh, p[4], v[3];
static const char amd_id[] = "AuthenticAMD";
static const char hygon_id[] = "HygonGenuine";
bool amd_cpu;
if (cpu_feature == 0)
return (2); /* should not happen due to RDTSC */
do_cpuid(0, p);
v[0] = p[1];
v[1] = p[3];
v[2] = p[2];
amd_cpu = memcmp(v, amd_id, sizeof(amd_id) - 1) == 0 ||
memcmp(v, hygon_id, sizeof(hygon_id) - 1) == 0;
if (cpu_feature != 0) {
do_cpuid(0x80000000, p);
cpu_exthigh = p[0];
} else {
cpu_exthigh = 0;
}
if (cpu_exthigh >= 0x80000001) {
do_cpuid(0x80000001, p);
amd_feature = p[3];
} else {
amd_feature = 0;
}
if ((amd_feature & AMDID_RDTSCP) != 0)
return (3);
if ((cpu_feature & CPUID_SSE2) == 0)
return (2);
return (amd_cpu ? 1 : 0);
}
DEFINE_UIFUNC(static, u_int, __vdso_gettc_rdtsc_low,
(const struct vdso_timehands *th))
{
return (tsc_selector[tsc_selector_idx(cpu_feature)].ts_rdtsc_low);
}
DEFINE_UIFUNC(static, u_int, __vdso_gettc_rdtsc32, (void))
{
return (tsc_selector[tsc_selector_idx(cpu_feature)].ts_rdtsc32);
}
DEFINE_UIFUNC(static, uint64_t, __vdso_gettc_rdtsc, (void))
{
return (tsc_selector[tsc_selector_idx(cpu_feature)].ts_rdtsc);
}
#define HPET_DEV_MAP_MAX 10
static volatile char *hpet_dev_map[HPET_DEV_MAP_MAX];
static void
__vdso_init_hpet(uint32_t u)
{
static const char devprefix[] = "/dev/hpet";
char devname[64], *c, *c1, t;
volatile char *new_map, *old_map;
unsigned int mode;
uint32_t u1;
int fd;
c1 = c = stpcpy(devname, devprefix);
u1 = u;
do {
*c++ = u1 % 10 + '0';
u1 /= 10;
} while (u1 != 0);
*c = '\0';
for (c--; c1 != c; c1++, c--) {
t = *c1;
*c1 = *c;
*c = t;
}
old_map = hpet_dev_map[u];
if (old_map != NULL)
return;
/*
* Explicitely check for the capability mode to avoid
* triggering trap_enocap on the device open by absolute path.
*/
if ((cap_getmode(&mode) == 0 && mode != 0) ||
(fd = _open(devname, O_RDONLY | O_CLOEXEC)) == -1) {
/* Prevent the caller from re-entering. */
atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u],
(uintptr_t)old_map, (uintptr_t)MAP_FAILED);
return;
}
new_map = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
_close(fd);
if (atomic_cmpset_rel_ptr((volatile uintptr_t *)&hpet_dev_map[u],
(uintptr_t)old_map, (uintptr_t)new_map) == 0 &&
new_map != MAP_FAILED)
munmap((void *)new_map, PAGE_SIZE);
}
#ifdef WANT_HYPERV
#define HYPERV_REFTSC_DEVPATH "/dev/" HYPERV_REFTSC_DEVNAME
/*
* NOTE:
* We use 'NULL' for this variable to indicate that initialization
* is required. And if this variable is 'MAP_FAILED', then Hyper-V
* reference TSC can not be used, e.g. in misconfigured jail.
*/
static struct hyperv_reftsc *hyperv_ref_tsc;
static void
__vdso_init_hyperv_tsc(void)
{
int fd;
unsigned int mode;
if (cap_getmode(&mode) == 0 && mode != 0)
goto fail;
fd = _open(HYPERV_REFTSC_DEVPATH, O_RDONLY | O_CLOEXEC);
if (fd < 0)
goto fail;
hyperv_ref_tsc = mmap(NULL, sizeof(*hyperv_ref_tsc), PROT_READ,
MAP_SHARED, fd, 0);
_close(fd);
return;
fail:
/* Prevent the caller from re-entering. */
hyperv_ref_tsc = MAP_FAILED;
}
static int
__vdso_hyperv_tsc(struct hyperv_reftsc *tsc_ref, u_int *tc)
{
uint64_t disc, ret, tsc, scale;
uint32_t seq;
int64_t ofs;
while ((seq = atomic_load_acq_int(&tsc_ref->tsc_seq)) != 0) {
scale = tsc_ref->tsc_scale;
ofs = tsc_ref->tsc_ofs;
mfence(); /* XXXKIB */
tsc = rdtsc();
/* ret = ((tsc * scale) >> 64) + ofs */
__asm__ __volatile__ ("mulq %3" :
"=d" (ret), "=a" (disc) :
"a" (tsc), "r" (scale));
ret += ofs;
atomic_thread_fence_acq();
if (tsc_ref->tsc_seq == seq) {
*tc = ret;
return (0);
}
/* Sequence changed; re-sync. */
}
return (ENOSYS);
}
#endif /* WANT_HYPERV */
static struct pvclock_vcpu_time_info *pvclock_timeinfos;
static int
__vdso_pvclock_gettc(const struct vdso_timehands *th, u_int *tc)
{
uint64_t delta, ns, tsc;
struct pvclock_vcpu_time_info *ti;
uint32_t cpuid_ti, cpuid_tsc, version;
bool stable;
do {
ti = &pvclock_timeinfos[0];
version = atomic_load_acq_32(&ti->version);
stable = (ti->flags & th->th_x86_pvc_stable_mask) != 0;
if (stable) {
tsc = __vdso_gettc_rdtsc();
} else {
(void)rdtscp_aux(&cpuid_ti);
ti = &pvclock_timeinfos[cpuid_ti];
version = atomic_load_acq_32(&ti->version);
tsc = rdtscp_aux(&cpuid_tsc);
}
delta = tsc - ti->tsc_timestamp;
ns = ti->system_time + pvclock_scale_delta(delta,
ti->tsc_to_system_mul, ti->tsc_shift);
atomic_thread_fence_acq();
} while ((ti->version & 1) != 0 || ti->version != version ||
(!stable && cpuid_ti != cpuid_tsc));
*tc = MAX(ns, th->th_x86_pvc_last_systime);
return (0);
}
static void
__vdso_init_pvclock_timeinfos(void)
{
struct pvclock_vcpu_time_info *timeinfos;
size_t len;
int fd, ncpus;
unsigned int mode;
timeinfos = MAP_FAILED;
if (_elf_aux_info(AT_NCPUS, &ncpus, sizeof(ncpus)) != 0 ||
(cap_getmode(&mode) == 0 && mode != 0) ||
(fd = _open("/dev/" PVCLOCK_CDEVNAME, O_RDONLY | O_CLOEXEC)) < 0)
goto leave;
len = ncpus * sizeof(*pvclock_timeinfos);
timeinfos = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
_close(fd);
leave:
if (atomic_cmpset_rel_ptr(
(volatile uintptr_t *)&pvclock_timeinfos, (uintptr_t)NULL,
(uintptr_t)timeinfos) == 0 && timeinfos != MAP_FAILED)
(void)munmap((void *)timeinfos, len);
}
#pragma weak __vdso_gettc
int
__vdso_gettc(const struct vdso_timehands *th, u_int *tc)
{
volatile char *map;
uint32_t idx;
switch (th->th_algo) {
case VDSO_TH_ALGO_X86_TSC:
*tc = th->th_x86_shift > 0 ? __vdso_gettc_rdtsc_low(th) :
__vdso_gettc_rdtsc32();
return (0);
case VDSO_TH_ALGO_X86_HPET:
idx = th->th_x86_hpet_idx;
if (idx >= HPET_DEV_MAP_MAX)
return (ENOSYS);
map = (volatile char *)atomic_load_acq_ptr(
(volatile uintptr_t *)&hpet_dev_map[idx]);
if (map == NULL) {
__vdso_init_hpet(idx);
map = (volatile char *)atomic_load_acq_ptr(
(volatile uintptr_t *)&hpet_dev_map[idx]);
}
if (map == MAP_FAILED)
return (ENOSYS);
*tc = *(volatile uint32_t *)(map + HPET_MAIN_COUNTER);
return (0);
#ifdef WANT_HYPERV
case VDSO_TH_ALGO_X86_HVTSC:
if (hyperv_ref_tsc == NULL)
__vdso_init_hyperv_tsc();
if (hyperv_ref_tsc == MAP_FAILED)
return (ENOSYS);
return (__vdso_hyperv_tsc(hyperv_ref_tsc, tc));
#endif
case VDSO_TH_ALGO_X86_PVCLK:
if (pvclock_timeinfos == NULL)
__vdso_init_pvclock_timeinfos();
if (pvclock_timeinfos == MAP_FAILED)
return (ENOSYS);
return (__vdso_pvclock_gettc(th, tc));
default:
return (ENOSYS);
}
}
#pragma weak __vdso_gettimekeep
int
__vdso_gettimekeep(struct vdso_timekeep **tk)
{
return (_elf_aux_info(AT_TIMEKEEP, tk, sizeof(*tk)));
}
diff --git a/lib/libc/x86/sys/pkru.c b/lib/libc/x86/sys/pkru.c
index a03becb3e101..b6ae181c131f 100644
--- a/lib/libc/x86/sys/pkru.c
+++ b/lib/libc/x86/sys/pkru.c
@@ -1,135 +1,134 @@
/*-
* Copyright (c) 2019 The FreeBSD Foundation
*
* Portions of this software were developed by Konstantin Belousov
* under sponsorship from the FreeBSD Foundation.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <sys/param.h>
#include <machine/cpufunc.h>
#include <machine/specialreg.h>
#include <machine/sysarch.h>
#include <x86/ifunc.h>
#include <errno.h>
#include <string.h>
#define MAX_PKRU_IDX 0xf
#ifdef __i386__
#define X86_SET_PKRU I386_SET_PKRU
#define X86_CLEAR_PKRU I386_CLEAR_PKRU
#else
#define X86_SET_PKRU AMD64_SET_PKRU
#define X86_CLEAR_PKRU AMD64_CLEAR_PKRU
#endif
static int
x86_pkru_get_perm_unsup(u_int keyidx, int *access, int *modify)
{
errno = EOPNOTSUPP;
return (-1);
}
static int
x86_pkru_get_perm_hw(u_int keyidx, int *access, int *modify)
{
uint32_t pkru;
if (keyidx > MAX_PKRU_IDX) {
errno = EINVAL;
return (-1);
}
keyidx *= 2;
pkru = rdpkru();
*access = (pkru & (1 << keyidx)) == 0;
*modify = (pkru & (2 << keyidx)) == 0;
return (0);
}
DEFINE_UIFUNC(, int, x86_pkru_get_perm, (u_int, int *, int *))
{
return ((cpu_stdext_feature2 & CPUID_STDEXT2_OSPKE) == 0 ?
x86_pkru_get_perm_unsup : x86_pkru_get_perm_hw);
}
static int
x86_pkru_set_perm_unsup(u_int keyidx, int access, int modify)
{
errno = EOPNOTSUPP;
return (-1);
}
static int
x86_pkru_set_perm_hw(u_int keyidx, int access, int modify)
{
uint32_t pkru;
if (keyidx > MAX_PKRU_IDX) {
errno = EINVAL;
return (-1);
}
keyidx *= 2;
pkru = rdpkru();
pkru &= ~(3 << keyidx);
if (!access)
pkru |= 1 << keyidx;
if (!modify)
pkru |= 2 << keyidx;
wrpkru(pkru);
return (0);
}
DEFINE_UIFUNC(, int, x86_pkru_set_perm, (u_int, int, int))
{
return ((cpu_stdext_feature2 & CPUID_STDEXT2_OSPKE) == 0 ?
x86_pkru_set_perm_unsup : x86_pkru_set_perm_hw);
}
int
x86_pkru_protect_range(void *addr, unsigned long len, u_int keyidx, int flags)
{
struct amd64_set_pkru a64pkru;
memset(&a64pkru, 0, sizeof(a64pkru));
a64pkru.addr = addr;
a64pkru.len = len;
a64pkru.keyidx = keyidx;
a64pkru.flags = flags;
return (sysarch(X86_SET_PKRU, &a64pkru));
}
int
x86_pkru_unprotect_range(void *addr, unsigned long len)
{
struct amd64_set_pkru a64pkru;
memset(&a64pkru, 0, sizeof(a64pkru));
a64pkru.addr = addr;
a64pkru.len = len;
return (sysarch(X86_CLEAR_PKRU, &a64pkru));
}
diff --git a/lib/libc/xdr/xdr.c b/lib/libc/xdr/xdr.c
index 6d44a012443b..15f80502ea39 100644
--- a/lib/libc/xdr/xdr.c
+++ b/lib/libc/xdr/xdr.c
@@ -1,927 +1,926 @@
/* $NetBSD: xdr.c,v 1.22 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr.c 1.35 87/08/12";
static char *sccsid = "@(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* xdr.c, Generic XDR routines implementation.
*
* These are the "generic" xdr routines used to serialize and de-serialize
* most common data items. See xdr.h for more info on the interface to
* xdr.
*/
#include "namespace.h"
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/rpc.h>
#include <rpc/rpc_com.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "un-namespace.h"
typedef quad_t longlong_t; /* ANSI long long type */
typedef u_quad_t u_longlong_t; /* ANSI unsigned long long type */
/*
* constants specific to the xdr "protocol"
*/
#define XDR_FALSE ((long) 0)
#define XDR_TRUE ((long) 1)
/*
* for unit alignment
*/
static const char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 };
/*
* Free a data structure using XDR
* Not a filter, but a convenient utility nonetheless
*/
void
xdr_free(xdrproc_t proc, void *objp)
{
XDR x;
x.x_op = XDR_FREE;
(*proc)(&x, objp);
}
/*
* XDR nothing
*/
bool_t
xdr_void(void)
{
return (TRUE);
}
/*
* XDR integers
*/
bool_t
xdr_int(XDR *xdrs, int *ip)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *ip;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*ip = (int) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned integers
*/
bool_t
xdr_u_int(XDR *xdrs, u_int *up)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *up;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*up = (u_int) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR long integers
* same as xdr_u_long - open coded to save a proc call!
*/
bool_t
xdr_long(XDR *xdrs, long *lp)
{
switch (xdrs->x_op) {
case XDR_ENCODE:
return (XDR_PUTLONG(xdrs, lp));
case XDR_DECODE:
return (XDR_GETLONG(xdrs, lp));
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned long integers
* same as xdr_long - open coded to save a proc call!
*/
bool_t
xdr_u_long(XDR *xdrs, u_long *ulp)
{
switch (xdrs->x_op) {
case XDR_ENCODE:
return (XDR_PUTLONG(xdrs, (long *)ulp));
case XDR_DECODE:
return (XDR_GETLONG(xdrs, (long *)ulp));
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR 32-bit integers
* same as xdr_u_int32_t - open coded to save a proc call!
*/
bool_t
xdr_int32_t(XDR *xdrs, int32_t *int32_p)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *int32_p;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*int32_p = (int32_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 32-bit integers
* same as xdr_int32_t - open coded to save a proc call!
*/
bool_t
xdr_u_int32_t(XDR *xdrs, u_int32_t *u_int32_p)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *u_int32_p;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*u_int32_p = (u_int32_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 32-bit integers
* same as xdr_int32_t - open coded to save a proc call!
*/
bool_t
xdr_uint32_t(XDR *xdrs, uint32_t *u_int32_p)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *u_int32_p;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*u_int32_p = (u_int32_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR short integers
*/
bool_t
xdr_short(XDR *xdrs, short *sp)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *sp;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*sp = (short) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned short integers
*/
bool_t
xdr_u_short(XDR *xdrs, u_short *usp)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *usp;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*usp = (u_short) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR 16-bit integers
*/
bool_t
xdr_int16_t(XDR *xdrs, int16_t *int16_p)
{
long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (long) *int16_p;
return (XDR_PUTLONG(xdrs, &l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &l)) {
return (FALSE);
}
*int16_p = (int16_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 16-bit integers
*/
bool_t
xdr_u_int16_t(XDR *xdrs, u_int16_t *u_int16_p)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *u_int16_p;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*u_int16_p = (u_int16_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 16-bit integers
*/
bool_t
xdr_uint16_t(XDR *xdrs, uint16_t *u_int16_p)
{
u_long l;
switch (xdrs->x_op) {
case XDR_ENCODE:
l = (u_long) *u_int16_p;
return (XDR_PUTLONG(xdrs, (long *)&l));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, (long *)&l)) {
return (FALSE);
}
*u_int16_p = (u_int16_t) l;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR a char
*/
bool_t
xdr_char(XDR *xdrs, char *cp)
{
u_int i;
i = *((unsigned char *)cp);
if (!xdr_u_int(xdrs, &i)) {
return (FALSE);
}
*((unsigned char *)cp) = i;
return (TRUE);
}
/*
* XDR an unsigned char
*/
bool_t
xdr_u_char(XDR *xdrs, u_char *cp)
{
u_int u;
u = (*cp);
if (!xdr_u_int(xdrs, &u)) {
return (FALSE);
}
*cp = u;
return (TRUE);
}
/*
* XDR booleans
*/
bool_t
xdr_bool(XDR *xdrs, bool_t *bp)
{
long lb;
switch (xdrs->x_op) {
case XDR_ENCODE:
lb = *bp ? XDR_TRUE : XDR_FALSE;
return (XDR_PUTLONG(xdrs, &lb));
case XDR_DECODE:
if (!XDR_GETLONG(xdrs, &lb)) {
return (FALSE);
}
*bp = (lb == XDR_FALSE) ? FALSE : TRUE;
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR enumerations
*/
bool_t
xdr_enum(XDR *xdrs, enum_t *ep)
{
enum sizecheck { SIZEVAL }; /* used to find the size of an enum */
/*
* enums are treated as ints
*/
/* LINTED */ if (sizeof (enum sizecheck) == sizeof (long)) {
return (xdr_long(xdrs, (long *)(void *)ep));
} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (int)) {
return (xdr_int(xdrs, (int *)(void *)ep));
} else /* LINTED */ if (sizeof (enum sizecheck) == sizeof (short)) {
return (xdr_short(xdrs, (short *)(void *)ep));
} else {
return (FALSE);
}
}
/*
* XDR opaque data
* Allows the specification of a fixed size sequence of opaque bytes.
* cp points to the opaque object and cnt gives the byte length.
*/
bool_t
xdr_opaque(XDR *xdrs, caddr_t cp, u_int cnt)
{
u_int rndup;
static int crud[BYTES_PER_XDR_UNIT];
/*
* if no data we are done
*/
if (cnt == 0)
return (TRUE);
/*
* round byte count to full xdr units
*/
rndup = cnt % BYTES_PER_XDR_UNIT;
if (rndup > 0)
rndup = BYTES_PER_XDR_UNIT - rndup;
if (xdrs->x_op == XDR_DECODE) {
if (!XDR_GETBYTES(xdrs, cp, cnt)) {
return (FALSE);
}
if (rndup == 0)
return (TRUE);
return (XDR_GETBYTES(xdrs, (caddr_t)(void *)crud, rndup));
}
if (xdrs->x_op == XDR_ENCODE) {
if (!XDR_PUTBYTES(xdrs, cp, cnt)) {
return (FALSE);
}
if (rndup == 0)
return (TRUE);
return (XDR_PUTBYTES(xdrs, xdr_zero, rndup));
}
if (xdrs->x_op == XDR_FREE) {
return (TRUE);
}
return (FALSE);
}
/*
* XDR counted bytes
* *cpp is a pointer to the bytes, *sizep is the count.
* If *cpp is NULL maxsize bytes are allocated
*/
bool_t
xdr_bytes(XDR *xdrs, char **cpp, u_int *sizep, u_int maxsize)
{
char *sp = *cpp; /* sp is the actual string pointer */
u_int nodesize;
bool_t ret, allocated = FALSE;
/*
* first deal with the length since xdr bytes are counted
*/
if (! xdr_u_int(xdrs, sizep)) {
return (FALSE);
}
nodesize = *sizep;
if ((nodesize > maxsize) && (xdrs->x_op != XDR_FREE)) {
return (FALSE);
}
/*
* now deal with the actual bytes
*/
switch (xdrs->x_op) {
case XDR_DECODE:
if (nodesize == 0) {
return (TRUE);
}
if (sp == NULL) {
*cpp = sp = mem_alloc(nodesize);
allocated = TRUE;
}
if (sp == NULL) {
warnx("xdr_bytes: out of memory");
return (FALSE);
}
/* FALLTHROUGH */
case XDR_ENCODE:
ret = xdr_opaque(xdrs, sp, nodesize);
if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
if (allocated == TRUE) {
free(sp);
*cpp = NULL;
}
}
return (ret);
case XDR_FREE:
if (sp != NULL) {
mem_free(sp, nodesize);
*cpp = NULL;
}
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* Implemented here due to commonality of the object.
*/
bool_t
xdr_netobj(XDR *xdrs, struct netobj *np)
{
return (xdr_bytes(xdrs, &np->n_bytes, &np->n_len, MAX_NETOBJ_SZ));
}
/*
* XDR a descriminated union
* Support routine for discriminated unions.
* You create an array of xdrdiscrim structures, terminated with
* an entry with a null procedure pointer. The routine gets
* the discriminant value and then searches the array of xdrdiscrims
* looking for that value. It calls the procedure given in the xdrdiscrim
* to handle the discriminant. If there is no specific routine a default
* routine may be called.
* If there is no specific or default routine an error is returned.
*/
bool_t
xdr_union(XDR *xdrs, enum_t *dscmp, char *unp, const struct xdr_discrim *choices, xdrproc_t dfault)
/*
* XDR *xdrs;
* enum_t *dscmp; // enum to decide which arm to work on
* char *unp; // the union itself
* const struct xdr_discrim *choices; // [value, xdr proc] for each arm
* xdrproc_t dfault; // default xdr routine
*/
{
enum_t dscm;
/*
* we deal with the discriminator; it's an enum
*/
if (! xdr_enum(xdrs, dscmp)) {
return (FALSE);
}
dscm = *dscmp;
/*
* search choices for a value that matches the discriminator.
* if we find one, execute the xdr routine for that value.
*/
for (; choices->proc != NULL_xdrproc_t; choices++) {
if (choices->value == dscm)
return ((*(choices->proc))(xdrs, unp));
}
/*
* no match - execute the default xdr routine if there is one
*/
return ((dfault == NULL_xdrproc_t) ? FALSE :
(*dfault)(xdrs, unp));
}
/*
* Non-portable xdr primitives.
* Care should be taken when moving these routines to new architectures.
*/
/*
* XDR null terminated ASCII strings
* xdr_string deals with "C strings" - arrays of bytes that are
* terminated by a NULL character. The parameter cpp references a
* pointer to storage; If the pointer is null, then the necessary
* storage is allocated. The last parameter is the max allowed length
* of the string as specified by a protocol.
*/
bool_t
xdr_string(XDR *xdrs, char **cpp, u_int maxsize)
{
char *sp = *cpp; /* sp is the actual string pointer */
u_int size;
u_int nodesize;
bool_t ret, allocated = FALSE;
/*
* first deal with the length since xdr strings are counted-strings
*/
switch (xdrs->x_op) {
case XDR_FREE:
if (sp == NULL) {
return(TRUE); /* already free */
}
/* FALLTHROUGH */
case XDR_ENCODE:
size = strlen(sp);
break;
case XDR_DECODE:
break;
}
if (! xdr_u_int(xdrs, &size)) {
return (FALSE);
}
if (size > maxsize) {
return (FALSE);
}
nodesize = size + 1;
/*
* now deal with the actual bytes
*/
switch (xdrs->x_op) {
case XDR_DECODE:
if (nodesize == 0) {
return (TRUE);
}
if (sp == NULL) {
*cpp = sp = mem_alloc(nodesize);
allocated = TRUE;
}
if (sp == NULL) {
warnx("xdr_string: out of memory");
return (FALSE);
}
sp[size] = 0;
/* FALLTHROUGH */
case XDR_ENCODE:
ret = xdr_opaque(xdrs, sp, size);
if ((xdrs->x_op == XDR_DECODE) && (ret == FALSE)) {
if (allocated == TRUE) {
free(sp);
*cpp = NULL;
}
}
return (ret);
case XDR_FREE:
mem_free(sp, nodesize);
*cpp = NULL;
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* Wrapper for xdr_string that can be called directly from
* routines like clnt_call
*/
bool_t
xdr_wrapstring(XDR *xdrs, char **cpp)
{
return xdr_string(xdrs, cpp, RPC_MAXDATASIZE);
}
/*
* NOTE: xdr_hyper(), xdr_u_hyper(), xdr_longlong_t(), and xdr_u_longlong_t()
* are in the "non-portable" section because they require that a `long long'
* be a 64-bit type.
*
* --thorpej@netbsd.org, November 30, 1999
*/
/*
* XDR 64-bit integers
*/
bool_t
xdr_int64_t(XDR *xdrs, int64_t *llp)
{
u_long ul[2];
switch (xdrs->x_op) {
case XDR_ENCODE:
ul[0] = (u_long)((u_int64_t)*llp >> 32) & 0xffffffff;
ul[1] = (u_long)((u_int64_t)*llp) & 0xffffffff;
if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
case XDR_DECODE:
if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
return (FALSE);
*llp = (int64_t)
(((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 64-bit integers
*/
bool_t
xdr_u_int64_t(XDR *xdrs, u_int64_t *ullp)
{
u_long ul[2];
switch (xdrs->x_op) {
case XDR_ENCODE:
ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
ul[1] = (u_long)(*ullp) & 0xffffffff;
if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
case XDR_DECODE:
if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
return (FALSE);
*ullp = (u_int64_t)
(((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR unsigned 64-bit integers
*/
bool_t
xdr_uint64_t(XDR *xdrs, uint64_t *ullp)
{
u_long ul[2];
switch (xdrs->x_op) {
case XDR_ENCODE:
ul[0] = (u_long)(*ullp >> 32) & 0xffffffff;
ul[1] = (u_long)(*ullp) & 0xffffffff;
if (XDR_PUTLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
return (XDR_PUTLONG(xdrs, (long *)&ul[1]));
case XDR_DECODE:
if (XDR_GETLONG(xdrs, (long *)&ul[0]) == FALSE)
return (FALSE);
if (XDR_GETLONG(xdrs, (long *)&ul[1]) == FALSE)
return (FALSE);
*ullp = (u_int64_t)
(((u_int64_t)ul[0] << 32) | ((u_int64_t)ul[1]));
return (TRUE);
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
/*
* XDR hypers
*/
bool_t
xdr_hyper(XDR *xdrs, longlong_t *llp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_int64_t().
*/
return (xdr_int64_t(xdrs, (int64_t *)llp));
}
/*
* XDR unsigned hypers
*/
bool_t
xdr_u_hyper(XDR *xdrs, u_longlong_t *ullp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_u_int64_t().
*/
return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp));
}
/*
* XDR longlong_t's
*/
bool_t
xdr_longlong_t(XDR *xdrs, longlong_t *llp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_int64_t().
*/
return (xdr_int64_t(xdrs, (int64_t *)llp));
}
/*
* XDR u_longlong_t's
*/
bool_t
xdr_u_longlong_t(XDR *xdrs, u_longlong_t *ullp)
{
/*
* Don't bother open-coding this; it's a fair amount of code. Just
* call xdr_u_int64_t().
*/
return (xdr_u_int64_t(xdrs, (u_int64_t *)ullp));
}
diff --git a/lib/libc/xdr/xdr_array.c b/lib/libc/xdr/xdr_array.c
index 6e910557c702..80d07b8a5dc8 100644
--- a/lib/libc/xdr/xdr_array.c
+++ b/lib/libc/xdr/xdr_array.c
@@ -1,160 +1,159 @@
/* $NetBSD: xdr_array.c,v 1.12 2000/01/22 22:19:18 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_array.c 1.10 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)xdr_array.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* xdr_array.c, Generic XDR routines implementation.
*
* These are the "non-trivial" xdr primitives used to serialize and de-serialize
* arrays. See xdr.h for more info on the interface to xdr.
*/
#include "namespace.h"
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "un-namespace.h"
/*
* XDR an array of arbitrary elements
* *addrp is a pointer to the array, *sizep is the number of elements.
* If addrp is NULL (*sizep * elsize) bytes are allocated.
* elsize is the size (in bytes) of each element, and elproc is the
* xdr procedure to call to handle each element of the array.
*/
bool_t
xdr_array(XDR *xdrs, caddr_t *addrp, u_int *sizep, u_int maxsize, u_int elsize, xdrproc_t elproc)
/*
* XDR *xdrs;
* caddr_t *addrp; // array pointer
* u_int *sizep; // number of elements
* u_int maxsize; // max numberof elements
* u_int elsize; // size in bytes of each element
* xdrproc_t elproc; // xdr routine to handle each element
*/
{
u_int i;
caddr_t target = *addrp;
u_int c; /* the actual element count */
bool_t stat = TRUE;
u_int nodesize;
/* like strings, arrays are really counted arrays */
if (!xdr_u_int(xdrs, sizep)) {
return (FALSE);
}
c = *sizep;
if ((c > maxsize || UINT_MAX/elsize < c) &&
(xdrs->x_op != XDR_FREE)) {
return (FALSE);
}
nodesize = c * elsize;
/*
* if we are deserializing, we may need to allocate an array.
* We also save time by checking for a null array if we are freeing.
*/
if (target == NULL)
switch (xdrs->x_op) {
case XDR_DECODE:
if (c == 0)
return (TRUE);
*addrp = target = mem_alloc(nodesize);
if (target == NULL) {
warnx("xdr_array: out of memory");
return (FALSE);
}
memset(target, 0, nodesize);
break;
case XDR_FREE:
return (TRUE);
case XDR_ENCODE:
break;
}
/*
* now we xdr each element of array
*/
for (i = 0; (i < c) && stat; i++) {
stat = (*elproc)(xdrs, target);
target += elsize;
}
/*
* the array may need freeing
*/
if (xdrs->x_op == XDR_FREE) {
mem_free(*addrp, nodesize);
*addrp = NULL;
}
return (stat);
}
/*
* xdr_vector():
*
* XDR a fixed length array. Unlike variable-length arrays,
* the storage of fixed length arrays is static and unfreeable.
* > basep: base of the array
* > size: size of the array
* > elemsize: size of each element
* > xdr_elem: routine to XDR each element
*/
bool_t
xdr_vector(XDR *xdrs, char *basep, u_int nelem, u_int elemsize, xdrproc_t xdr_elem)
{
u_int i;
char *elptr;
elptr = basep;
for (i = 0; i < nelem; i++) {
if (!(*xdr_elem)(xdrs, elptr)) {
return(FALSE);
}
elptr += elemsize;
}
return(TRUE);
}
diff --git a/lib/libc/xdr/xdr_float.c b/lib/libc/xdr/xdr_float.c
index 4366a04586a1..a85a196f77fe 100644
--- a/lib/libc/xdr/xdr_float.c
+++ b/lib/libc/xdr/xdr_float.c
@@ -1,295 +1,294 @@
/* $NetBSD: xdr_float.c,v 1.23 2000/07/17 04:59:51 matt Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_float.c 1.12 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)xdr_float.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* xdr_float.c, Generic XDR routines implementation.
*
* These are the "floating point" xdr routines used to (de)serialize
* most common data items. See xdr.h for more info on the interface to
* xdr.
*/
#include "namespace.h"
#include <sys/param.h>
#include <stdio.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "un-namespace.h"
/*
* NB: Not portable.
* This routine works on machines with IEEE754 FP and Vaxen.
*/
#include <machine/endian.h>
#define IEEEFP
#if defined(__vax__)
/* What IEEE single precision floating point looks like on a Vax */
struct ieee_single {
unsigned int mantissa: 23;
unsigned int exp : 8;
unsigned int sign : 1;
};
/* Vax single precision floating point */
struct vax_single {
unsigned int mantissa1 : 7;
unsigned int exp : 8;
unsigned int sign : 1;
unsigned int mantissa2 : 16;
};
#define VAX_SNG_BIAS 0x81
#define IEEE_SNG_BIAS 0x7f
static struct sgl_limits {
struct vax_single s;
struct ieee_single ieee;
} sgl_limits[2] = {
{{ 0x7f, 0xff, 0x0, 0xffff }, /* Max Vax */
{ 0x0, 0xff, 0x0 }}, /* Max IEEE */
{{ 0x0, 0x0, 0x0, 0x0 }, /* Min Vax */
{ 0x0, 0x0, 0x0 }} /* Min IEEE */
};
#endif /* vax */
bool_t
xdr_float(XDR *xdrs, float *fp)
{
#ifndef IEEEFP
struct ieee_single is;
struct vax_single vs, *vsp;
struct sgl_limits *lim;
u_int i;
#endif
switch (xdrs->x_op) {
case XDR_ENCODE:
#ifdef IEEEFP
return (XDR_PUTINT32(xdrs, (int32_t *)fp));
#else
vs = *((struct vax_single *)fp);
for (i = 0, lim = sgl_limits; i < nitems(sgl_limits);
i++, lim++) {
if ((vs.mantissa2 == lim->s.mantissa2) &&
(vs.exp == lim->s.exp) &&
(vs.mantissa1 == lim->s.mantissa1)) {
is = lim->ieee;
goto shipit;
}
}
is.exp = vs.exp - VAX_SNG_BIAS + IEEE_SNG_BIAS;
is.mantissa = (vs.mantissa1 << 16) | vs.mantissa2;
shipit:
is.sign = vs.sign;
return (XDR_PUTINT32(xdrs, (int32_t *)&is));
#endif
case XDR_DECODE:
#ifdef IEEEFP
return (XDR_GETINT32(xdrs, (int32_t *)fp));
#else
vsp = (struct vax_single *)fp;
if (!XDR_GETINT32(xdrs, (int32_t *)&is))
return (FALSE);
for (i = 0, lim = sgl_limits; i < nitems(sgl_limits);
i++, lim++) {
if ((is.exp == lim->ieee.exp) &&
(is.mantissa == lim->ieee.mantissa)) {
*vsp = lim->s;
goto doneit;
}
}
vsp->exp = is.exp - IEEE_SNG_BIAS + VAX_SNG_BIAS;
vsp->mantissa2 = is.mantissa;
vsp->mantissa1 = (is.mantissa >> 16);
doneit:
vsp->sign = is.sign;
return (TRUE);
#endif
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
#if defined(__vax__)
/* What IEEE double precision floating point looks like on a Vax */
struct ieee_double {
unsigned int mantissa1 : 20;
unsigned int exp : 11;
unsigned int sign : 1;
unsigned int mantissa2 : 32;
};
/* Vax double precision floating point */
struct vax_double {
unsigned int mantissa1 : 7;
unsigned int exp : 8;
unsigned int sign : 1;
unsigned int mantissa2 : 16;
unsigned int mantissa3 : 16;
unsigned int mantissa4 : 16;
};
#define VAX_DBL_BIAS 0x81
#define IEEE_DBL_BIAS 0x3ff
#define MASK(nbits) ((1 << nbits) - 1)
static struct dbl_limits {
struct vax_double d;
struct ieee_double ieee;
} dbl_limits[2] = {
{{ 0x7f, 0xff, 0x0, 0xffff, 0xffff, 0xffff }, /* Max Vax */
{ 0x0, 0x7ff, 0x0, 0x0 }}, /* Max IEEE */
{{ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, /* Min Vax */
{ 0x0, 0x0, 0x0, 0x0 }} /* Min IEEE */
};
#endif /* vax */
bool_t
xdr_double(XDR *xdrs, double *dp)
{
#ifdef IEEEFP
int32_t *i32p;
bool_t rv;
#else
int32_t *lp;
struct ieee_double id;
struct vax_double vd;
struct dbl_limits *lim;
u_int i;
#endif
switch (xdrs->x_op) {
case XDR_ENCODE:
#ifdef IEEEFP
i32p = (int32_t *)(void *)dp;
#if BYTE_ORDER == BIG_ENDIAN
rv = XDR_PUTINT32(xdrs, i32p);
if (!rv)
return (rv);
rv = XDR_PUTINT32(xdrs, i32p+1);
#else
rv = XDR_PUTINT32(xdrs, i32p+1);
if (!rv)
return (rv);
rv = XDR_PUTINT32(xdrs, i32p);
#endif
return (rv);
#else
vd = *((struct vax_double *)dp);
for (i = 0, lim = dbl_limits; i < nitems(dbl_limits);
i++, lim++) {
if ((vd.mantissa4 == lim->d.mantissa4) &&
(vd.mantissa3 == lim->d.mantissa3) &&
(vd.mantissa2 == lim->d.mantissa2) &&
(vd.mantissa1 == lim->d.mantissa1) &&
(vd.exp == lim->d.exp)) {
id = lim->ieee;
goto shipit;
}
}
id.exp = vd.exp - VAX_DBL_BIAS + IEEE_DBL_BIAS;
id.mantissa1 = (vd.mantissa1 << 13) | (vd.mantissa2 >> 3);
id.mantissa2 = ((vd.mantissa2 & MASK(3)) << 29) |
(vd.mantissa3 << 13) |
((vd.mantissa4 >> 3) & MASK(13));
shipit:
id.sign = vd.sign;
lp = (int32_t *)&id;
return (XDR_PUTINT32(xdrs, lp++) && XDR_PUTINT32(xdrs, lp));
#endif
case XDR_DECODE:
#ifdef IEEEFP
i32p = (int32_t *)(void *)dp;
#if BYTE_ORDER == BIG_ENDIAN
rv = XDR_GETINT32(xdrs, i32p);
if (!rv)
return (rv);
rv = XDR_GETINT32(xdrs, i32p+1);
#else
rv = XDR_GETINT32(xdrs, i32p+1);
if (!rv)
return (rv);
rv = XDR_GETINT32(xdrs, i32p);
#endif
return (rv);
#else
lp = (int32_t *)&id;
if (!XDR_GETINT32(xdrs, lp++) || !XDR_GETINT32(xdrs, lp))
return (FALSE);
for (i = 0, lim = dbl_limits; i < nitems(dbl_limits);
i++, lim++) {
if ((id.mantissa2 == lim->ieee.mantissa2) &&
(id.mantissa1 == lim->ieee.mantissa1) &&
(id.exp == lim->ieee.exp)) {
vd = lim->d;
goto doneit;
}
}
vd.exp = id.exp - IEEE_DBL_BIAS + VAX_DBL_BIAS;
vd.mantissa1 = (id.mantissa1 >> 13);
vd.mantissa2 = ((id.mantissa1 & MASK(13)) << 3) |
(id.mantissa2 >> 29);
vd.mantissa3 = (id.mantissa2 >> 13);
vd.mantissa4 = (id.mantissa2 << 3);
doneit:
vd.sign = id.sign;
*dp = *((double *)&vd);
return (TRUE);
#endif
case XDR_FREE:
return (TRUE);
}
/* NOTREACHED */
return (FALSE);
}
diff --git a/lib/libc/xdr/xdr_mem.c b/lib/libc/xdr/xdr_mem.c
index b08606e54fa3..2c3329d0db16 100644
--- a/lib/libc/xdr/xdr_mem.c
+++ b/lib/libc/xdr/xdr_mem.c
@@ -1,234 +1,233 @@
/* $NetBSD: xdr_mem.c,v 1.15 2000/01/22 22:19:18 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* xdr_mem.h, XDR implementation using memory buffers.
*
* If you have some data to be interpreted as external data representation
* or to be converted to external data representation in a memory buffer,
* then this is the package for you.
*
*/
#include "namespace.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "un-namespace.h"
static void xdrmem_destroy(XDR *);
static bool_t xdrmem_getlong_aligned(XDR *, long *);
static bool_t xdrmem_putlong_aligned(XDR *, const long *);
static bool_t xdrmem_getlong_unaligned(XDR *, long *);
static bool_t xdrmem_putlong_unaligned(XDR *, const long *);
static bool_t xdrmem_getbytes(XDR *, char *, u_int);
static bool_t xdrmem_putbytes(XDR *, const char *, u_int);
/* XXX: w/64-bit pointers, u_int not enough! */
static u_int xdrmem_getpos(XDR *);
static bool_t xdrmem_setpos(XDR *, u_int);
static int32_t *xdrmem_inline_aligned(XDR *, u_int);
static int32_t *xdrmem_inline_unaligned(XDR *, u_int);
static const struct xdr_ops xdrmem_ops_aligned = {
xdrmem_getlong_aligned,
xdrmem_putlong_aligned,
xdrmem_getbytes,
xdrmem_putbytes,
xdrmem_getpos,
xdrmem_setpos,
xdrmem_inline_aligned,
xdrmem_destroy
};
static const struct xdr_ops xdrmem_ops_unaligned = {
xdrmem_getlong_unaligned,
xdrmem_putlong_unaligned,
xdrmem_getbytes,
xdrmem_putbytes,
xdrmem_getpos,
xdrmem_setpos,
xdrmem_inline_unaligned,
xdrmem_destroy
};
/*
* The procedure xdrmem_create initializes a stream descriptor for a
* memory buffer.
*/
void
xdrmem_create(XDR *xdrs, char *addr, u_int size, enum xdr_op op)
{
xdrs->x_op = op;
xdrs->x_ops = ((unsigned long)addr & (sizeof(int32_t) - 1))
? &xdrmem_ops_unaligned : &xdrmem_ops_aligned;
xdrs->x_private = xdrs->x_base = addr;
xdrs->x_handy = size;
}
/*ARGSUSED*/
static void
xdrmem_destroy(XDR *xdrs)
{
}
static bool_t
xdrmem_getlong_aligned(XDR *xdrs, long *lp)
{
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
*lp = ntohl(*(u_int32_t *)xdrs->x_private);
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_putlong_aligned(XDR *xdrs, const long *lp)
{
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
*(u_int32_t *)xdrs->x_private = htonl((u_int32_t)*lp);
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_getlong_unaligned(XDR *xdrs, long *lp)
{
u_int32_t l;
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
memmove(&l, xdrs->x_private, sizeof(int32_t));
*lp = ntohl(l);
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_putlong_unaligned(XDR *xdrs, const long *lp)
{
u_int32_t l;
if (xdrs->x_handy < sizeof(int32_t))
return (FALSE);
xdrs->x_handy -= sizeof(int32_t);
l = htonl((u_int32_t)*lp);
memmove(xdrs->x_private, &l, sizeof(int32_t));
xdrs->x_private = (char *)xdrs->x_private + sizeof(int32_t);
return (TRUE);
}
static bool_t
xdrmem_getbytes(XDR *xdrs, char *addr, u_int len)
{
if (xdrs->x_handy < len)
return (FALSE);
xdrs->x_handy -= len;
memmove(addr, xdrs->x_private, len);
xdrs->x_private = (char *)xdrs->x_private + len;
return (TRUE);
}
static bool_t
xdrmem_putbytes(XDR *xdrs, const char *addr, u_int len)
{
if (xdrs->x_handy < len)
return (FALSE);
xdrs->x_handy -= len;
memmove(xdrs->x_private, addr, len);
xdrs->x_private = (char *)xdrs->x_private + len;
return (TRUE);
}
static u_int
xdrmem_getpos(XDR *xdrs)
{
/* XXX w/64-bit pointers, u_int not enough! */
return (u_int)((u_long)xdrs->x_private - (u_long)xdrs->x_base);
}
static bool_t
xdrmem_setpos(XDR *xdrs, u_int pos)
{
char *newaddr = xdrs->x_base + pos;
char *lastaddr = (char *)xdrs->x_private + xdrs->x_handy;
if (newaddr > lastaddr)
return (FALSE);
xdrs->x_private = newaddr;
xdrs->x_handy = (u_int)(lastaddr - newaddr); /* XXX sizeof(u_int) <? sizeof(ptrdiff_t) */
return (TRUE);
}
static int32_t *
xdrmem_inline_aligned(XDR *xdrs, u_int len)
{
int32_t *buf = NULL;
if (xdrs->x_handy >= len) {
xdrs->x_handy -= len;
buf = (int32_t *)xdrs->x_private;
xdrs->x_private = (char *)xdrs->x_private + len;
}
return (buf);
}
/* ARGSUSED */
static int32_t *
xdrmem_inline_unaligned(XDR *xdrs, u_int len)
{
return (0);
}
diff --git a/lib/libc/xdr/xdr_rec.c b/lib/libc/xdr/xdr_rec.c
index cd99eecf6108..3f0dc6ec3cba 100644
--- a/lib/libc/xdr/xdr_rec.c
+++ b/lib/libc/xdr/xdr_rec.c
@@ -1,761 +1,760 @@
/* $NetBSD: xdr_rec.c,v 1.18 2000/07/06 03:10:35 christos Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_rec.c 1.21 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)xdr_rec.c 2.2 88/08/01 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
* layer above tcp (for rpc's use).
*
* These routines interface XDRSTREAMS to a tcp/ip connection.
* There is a record marking layer between the xdr stream
* and the tcp transport level. A record is composed on one or more
* record fragments. A record fragment is a thirty-two bit header followed
* by n bytes of data, where n is contained in the header. The header
* is represented as a htonl(u_long). Thegh order bit encodes
* whether or not the fragment is the last fragment of the record
* (1 => fragment is last, 0 => more fragments to follow.
* The other 31 bits encode the byte length of the fragment.
*/
#include "namespace.h"
#include <sys/types.h>
#include <netinet/in.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <rpc/auth.h>
#include <rpc/svc.h>
#include <rpc/clnt.h>
#include <sys/stddef.h>
#include "un-namespace.h"
#include "rpc_com.h"
static bool_t xdrrec_getlong(XDR *, long *);
static bool_t xdrrec_putlong(XDR *, const long *);
static bool_t xdrrec_getbytes(XDR *, char *, u_int);
static bool_t xdrrec_putbytes(XDR *, const char *, u_int);
static u_int xdrrec_getpos(XDR *);
static bool_t xdrrec_setpos(XDR *, u_int);
static int32_t *xdrrec_inline(XDR *, u_int);
static void xdrrec_destroy(XDR *);
static const struct xdr_ops xdrrec_ops = {
xdrrec_getlong,
xdrrec_putlong,
xdrrec_getbytes,
xdrrec_putbytes,
xdrrec_getpos,
xdrrec_setpos,
xdrrec_inline,
xdrrec_destroy
};
/*
* A record is composed of one or more record fragments.
* A record fragment is a four-byte header followed by zero to
* 2**32-1 bytes. The header is treated as a long unsigned and is
* encode/decoded to the network via htonl/ntohl. The low order 31 bits
* are a byte count of the fragment. The highest order bit is a boolean:
* 1 => this fragment is the last fragment of the record,
* 0 => this fragment is followed by more fragment(s).
*
* The fragment/record machinery is not general; it is constructed to
* meet the needs of xdr and rpc based on tcp.
*/
#define LAST_FRAG ((u_int32_t)(1U << 31))
typedef struct rec_strm {
char *tcp_handle;
/*
* out-goung bits
*/
int (*writeit)(void *, void *, int);
char *out_base; /* output buffer (points to frag header) */
char *out_finger; /* next output position */
char *out_boundry; /* data cannot up to this address */
u_int32_t *frag_header; /* beginning of current fragment */
bool_t frag_sent; /* true if buffer sent in middle of record */
/*
* in-coming bits
*/
int (*readit)(void *, void *, int);
u_long in_size; /* fixed size of the input buffer */
char *in_base;
char *in_finger; /* location of next byte to be had */
char *in_boundry; /* can read up to this location */
long fbtbc; /* fragment bytes to be consumed */
bool_t last_frag;
u_int sendsize;
u_int recvsize;
bool_t nonblock;
bool_t in_haveheader;
u_int32_t in_header;
char *in_hdrp;
int in_hdrlen;
int in_reclen;
int in_received;
int in_maxrec;
} RECSTREAM;
static u_int fix_buf_size(u_int);
static bool_t flush_out(RECSTREAM *, bool_t);
static bool_t fill_input_buf(RECSTREAM *);
static bool_t get_input_bytes(RECSTREAM *, char *, int);
static bool_t set_input_fragment(RECSTREAM *);
static bool_t skip_input_bytes(RECSTREAM *, long);
static bool_t realloc_stream(RECSTREAM *, int);
/*
* Create an xdr handle for xdrrec
* xdrrec_create fills in xdrs. Sendsize and recvsize are
* send and recv buffer sizes (0 => use default).
* tcp_handle is an opaque handle that is passed as the first parameter to
* the procedures readit and writeit. Readit and writeit are read and
* write respectively. They are like the system
* calls expect that they take an opaque handle rather than an fd.
*/
void
xdrrec_create(XDR *xdrs, u_int sendsize, u_int recvsize, void *tcp_handle,
int (*readit)(void *, void *, int), int (*writeit)(void *, void *, int))
/*
* XDR *xdrs;
* u_int sendsize;
* u_int recvsize;
* void *tcp_handle;
* // like read, but pass it a tcp_handle, not sock
* int (*readit)(void *, void *, int);
* // like write, but pass it a tcp_handle, not sock
* int (*writeit)(void *, void *, int);
*/
{
RECSTREAM *rstrm = mem_alloc(sizeof(RECSTREAM));
if (rstrm == NULL) {
warnx("xdrrec_create: out of memory");
/*
* This is bad. Should rework xdrrec_create to
* return a handle, and in this case return NULL
*/
return;
}
rstrm->sendsize = sendsize = fix_buf_size(sendsize);
rstrm->out_base = mem_alloc(rstrm->sendsize);
if (rstrm->out_base == NULL) {
warnx("xdrrec_create: out of memory");
mem_free(rstrm, sizeof(RECSTREAM));
return;
}
rstrm->recvsize = recvsize = fix_buf_size(recvsize);
rstrm->in_base = mem_alloc(recvsize);
if (rstrm->in_base == NULL) {
warnx("xdrrec_create: out of memory");
mem_free(rstrm->out_base, sendsize);
mem_free(rstrm, sizeof(RECSTREAM));
return;
}
/*
* now the rest ...
*/
xdrs->x_ops = &xdrrec_ops;
xdrs->x_private = rstrm;
rstrm->tcp_handle = tcp_handle;
rstrm->readit = readit;
rstrm->writeit = writeit;
rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
rstrm->out_finger += sizeof(u_int32_t);
rstrm->out_boundry += sendsize;
rstrm->frag_sent = FALSE;
rstrm->in_size = recvsize;
rstrm->in_boundry = rstrm->in_base;
rstrm->in_finger = (rstrm->in_boundry += recvsize);
rstrm->fbtbc = 0;
rstrm->last_frag = TRUE;
rstrm->in_haveheader = FALSE;
rstrm->in_hdrlen = 0;
rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
rstrm->nonblock = FALSE;
rstrm->in_reclen = 0;
rstrm->in_received = 0;
}
/*
* The reoutines defined below are the xdr ops which will go into the
* xdr handle filled in by xdrrec_create.
*/
static bool_t
xdrrec_getlong(XDR *xdrs, long *lp)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
int32_t *buflp = (int32_t *)(void *)(rstrm->in_finger);
int32_t mylong;
/* first try the inline, fast case */
if ((rstrm->fbtbc >= sizeof(int32_t)) &&
(((long)rstrm->in_boundry - (long)buflp) >= sizeof(int32_t))) {
*lp = (long)ntohl((u_int32_t)(*buflp));
rstrm->fbtbc -= sizeof(int32_t);
rstrm->in_finger += sizeof(int32_t);
} else {
if (! xdrrec_getbytes(xdrs, (char *)(void *)&mylong,
sizeof(int32_t)))
return (FALSE);
*lp = (long)ntohl((u_int32_t)mylong);
}
return (TRUE);
}
static bool_t
xdrrec_putlong(XDR *xdrs, const long *lp)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
int32_t *dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
if ((rstrm->out_finger += sizeof(int32_t)) > rstrm->out_boundry) {
/*
* this case should almost never happen so the code is
* inefficient
*/
rstrm->out_finger -= sizeof(int32_t);
rstrm->frag_sent = TRUE;
if (! flush_out(rstrm, FALSE))
return (FALSE);
dest_lp = ((int32_t *)(void *)(rstrm->out_finger));
rstrm->out_finger += sizeof(int32_t);
}
*dest_lp = (int32_t)htonl((u_int32_t)(*lp));
return (TRUE);
}
static bool_t /* must manage buffers, fragments, and records */
xdrrec_getbytes(XDR *xdrs, char *addr, u_int len)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
int current;
while (len > 0) {
current = (int)rstrm->fbtbc;
if (current == 0) {
if (rstrm->last_frag)
return (FALSE);
if (! set_input_fragment(rstrm))
return (FALSE);
continue;
}
current = (len < current) ? len : current;
if (! get_input_bytes(rstrm, addr, current))
return (FALSE);
addr += current;
rstrm->fbtbc -= current;
len -= current;
}
return (TRUE);
}
static bool_t
xdrrec_putbytes(XDR *xdrs, const char *addr, u_int len)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
size_t current;
while (len > 0) {
current = (size_t)((u_long)rstrm->out_boundry -
(u_long)rstrm->out_finger);
current = (len < current) ? len : current;
memmove(rstrm->out_finger, addr, current);
rstrm->out_finger += current;
addr += current;
len -= current;
if (rstrm->out_finger == rstrm->out_boundry) {
rstrm->frag_sent = TRUE;
if (! flush_out(rstrm, FALSE))
return (FALSE);
}
}
return (TRUE);
}
static u_int
xdrrec_getpos(XDR *xdrs)
{
RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
off_t pos;
pos = lseek((int)(u_long)rstrm->tcp_handle, (off_t)0, 1);
if (pos == -1)
pos = 0;
switch (xdrs->x_op) {
case XDR_ENCODE:
pos += rstrm->out_finger - rstrm->out_base;
break;
case XDR_DECODE:
pos -= rstrm->in_boundry - rstrm->in_finger;
break;
default:
pos = (off_t) -1;
break;
}
return ((u_int) pos);
}
static bool_t
xdrrec_setpos(XDR *xdrs, u_int pos)
{
RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
u_int currpos = xdrrec_getpos(xdrs);
int delta = currpos - pos;
char *newpos;
if ((int)currpos != -1)
switch (xdrs->x_op) {
case XDR_ENCODE:
newpos = rstrm->out_finger - delta;
if ((newpos > (char *)(void *)(rstrm->frag_header)) &&
(newpos < rstrm->out_boundry)) {
rstrm->out_finger = newpos;
return (TRUE);
}
break;
case XDR_DECODE:
newpos = rstrm->in_finger - delta;
if ((delta < (int)(rstrm->fbtbc)) &&
(newpos <= rstrm->in_boundry) &&
(newpos >= rstrm->in_base)) {
rstrm->in_finger = newpos;
rstrm->fbtbc -= delta;
return (TRUE);
}
break;
case XDR_FREE:
break;
}
return (FALSE);
}
static int32_t *
xdrrec_inline(XDR *xdrs, u_int len)
{
RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
int32_t *buf = NULL;
switch (xdrs->x_op) {
case XDR_ENCODE:
if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
buf = (int32_t *)(void *)rstrm->out_finger;
rstrm->out_finger += len;
}
break;
case XDR_DECODE:
if ((len <= rstrm->fbtbc) &&
((rstrm->in_finger + len) <= rstrm->in_boundry)) {
buf = (int32_t *)(void *)rstrm->in_finger;
rstrm->fbtbc -= len;
rstrm->in_finger += len;
}
break;
case XDR_FREE:
break;
}
return (buf);
}
static void
xdrrec_destroy(XDR *xdrs)
{
RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
mem_free(rstrm->out_base, rstrm->sendsize);
mem_free(rstrm->in_base, rstrm->recvsize);
mem_free(rstrm, sizeof(RECSTREAM));
}
/*
* Exported routines to manage xdr records
*/
/*
* Before reading (deserializing from the stream, one should always call
* this procedure to guarantee proper record alignment.
*/
bool_t
xdrrec_skiprecord(XDR *xdrs)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
enum xprt_stat xstat;
if (rstrm->nonblock) {
if (__xdrrec_getrec(xdrs, &xstat, FALSE)) {
rstrm->fbtbc = 0;
return TRUE;
}
if (rstrm->in_finger == rstrm->in_boundry &&
xstat == XPRT_MOREREQS) {
rstrm->fbtbc = 0;
return TRUE;
}
return FALSE;
}
while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
if (! skip_input_bytes(rstrm, rstrm->fbtbc))
return (FALSE);
rstrm->fbtbc = 0;
if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
return (FALSE);
}
rstrm->last_frag = FALSE;
return (TRUE);
}
/*
* Look ahead function.
* Returns TRUE iff there is no more input in the buffer
* after consuming the rest of the current record.
*/
bool_t
xdrrec_eof(XDR *xdrs)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
if (! skip_input_bytes(rstrm, rstrm->fbtbc))
return (TRUE);
rstrm->fbtbc = 0;
if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
return (TRUE);
}
if (rstrm->in_finger == rstrm->in_boundry)
return (TRUE);
return (FALSE);
}
/*
* The client must tell the package when an end-of-record has occurred.
* The second paraemters tells whether the record should be flushed to the
* (output) tcp stream. (This let's the package support batched or
* pipelined procedure calls.) TRUE => immmediate flush to tcp connection.
*/
bool_t
xdrrec_endofrecord(XDR *xdrs, bool_t sendnow)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
u_long len; /* fragment length */
if (sendnow || rstrm->frag_sent ||
((u_long)rstrm->out_finger + sizeof(u_int32_t) >=
(u_long)rstrm->out_boundry)) {
rstrm->frag_sent = FALSE;
return (flush_out(rstrm, TRUE));
}
len = (u_long)(rstrm->out_finger) - (u_long)(rstrm->frag_header) -
sizeof(u_int32_t);
*(rstrm->frag_header) = htonl((u_int32_t)len | LAST_FRAG);
rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_finger;
rstrm->out_finger += sizeof(u_int32_t);
return (TRUE);
}
/*
* Fill the stream buffer with a record for a non-blocking connection.
* Return true if a record is available in the buffer, false if not.
*/
bool_t
__xdrrec_getrec(XDR *xdrs, enum xprt_stat *statp, bool_t expectdata)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
ssize_t n;
int fraglen;
if (!rstrm->in_haveheader) {
n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp,
(int)sizeof (rstrm->in_header) - rstrm->in_hdrlen);
if (n == 0) {
*statp = expectdata ? XPRT_DIED : XPRT_IDLE;
return FALSE;
}
if (n < 0) {
*statp = XPRT_DIED;
return FALSE;
}
rstrm->in_hdrp += n;
rstrm->in_hdrlen += n;
if (rstrm->in_hdrlen < sizeof (rstrm->in_header)) {
*statp = XPRT_MOREREQS;
return FALSE;
}
rstrm->in_header = ntohl(rstrm->in_header);
fraglen = (int)(rstrm->in_header & ~LAST_FRAG);
if (fraglen == 0 || fraglen > rstrm->in_maxrec ||
(rstrm->in_reclen + fraglen) > rstrm->in_maxrec) {
*statp = XPRT_DIED;
return FALSE;
}
rstrm->in_reclen += fraglen;
if (rstrm->in_reclen > rstrm->recvsize)
realloc_stream(rstrm, rstrm->in_reclen);
if (rstrm->in_header & LAST_FRAG) {
rstrm->in_header &= ~LAST_FRAG;
rstrm->last_frag = TRUE;
}
/*
* We can only reasonably expect to read once from a
* non-blocking stream. Reading the fragment header
* may have drained the stream.
*/
expectdata = FALSE;
}
n = rstrm->readit(rstrm->tcp_handle,
rstrm->in_base + rstrm->in_received,
(rstrm->in_reclen - rstrm->in_received));
if (n < 0) {
*statp = XPRT_DIED;
return FALSE;
}
if (n == 0) {
*statp = expectdata ? XPRT_DIED : XPRT_IDLE;
return FALSE;
}
rstrm->in_received += n;
if (rstrm->in_received == rstrm->in_reclen) {
rstrm->in_haveheader = FALSE;
rstrm->in_hdrp = (char *)(void *)&rstrm->in_header;
rstrm->in_hdrlen = 0;
if (rstrm->last_frag) {
rstrm->fbtbc = rstrm->in_reclen;
rstrm->in_boundry = rstrm->in_base + rstrm->in_reclen;
rstrm->in_finger = rstrm->in_base;
rstrm->in_reclen = rstrm->in_received = 0;
*statp = XPRT_MOREREQS;
return TRUE;
}
}
*statp = XPRT_MOREREQS;
return FALSE;
}
bool_t
__xdrrec_setnonblock(XDR *xdrs, int maxrec)
{
RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
rstrm->nonblock = TRUE;
if (maxrec == 0)
maxrec = rstrm->recvsize;
rstrm->in_maxrec = maxrec;
return TRUE;
}
/*
* Internal useful routines
*/
static bool_t
flush_out(RECSTREAM *rstrm, bool_t eor)
{
u_int32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
u_int32_t len = (u_int32_t)((u_long)(rstrm->out_finger) -
(u_long)(rstrm->frag_header) - sizeof(u_int32_t));
*(rstrm->frag_header) = htonl(len | eormask);
len = (u_int32_t)((u_long)(rstrm->out_finger) -
(u_long)(rstrm->out_base));
if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
!= (int)len)
return (FALSE);
rstrm->frag_header = (u_int32_t *)(void *)rstrm->out_base;
rstrm->out_finger = (char *)rstrm->out_base + sizeof(u_int32_t);
return (TRUE);
}
static bool_t /* knows nothing about records! Only about input buffers */
fill_input_buf(RECSTREAM *rstrm)
{
char *where;
u_int32_t i;
int len;
if (rstrm->nonblock)
return FALSE;
where = rstrm->in_base;
i = (u_int32_t)((u_long)rstrm->in_boundry % BYTES_PER_XDR_UNIT);
where += i;
len = (u_int32_t)(rstrm->in_size - i);
if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
return (FALSE);
rstrm->in_finger = where;
where += len;
rstrm->in_boundry = where;
return (TRUE);
}
static bool_t /* knows nothing about records! Only about input buffers */
get_input_bytes(RECSTREAM *rstrm, char *addr, int len)
{
size_t current;
if (rstrm->nonblock) {
if (len > (int)(rstrm->in_boundry - rstrm->in_finger))
return FALSE;
memcpy(addr, rstrm->in_finger, (size_t)len);
rstrm->in_finger += len;
return TRUE;
}
while (len > 0) {
current = (size_t)((long)rstrm->in_boundry -
(long)rstrm->in_finger);
if (current == 0) {
if (! fill_input_buf(rstrm))
return (FALSE);
continue;
}
current = (len < current) ? len : current;
memmove(addr, rstrm->in_finger, current);
rstrm->in_finger += current;
addr += current;
len -= current;
}
return (TRUE);
}
static bool_t /* next two bytes of the input stream are treated as a header */
set_input_fragment(RECSTREAM *rstrm)
{
u_int32_t header;
if (rstrm->nonblock)
return FALSE;
if (! get_input_bytes(rstrm, (char *)(void *)&header, sizeof(header)))
return (FALSE);
header = ntohl(header);
rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
/*
* Sanity check. Try not to accept wildly incorrect
* record sizes. Unfortunately, the only record size
* we can positively identify as being 'wildly incorrect'
* is zero. Ridiculously large record sizes may look wrong,
* but we don't have any way to be certain that they aren't
* what the client actually intended to send us.
*/
if (header == 0)
return(FALSE);
rstrm->fbtbc = header & (~LAST_FRAG);
return (TRUE);
}
static bool_t /* consumes input bytes; knows nothing about records! */
skip_input_bytes(RECSTREAM *rstrm, long cnt)
{
u_int32_t current;
while (cnt > 0) {
current = (size_t)((long)rstrm->in_boundry -
(long)rstrm->in_finger);
if (current == 0) {
if (! fill_input_buf(rstrm))
return (FALSE);
continue;
}
current = (u_int32_t)((cnt < current) ? cnt : current);
rstrm->in_finger += current;
cnt -= current;
}
return (TRUE);
}
static u_int
fix_buf_size(u_int s)
{
if (s < 100)
s = 4000;
return (RNDUP(s));
}
/*
* Reallocate the input buffer for a non-block stream.
*/
static bool_t
realloc_stream(RECSTREAM *rstrm, int size)
{
ptrdiff_t diff;
char *buf;
if (size > rstrm->recvsize) {
buf = realloc(rstrm->in_base, (size_t)size);
if (buf == NULL)
return FALSE;
diff = buf - rstrm->in_base;
rstrm->in_finger += diff;
rstrm->in_base = buf;
rstrm->in_boundry = buf + size;
rstrm->recvsize = size;
rstrm->in_size = size;
}
return TRUE;
}
diff --git a/lib/libc/xdr/xdr_reference.c b/lib/libc/xdr/xdr_reference.c
index 321aa1d9f6ad..023188f7f05e 100644
--- a/lib/libc/xdr/xdr_reference.c
+++ b/lib/libc/xdr/xdr_reference.c
@@ -1,141 +1,140 @@
/* $NetBSD: xdr_reference.c,v 1.13 2000/01/22 22:19:18 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_reference.c 1.11 87/08/11 SMI";
static char *sccsid = "@(#)xdr_reference.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* xdr_reference.c, Generic XDR routines implementation.
*
* These are the "non-trivial" xdr primitives used to serialize and de-serialize
* "pointers". See xdr.h for more info on the interface to xdr.
*/
#include "namespace.h"
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "libc_private.h"
/*
* XDR an indirect pointer
* xdr_reference is for recursively translating a structure that is
* referenced by a pointer inside the structure that is currently being
* translated. pp references a pointer to storage. If *pp is null
* the necessary storage is allocated.
* size is the sizeof the referneced structure.
* proc is the routine to handle the referenced structure.
*/
bool_t
xdr_reference(XDR *xdrs, caddr_t *pp, u_int size, xdrproc_t proc)
/*
* XDR *xdrs;
* caddr_t *pp; // the pointer to work on
* u_int size; // size of the object pointed to
* xdrproc_t proc; // xdr routine to handle the object
*/
{
caddr_t loc = *pp;
bool_t stat;
if (loc == NULL)
switch (xdrs->x_op) {
case XDR_FREE:
return (TRUE);
case XDR_DECODE:
*pp = loc = (caddr_t) mem_alloc(size);
if (loc == NULL) {
warnx("xdr_reference: out of memory");
return (FALSE);
}
memset(loc, 0, size);
break;
case XDR_ENCODE:
break;
}
stat = (*proc)(xdrs, loc);
if (xdrs->x_op == XDR_FREE) {
mem_free(loc, size);
*pp = NULL;
}
return (stat);
}
/*
* xdr_pointer():
*
* XDR a pointer to a possibly recursive data structure. This
* differs with xdr_reference in that it can serialize/deserialiaze
* trees correctly.
*
* What's sent is actually a union:
*
* union object_pointer switch (boolean b) {
* case TRUE: object_data data;
* case FALSE: void nothing;
* }
*
* > objpp: Pointer to the pointer to the object.
* > obj_size: size of the object.
* > xdr_obj: routine to XDR an object.
*
*/
bool_t
xdr_pointer(XDR *xdrs, char **objpp, u_int obj_size, xdrproc_t xdr_obj)
{
bool_t more_data;
more_data = (*objpp != NULL);
if (! xdr_bool(xdrs,&more_data)) {
return (FALSE);
}
if (! more_data) {
*objpp = NULL;
return (TRUE);
}
return (xdr_reference(xdrs,objpp,obj_size,xdr_obj));
}
diff --git a/lib/libc/xdr/xdr_sizeof.c b/lib/libc/xdr/xdr_sizeof.c
index b0889c233c10..b374daf82a39 100644
--- a/lib/libc/xdr/xdr_sizeof.c
+++ b/lib/libc/xdr/xdr_sizeof.c
@@ -1,155 +1,154 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
* xdr_sizeof.c
*
* General purpose routine to see how much space something will use
* when serialized using XDR.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include <rpc/types.h>
#include <rpc/xdr.h>
#include <sys/types.h>
#include <stdlib.h>
#include "un-namespace.h"
/* ARGSUSED */
static bool_t
x_putlong(XDR *xdrs, const long *longp)
{
xdrs->x_handy += BYTES_PER_XDR_UNIT;
return (TRUE);
}
/* ARGSUSED */
static bool_t
x_putbytes(XDR *xdrs, const char *bp, u_int len)
{
xdrs->x_handy += len;
return (TRUE);
}
static u_int
x_getpostn(XDR *xdrs)
{
return (xdrs->x_handy);
}
/* ARGSUSED */
static bool_t
x_setpostn(XDR *xdrs, u_int pos)
{
/* This is not allowed */
return (FALSE);
}
static int32_t *
x_inline(XDR *xdrs, u_int len)
{
if (len == 0) {
return (NULL);
}
if (xdrs->x_op != XDR_ENCODE) {
return (NULL);
}
if (len < (u_int)(uintptr_t)xdrs->x_base) {
/* x_private was already allocated */
xdrs->x_handy += len;
return ((int32_t *) xdrs->x_private);
} else {
/* Free the earlier space and allocate new area */
if (xdrs->x_private)
free(xdrs->x_private);
if ((xdrs->x_private = (caddr_t) malloc(len)) == NULL) {
xdrs->x_base = 0;
return (NULL);
}
xdrs->x_base = (caddr_t)(uintptr_t)len;
xdrs->x_handy += len;
return ((int32_t *) xdrs->x_private);
}
}
static int
harmless(void)
{
/* Always return FALSE/NULL, as the case may be */
return (0);
}
static void
x_destroy(XDR *xdrs)
{
xdrs->x_handy = 0;
xdrs->x_base = 0;
if (xdrs->x_private) {
free(xdrs->x_private);
xdrs->x_private = NULL;
}
return;
}
unsigned long
xdr_sizeof(xdrproc_t func, void *data)
{
XDR x;
struct xdr_ops ops;
bool_t stat;
/* to stop ANSI-C compiler from complaining */
typedef bool_t (* dummyfunc1)(XDR *, long *);
typedef bool_t (* dummyfunc2)(XDR *, caddr_t, u_int);
ops.x_putlong = x_putlong;
ops.x_putbytes = x_putbytes;
ops.x_inline = x_inline;
ops.x_getpostn = x_getpostn;
ops.x_setpostn = x_setpostn;
ops.x_destroy = x_destroy;
/* the other harmless ones */
ops.x_getlong = (dummyfunc1) harmless;
ops.x_getbytes = (dummyfunc2) harmless;
x.x_op = XDR_ENCODE;
x.x_ops = &ops;
x.x_handy = 0;
x.x_private = (caddr_t) NULL;
x.x_base = (caddr_t) 0;
stat = func(&x, data);
if (x.x_private)
free(x.x_private);
return (stat == TRUE ? (unsigned) x.x_handy: 0);
}
diff --git a/lib/libc/xdr/xdr_stdio.c b/lib/libc/xdr/xdr_stdio.c
index 26335372d544..d75c5d2f6893 100644
--- a/lib/libc/xdr/xdr_stdio.c
+++ b/lib/libc/xdr/xdr_stdio.c
@@ -1,177 +1,176 @@
/* $NetBSD: xdr_stdio.c,v 1.14 2000/01/22 22:19:19 mycroft Exp $ */
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 2010, Oracle America, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
* * Neither the name of the "Oracle America, Inc." nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *sccsid2 = "@(#)xdr_stdio.c 1.16 87/08/11 Copyr 1984 Sun Micro";
static char *sccsid = "@(#)xdr_stdio.c 2.1 88/07/29 4.0 RPCSRC";
#endif
-#include <sys/cdefs.h>
/*
* xdr_stdio.c, XDR implementation on standard i/o file.
*
* This set of routines implements a XDR on a stdio stream.
* XDR_ENCODE serializes onto the stream, XDR_DECODE de-serializes
* from the stream.
*/
#include "namespace.h"
#include <stdio.h>
#include <arpa/inet.h>
#include <rpc/types.h>
#include <rpc/xdr.h>
#include "un-namespace.h"
static void xdrstdio_destroy(XDR *);
static bool_t xdrstdio_getlong(XDR *, long *);
static bool_t xdrstdio_putlong(XDR *, const long *);
static bool_t xdrstdio_getbytes(XDR *, char *, u_int);
static bool_t xdrstdio_putbytes(XDR *, const char *, u_int);
static u_int xdrstdio_getpos(XDR *);
static bool_t xdrstdio_setpos(XDR *, u_int);
static int32_t *xdrstdio_inline(XDR *, u_int);
/*
* Ops vector for stdio type XDR
*/
static const struct xdr_ops xdrstdio_ops = {
xdrstdio_getlong, /* deseraialize a long int */
xdrstdio_putlong, /* seraialize a long int */
xdrstdio_getbytes, /* deserialize counted bytes */
xdrstdio_putbytes, /* serialize counted bytes */
xdrstdio_getpos, /* get offset in the stream */
xdrstdio_setpos, /* set offset in the stream */
xdrstdio_inline, /* prime stream for inline macros */
xdrstdio_destroy /* destroy stream */
};
/*
* Initialize a stdio xdr stream.
* Sets the xdr stream handle xdrs for use on the stream file.
* Operation flag is set to op.
*/
void
xdrstdio_create(XDR *xdrs, FILE *file, enum xdr_op op)
{
xdrs->x_op = op;
xdrs->x_ops = &xdrstdio_ops;
xdrs->x_private = file;
xdrs->x_handy = 0;
xdrs->x_base = 0;
}
/*
* Destroy a stdio xdr stream.
* Cleans up the xdr stream handle xdrs previously set up by xdrstdio_create.
*/
static void
xdrstdio_destroy(XDR *xdrs)
{
(void)fflush((FILE *)xdrs->x_private);
/* XXX: should we close the file ?? */
}
static bool_t
xdrstdio_getlong(XDR *xdrs, long *lp)
{
u_int32_t temp;
if (fread(&temp, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1)
return (FALSE);
*lp = (long)ntohl(temp);
return (TRUE);
}
static bool_t
xdrstdio_putlong(XDR *xdrs, const long *lp)
{
int32_t mycopy = htonl((u_int32_t)*lp);
if (fwrite(&mycopy, sizeof(int32_t), 1, (FILE *)xdrs->x_private) != 1)
return (FALSE);
return (TRUE);
}
static bool_t
xdrstdio_getbytes(XDR *xdrs, char *addr, u_int len)
{
if ((len != 0) && (fread(addr, (size_t)len, 1, (FILE *)xdrs->x_private) != 1))
return (FALSE);
return (TRUE);
}
static bool_t
xdrstdio_putbytes(XDR *xdrs, const char *addr, u_int len)
{
if ((len != 0) && (fwrite(addr, (size_t)len, 1,
(FILE *)xdrs->x_private) != 1))
return (FALSE);
return (TRUE);
}
static u_int
xdrstdio_getpos(XDR *xdrs)
{
return ((u_int) ftell((FILE *)xdrs->x_private));
}
static bool_t
xdrstdio_setpos(XDR *xdrs, u_int pos)
{
return ((fseek((FILE *)xdrs->x_private, (long)pos, 0) < 0) ?
FALSE : TRUE);
}
/* ARGSUSED */
static int32_t *
xdrstdio_inline(XDR *xdrs, u_int len)
{
/*
* Must do some work to implement this: must insure
* enough data in the underlying stdio buffer,
* that the buffer is aligned so that we can indirect through a
* long *, and stuff this pointer in xdrs->x_buf. Doing
* a fread or fwrite to a scratch buffer would defeat
* most of the gains to be had here and require storage
* management on this buffer, so we don't do this.
*/
return (NULL);
}
diff --git a/lib/libc/yp/xdryp.c b/lib/libc/yp/xdryp.c
index ebd76cb48050..eae57e7e8347 100644
--- a/lib/libc/yp/xdryp.c
+++ b/lib/libc/yp/xdryp.c
@@ -1,125 +1,124 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include <rpc/rpc.h>
#include <rpcsvc/yp.h>
#include <stdlib.h>
#include <string.h>
extern int (*ypresp_allfn)(u_long, char *, int, char *, int, void *);
extern void *ypresp_data;
/*
* I'm leaving the xdr_datum() function in purely for backwards
* compatibility. yplib.c doesn't actually use it, but it's listed
* in yp_prot.h as being available, so it's probably a good idea to
* leave it in case somebody goes looking for it.
*/
typedef struct {
char *dptr;
int dsize;
} datum;
bool_t
xdr_datum(XDR *xdrs, datum *objp)
{
if (!xdr_bytes(xdrs, (char **)&objp->dptr, (u_int *)&objp->dsize, YPMAXRECORD)) {
return (FALSE);
}
return (TRUE);
}
bool_t
xdr_ypresp_all_seq(XDR *xdrs, u_long *objp)
{
struct ypresp_all out;
u_long status;
char *key, *val;
int r;
bzero(&out, sizeof out);
while (1) {
if (!xdr_ypresp_all(xdrs, &out)) {
xdr_free((xdrproc_t)xdr_ypresp_all, &out);
*objp = YP_YPERR;
return (FALSE);
}
if (out.more == 0) {
xdr_free((xdrproc_t)xdr_ypresp_all, &out);
*objp = YP_NOMORE;
return (TRUE);
}
status = out.ypresp_all_u.val.stat;
switch (status) {
case YP_TRUE:
key = (char *)malloc(out.ypresp_all_u.val.key.keydat_len + 1);
if (key == NULL) {
xdr_free((xdrproc_t)xdr_ypresp_all, &out);
*objp = YP_YPERR;
return (FALSE);
}
bcopy(out.ypresp_all_u.val.key.keydat_val, key,
out.ypresp_all_u.val.key.keydat_len);
key[out.ypresp_all_u.val.key.keydat_len] = '\0';
val = (char *)malloc(out.ypresp_all_u.val.val.valdat_len + 1);
if (val == NULL) {
free(key);
xdr_free((xdrproc_t)xdr_ypresp_all, &out);
*objp = YP_YPERR;
return (FALSE);
}
bcopy(out.ypresp_all_u.val.val.valdat_val, val,
out.ypresp_all_u.val.val.valdat_len);
val[out.ypresp_all_u.val.val.valdat_len] = '\0';
xdr_free((xdrproc_t)xdr_ypresp_all, &out);
r = (*ypresp_allfn)(status,
key, out.ypresp_all_u.val.key.keydat_len,
val, out.ypresp_all_u.val.val.valdat_len,
ypresp_data);
*objp = status;
free(key);
free(val);
if (r)
return (TRUE);
break;
case YP_NOMORE:
xdr_free((xdrproc_t)xdr_ypresp_all, &out);
*objp = YP_NOMORE;
return (TRUE);
default:
xdr_free((xdrproc_t)xdr_ypresp_all, &out);
*objp = status;
return (TRUE);
}
}
}
diff --git a/lib/libc/yp/yplib.c b/lib/libc/yp/yplib.c
index cddaaa697ab6..d222200ed728 100644
--- a/lib/libc/yp/yplib.c
+++ b/lib/libc/yp/yplib.c
@@ -1,1238 +1,1237 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1992/3 Theo de Raadt <deraadt@fsa.ca>
* Copyright (c) 1998 Bill Paul <wpaul@ctr.columbia.edu>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote
* products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
-#include <sys/cdefs.h>
#include "namespace.h"
#include "reentrant.h"
#include <sys/param.h>
#include <sys/socket.h>
#include <sys/file.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <rpc/rpc.h>
#include <rpc/xdr.h>
#include <rpcsvc/yp.h>
#include "un-namespace.h"
#include "libc_private.h"
/*
* We have to define these here due to clashes between yp_prot.h and
* yp.h.
*/
#define YPMATCHCACHE
#ifdef YPMATCHCACHE
struct ypmatch_ent {
char *ypc_map;
keydat ypc_key;
valdat ypc_val;
time_t ypc_expire_t;
struct ypmatch_ent *ypc_next;
};
#define YPLIB_MAXCACHE 5 /* At most 5 entries */
#define YPLIB_EXPIRE 5 /* Expire after 5 seconds */
#endif
struct dom_binding {
struct dom_binding *dom_pnext;
char dom_domain[YPMAXDOMAIN + 1];
struct sockaddr_in dom_server_addr;
u_short dom_server_port;
int dom_socket;
CLIENT *dom_client;
u_short dom_local_port; /* now I finally know what this is for. */
long dom_vers;
#ifdef YPMATCHCACHE
struct ypmatch_ent *cache;
int ypmatch_cachecnt;
#endif
};
#include <rpcsvc/ypclnt.h>
#ifndef BINDINGDIR
#define BINDINGDIR "/var/yp/binding"
#endif
#define MAX_RETRIES 20
bool_t xdr_ypresp_all_seq(XDR *xdrs, u_long *objp);
int (*ypresp_allfn)();
void *ypresp_data;
static void _yp_unbind(struct dom_binding *);
struct dom_binding *_ypbindlist;
static char _yp_domain[MAXHOSTNAMELEN];
int _yplib_timeout = 20;
static mutex_t _ypmutex = MUTEX_INITIALIZER;
#define YPLOCK() mutex_lock(&_ypmutex);
#define YPUNLOCK() mutex_unlock(&_ypmutex);
#ifdef YPMATCHCACHE
static void
ypmatch_cache_delete(struct dom_binding *ypdb, struct ypmatch_ent *prev,
struct ypmatch_ent *cur)
{
if (prev == NULL)
ypdb->cache = cur->ypc_next;
else
prev->ypc_next = cur->ypc_next;
free(cur->ypc_map);
free(cur->ypc_key.keydat_val);
free(cur->ypc_val.valdat_val);
free(cur);
ypdb->ypmatch_cachecnt--;
return;
}
static void
ypmatch_cache_flush(struct dom_binding *ypdb)
{
struct ypmatch_ent *n, *c = ypdb->cache;
while (c != NULL) {
n = c->ypc_next;
ypmatch_cache_delete(ypdb, NULL, c);
c = n;
}
return;
}
static void
ypmatch_cache_expire(struct dom_binding *ypdb)
{
struct ypmatch_ent *c = ypdb->cache;
struct ypmatch_ent *n, *p = NULL;
time_t t;
time(&t);
while (c != NULL) {
if (t >= c->ypc_expire_t) {
n = c->ypc_next;
ypmatch_cache_delete(ypdb, p, c);
c = n;
} else {
p = c;
c = c->ypc_next;
}
}
return;
}
static void
ypmatch_cache_insert(struct dom_binding *ypdb, char *map, keydat *key,
valdat *val)
{
struct ypmatch_ent *new;
/* Do an expire run to maybe open up a slot. */
if (ypdb->ypmatch_cachecnt)
ypmatch_cache_expire(ypdb);
/*
* If there are no slots free, then force an expire of
* the least recently used entry.
*/
if (ypdb->ypmatch_cachecnt >= YPLIB_MAXCACHE) {
struct ypmatch_ent *o = NULL, *c = ypdb->cache;
time_t oldest = 0;
oldest = ~oldest;
while (c != NULL) {
if (c->ypc_expire_t < oldest) {
oldest = c->ypc_expire_t;
o = c;
}
c = c->ypc_next;
}
if (o == NULL)
return;
o->ypc_expire_t = 0;
ypmatch_cache_expire(ypdb);
}
new = malloc(sizeof(struct ypmatch_ent));
if (new == NULL)
return;
new->ypc_map = strdup(map);
if (new->ypc_map == NULL) {
free(new);
return;
}
new->ypc_key.keydat_val = malloc(key->keydat_len);
if (new->ypc_key.keydat_val == NULL) {
free(new->ypc_map);
free(new);
return;
}
new->ypc_val.valdat_val = malloc(val->valdat_len);
if (new->ypc_val.valdat_val == NULL) {
free(new->ypc_val.valdat_val);
free(new->ypc_map);
free(new);
return;
}
new->ypc_expire_t = time(NULL) + YPLIB_EXPIRE;
new->ypc_key.keydat_len = key->keydat_len;
new->ypc_val.valdat_len = val->valdat_len;
bcopy(key->keydat_val, new->ypc_key.keydat_val, key->keydat_len);
bcopy(val->valdat_val, new->ypc_val.valdat_val, val->valdat_len);
new->ypc_next = ypdb->cache;
ypdb->cache = new;
ypdb->ypmatch_cachecnt++;
return;
}
static bool_t
ypmatch_cache_lookup(struct dom_binding *ypdb, char *map, keydat *key,
valdat *val)
{
struct ypmatch_ent *c;
ypmatch_cache_expire(ypdb);
for (c = ypdb->cache; c != NULL; c = c->ypc_next) {
if (strcmp(map, c->ypc_map))
continue;
if (key->keydat_len != c->ypc_key.keydat_len)
continue;
if (bcmp(key->keydat_val, c->ypc_key.keydat_val,
key->keydat_len))
continue;
}
if (c == NULL)
return(FALSE);
val->valdat_len = c->ypc_val.valdat_len;
val->valdat_val = c->ypc_val.valdat_val;
return(TRUE);
}
#endif
const char *
ypbinderr_string(int incode)
{
static char err[80];
switch (incode) {
case 0:
return ("Success");
case YPBIND_ERR_ERR:
return ("Internal ypbind error");
case YPBIND_ERR_NOSERV:
return ("Domain not bound");
case YPBIND_ERR_RESC:
return ("System resource allocation failure");
}
sprintf(err, "Unknown ypbind error: #%d\n", incode);
return (err);
}
int
_yp_dobind(char *dom, struct dom_binding **ypdb)
{
static pid_t pid = -1;
char path[MAXPATHLEN];
struct dom_binding *ysd, *ysd2;
struct ypbind_resp ypbr;
struct timeval tv;
struct sockaddr_in clnt_sin;
int clnt_sock, fd;
pid_t gpid;
CLIENT *client;
int new = 0, r;
int retries = 0;
struct sockaddr_in check;
socklen_t checklen = sizeof(struct sockaddr_in);
/* Not allowed; bad doggie. Bad. */
if (strchr(dom, '/') != NULL)
return(YPERR_BADARGS);
gpid = getpid();
if (!(pid == -1 || pid == gpid)) {
ysd = _ypbindlist;
while (ysd) {
if (ysd->dom_client != NULL)
_yp_unbind(ysd);
ysd2 = ysd->dom_pnext;
free(ysd);
ysd = ysd2;
}
_ypbindlist = NULL;
}
pid = gpid;
if (ypdb != NULL)
*ypdb = NULL;
if (dom == NULL || strlen(dom) == 0)
return (YPERR_BADARGS);
for (ysd = _ypbindlist; ysd; ysd = ysd->dom_pnext)
if (strcmp(dom, ysd->dom_domain) == 0)
break;
if (ysd == NULL) {
ysd = (struct dom_binding *)malloc(sizeof *ysd);
if (ysd == NULL)
return (YPERR_RESRC);
bzero((char *)ysd, sizeof *ysd);
ysd->dom_socket = -1;
ysd->dom_vers = 0;
new = 1;
} else {
/* Check the socket -- may have been hosed by the caller. */
if (_getsockname(ysd->dom_socket, (struct sockaddr *)&check,
&checklen) == -1 || check.sin_family != AF_INET ||
check.sin_port != ysd->dom_local_port) {
/* Socket became bogus somehow... need to rebind. */
int save, sock;
sock = ysd->dom_socket;
save = _dup(ysd->dom_socket);
if (ysd->dom_client != NULL)
clnt_destroy(ysd->dom_client);
ysd->dom_vers = 0;
ysd->dom_client = NULL;
sock = _dup2(save, sock);
_close(save);
}
}
again:
retries++;
if (retries > MAX_RETRIES) {
if (new)
free(ysd);
return(YPERR_YPBIND);
}
#ifdef BINDINGDIR
if (ysd->dom_vers == 0) {
/*
* We're trying to make a new binding: zorch the
* existing handle now (if any).
*/
if (ysd->dom_client != NULL) {
clnt_destroy(ysd->dom_client);
ysd->dom_client = NULL;
ysd->dom_socket = -1;
}
snprintf(path, sizeof(path), "%s/%s.%d", BINDINGDIR, dom, 2);
if ((fd = _open(path, O_RDONLY | O_CLOEXEC)) == -1) {
/* no binding file, YP is dead. */
/* Try to bring it back to life. */
_close(fd);
goto skipit;
}
if (_flock(fd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK) {
struct iovec iov[2];
struct ypbind_resp ybr;
u_short ypb_port;
iov[0].iov_base = (caddr_t)&ypb_port;
iov[0].iov_len = sizeof ypb_port;
iov[1].iov_base = (caddr_t)&ybr;
iov[1].iov_len = sizeof ybr;
r = _readv(fd, iov, 2);
if (r != iov[0].iov_len + iov[1].iov_len) {
_close(fd);
ysd->dom_vers = -1;
goto again;
}
bzero(&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
ysd->dom_server_addr.sin_family = AF_INET;
ysd->dom_server_addr.sin_len = sizeof(struct sockaddr_in);
bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
&ysd->dom_server_addr.sin_addr.s_addr,
sizeof(ysd->dom_server_addr.sin_addr.s_addr));
bcopy(&ybr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
&ysd->dom_server_addr.sin_port,
sizeof(ysd->dom_server_addr.sin_port));
ysd->dom_server_port = ysd->dom_server_addr.sin_port;
_close(fd);
goto gotit;
} else {
/* no lock on binding file, YP is dead. */
/* Try to bring it back to life. */
_close(fd);
goto skipit;
}
}
skipit:
#endif
if (ysd->dom_vers == -1 || ysd->dom_vers == 0) {
/*
* We're trying to make a new binding: zorch the
* existing handle now (if any).
*/
if (ysd->dom_client != NULL) {
clnt_destroy(ysd->dom_client);
ysd->dom_client = NULL;
ysd->dom_socket = -1;
}
bzero((char *)&clnt_sin, sizeof clnt_sin);
clnt_sin.sin_family = AF_INET;
clnt_sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
clnt_sock = RPC_ANYSOCK;
client = clnttcp_create(&clnt_sin, YPBINDPROG, YPBINDVERS, &clnt_sock,
0, 0);
if (client == NULL) {
/*
* These conditions indicate ypbind just isn't
* alive -- we probably don't want to shoot our
* mouth off in this case; instead generate error
* messages only for really exotic problems.
*/
if (rpc_createerr.cf_stat != RPC_PROGNOTREGISTERED &&
(rpc_createerr.cf_stat != RPC_SYSTEMERROR &&
rpc_createerr.cf_error.re_errno == ECONNREFUSED))
clnt_pcreateerror("clnttcp_create");
if (new)
free(ysd);
return (YPERR_YPBIND);
}
/*
* Check the port number -- should be < IPPORT_RESERVED.
* If not, it's possible someone has registered a bogus
* ypbind with the portmapper and is trying to trick us.
*/
if (ntohs(clnt_sin.sin_port) >= IPPORT_RESERVED) {
if (client != NULL)
clnt_destroy(client);
if (new)
free(ysd);
return(YPERR_YPBIND);
}
tv.tv_sec = _yplib_timeout/2;
tv.tv_usec = 0;
r = clnt_call(client, YPBINDPROC_DOMAIN,
(xdrproc_t)xdr_domainname, &dom,
(xdrproc_t)xdr_ypbind_resp, &ypbr, tv);
if (r != RPC_SUCCESS) {
clnt_destroy(client);
ysd->dom_vers = -1;
if (r == RPC_PROGUNAVAIL || r == RPC_PROCUNAVAIL) {
if (new)
free(ysd);
return(YPERR_YPBIND);
}
fprintf(stderr,
"YP: server for domain %s not responding, retrying\n", dom);
goto again;
} else {
if (ypbr.ypbind_status != YPBIND_SUCC_VAL) {
struct timespec time_to_sleep, time_remaining;
clnt_destroy(client);
ysd->dom_vers = -1;
time_to_sleep.tv_sec = _yplib_timeout/2;
time_to_sleep.tv_nsec = 0;
_nanosleep(&time_to_sleep,
&time_remaining);
goto again;
}
}
clnt_destroy(client);
bzero((char *)&ysd->dom_server_addr, sizeof ysd->dom_server_addr);
ysd->dom_server_addr.sin_family = AF_INET;
bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port,
&ysd->dom_server_addr.sin_port,
sizeof(ysd->dom_server_addr.sin_port));
bcopy(&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_addr,
&ysd->dom_server_addr.sin_addr.s_addr,
sizeof(ysd->dom_server_addr.sin_addr.s_addr));
/*
* We could do a reserved port check here too, but this
* could pose compatibility problems. The local ypbind is
* supposed to decide whether or not to trust yp servers
* on insecure ports. For now, we trust its judgement.
*/
ysd->dom_server_port =
*(u_short *)&ypbr.ypbind_resp_u.ypbind_bindinfo.ypbind_binding_port;
gotit:
ysd->dom_vers = YPVERS;
strlcpy(ysd->dom_domain, dom, sizeof(ysd->dom_domain));
}
/* Don't rebuild the connection to the server unless we have to. */
if (ysd->dom_client == NULL) {
tv.tv_sec = _yplib_timeout/2;
tv.tv_usec = 0;
ysd->dom_socket = RPC_ANYSOCK;
ysd->dom_client = clntudp_bufcreate(&ysd->dom_server_addr,
YPPROG, YPVERS, tv, &ysd->dom_socket, 65507, 65507);
if (ysd->dom_client == NULL) {
clnt_pcreateerror("clntudp_create");
ysd->dom_vers = -1;
goto again;
}
if (_fcntl(ysd->dom_socket, F_SETFD, 1) == -1)
perror("fcntl: F_SETFD");
/*
* We want a port number associated with this socket
* so that we can check its authenticity later.
*/
checklen = sizeof(struct sockaddr_in);
bzero((char *)&check, checklen);
_bind(ysd->dom_socket, (struct sockaddr *)&check, checklen);
check.sin_family = AF_INET;
if (!_getsockname(ysd->dom_socket,
(struct sockaddr *)&check, &checklen)) {
ysd->dom_local_port = check.sin_port;
} else {
clnt_destroy(ysd->dom_client);
if (new)
free(ysd);
return(YPERR_YPBIND);
}
}
if (new) {
ysd->dom_pnext = _ypbindlist;
_ypbindlist = ysd;
}
/*
* Set low retry timeout to realistically handle UDP packet
* loss for YP packet bursts.
*/
tv.tv_sec = 1;
tv.tv_usec = 0;
clnt_control(ysd->dom_client, CLSET_RETRY_TIMEOUT, (char*)&tv);
if (ypdb != NULL)
*ypdb = ysd;
return (0);
}
static void
_yp_unbind(struct dom_binding *ypb)
{
struct sockaddr_in check;
socklen_t checklen = sizeof(struct sockaddr_in);
if (ypb->dom_client != NULL) {
/* Check the socket -- may have been hosed by the caller. */
if (_getsockname(ypb->dom_socket, (struct sockaddr *)&check,
&checklen) == -1 || check.sin_family != AF_INET ||
check.sin_port != ypb->dom_local_port) {
int save, sock;
sock = ypb->dom_socket;
save = _dup(ypb->dom_socket);
clnt_destroy(ypb->dom_client);
sock = _dup2(save, sock);
_close(save);
} else
clnt_destroy(ypb->dom_client);
}
ypb->dom_client = NULL;
ypb->dom_socket = -1;
ypb->dom_vers = -1;
#ifdef YPMATCHCACHE
ypmatch_cache_flush(ypb);
#endif
}
static int
yp_bind_locked(char *dom)
{
return (_yp_dobind(dom, NULL));
}
int
yp_bind(char *dom)
{
int r;
YPLOCK();
r = yp_bind_locked(dom);
YPUNLOCK();
return (r);
}
static void
yp_unbind_locked(char *dom)
{
struct dom_binding *ypb, *ypbp;
ypbp = NULL;
for (ypb = _ypbindlist; ypb; ypb = ypb->dom_pnext) {
if (strcmp(dom, ypb->dom_domain) == 0) {
_yp_unbind(ypb);
if (ypbp)
ypbp->dom_pnext = ypb->dom_pnext;
else
_ypbindlist = ypb->dom_pnext;
free(ypb);
return;
}
ypbp = ypb;
}
return;
}
void
yp_unbind(char *dom)
{
YPLOCK();
yp_unbind_locked(dom);
YPUNLOCK();
}
int
yp_match(char *indomain, char *inmap, const char *inkey, int inkeylen,
char **outval, int *outvallen)
{
struct dom_binding *ysd;
struct ypresp_val yprv;
struct timeval tv;
struct ypreq_key yprk;
int r;
int retries = 0;
*outval = NULL;
*outvallen = 0;
/* Sanity check */
if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
inmap == NULL || !strlen(inmap) ||
indomain == NULL || !strlen(indomain))
return (YPERR_BADARGS);
YPLOCK();
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return(YPERR_DOMAIN);
}
yprk.domain = indomain;
yprk.map = inmap;
yprk.key.keydat_val = (char *)inkey;
yprk.key.keydat_len = inkeylen;
#ifdef YPMATCHCACHE
if (ypmatch_cache_lookup(ysd, yprk.map, &yprk.key, &yprv.val) == TRUE) {
/*
if (!strcmp(_yp_domain, indomain) && ypmatch_find(inmap, inkey,
inkeylen, &yprv.val.valdat_val, &yprv.val.valdat_len)) {
*/
*outvallen = yprv.val.valdat_len;
*outval = (char *)malloc(*outvallen+1);
if (*outval == NULL) {
_yp_unbind(ysd);
*outvallen = 0;
YPUNLOCK();
return (YPERR_RESRC);
}
bcopy(yprv.val.valdat_val, *outval, *outvallen);
(*outval)[*outvallen] = '\0';
YPUNLOCK();
return (0);
}
_yp_unbind(ysd);
#endif
again:
if (retries > MAX_RETRIES) {
YPUNLOCK();
return (YPERR_RPC);
}
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return (YPERR_DOMAIN);
}
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
bzero((char *)&yprv, sizeof yprv);
r = clnt_call(ysd->dom_client, YPPROC_MATCH,
(xdrproc_t)xdr_ypreq_key, &yprk,
(xdrproc_t)xdr_ypresp_val, &yprv, tv);
if (r != RPC_SUCCESS) {
clnt_perror(ysd->dom_client, "yp_match: clnt_call");
_yp_unbind(ysd);
retries++;
goto again;
}
if (!(r = ypprot_err(yprv.stat))) {
*outvallen = yprv.val.valdat_len;
*outval = (char *)malloc(*outvallen+1);
if (*outval == NULL) {
_yp_unbind(ysd);
*outvallen = 0;
xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
YPUNLOCK();
return (YPERR_RESRC);
}
bcopy(yprv.val.valdat_val, *outval, *outvallen);
(*outval)[*outvallen] = '\0';
#ifdef YPMATCHCACHE
ypmatch_cache_insert(ysd, yprk.map, &yprk.key, &yprv.val);
#endif
}
xdr_free((xdrproc_t)xdr_ypresp_val, &yprv);
YPUNLOCK();
return (r);
}
static int
yp_get_default_domain_locked(char **domp)
{
*domp = NULL;
if (_yp_domain[0] == '\0')
if (getdomainname(_yp_domain, sizeof _yp_domain))
return (YPERR_NODOM);
*domp = _yp_domain;
return (0);
}
int
yp_get_default_domain(char **domp)
{
int r;
YPLOCK();
r = yp_get_default_domain_locked(domp);
YPUNLOCK();
return (r);
}
int
yp_first(char *indomain, char *inmap, char **outkey, int *outkeylen,
char **outval, int *outvallen)
{
struct ypresp_key_val yprkv;
struct ypreq_nokey yprnk;
struct dom_binding *ysd;
struct timeval tv;
int r;
int retries = 0;
/* Sanity check */
if (indomain == NULL || !strlen(indomain) ||
inmap == NULL || !strlen(inmap))
return (YPERR_BADARGS);
*outkey = *outval = NULL;
*outkeylen = *outvallen = 0;
YPLOCK();
again:
if (retries > MAX_RETRIES) {
YPUNLOCK();
return (YPERR_RPC);
}
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return (YPERR_DOMAIN);
}
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
yprnk.domain = indomain;
yprnk.map = inmap;
bzero((char *)&yprkv, sizeof yprkv);
r = clnt_call(ysd->dom_client, YPPROC_FIRST,
(xdrproc_t)xdr_ypreq_nokey, &yprnk,
(xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
if (r != RPC_SUCCESS) {
clnt_perror(ysd->dom_client, "yp_first: clnt_call");
_yp_unbind(ysd);
retries++;
goto again;
}
if (!(r = ypprot_err(yprkv.stat))) {
*outkeylen = yprkv.key.keydat_len;
*outkey = (char *)malloc(*outkeylen+1);
if (*outkey == NULL) {
_yp_unbind(ysd);
*outkeylen = 0;
xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
YPUNLOCK();
return (YPERR_RESRC);
}
bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
(*outkey)[*outkeylen] = '\0';
*outvallen = yprkv.val.valdat_len;
*outval = (char *)malloc(*outvallen+1);
if (*outval == NULL) {
free(*outkey);
_yp_unbind(ysd);
*outkeylen = *outvallen = 0;
xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
YPUNLOCK();
return (YPERR_RESRC);
}
bcopy(yprkv.val.valdat_val, *outval, *outvallen);
(*outval)[*outvallen] = '\0';
}
xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
YPUNLOCK();
return (r);
}
int
yp_next(char *indomain, char *inmap, char *inkey, int inkeylen,
char **outkey, int *outkeylen, char **outval, int *outvallen)
{
struct ypresp_key_val yprkv;
struct ypreq_key yprk;
struct dom_binding *ysd;
struct timeval tv;
int r;
int retries = 0;
/* Sanity check */
if (inkey == NULL || !strlen(inkey) || inkeylen <= 0 ||
inmap == NULL || !strlen(inmap) ||
indomain == NULL || !strlen(indomain))
return (YPERR_BADARGS);
*outkey = *outval = NULL;
*outkeylen = *outvallen = 0;
YPLOCK();
again:
if (retries > MAX_RETRIES) {
YPUNLOCK();
return (YPERR_RPC);
}
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return (YPERR_DOMAIN);
}
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
yprk.domain = indomain;
yprk.map = inmap;
yprk.key.keydat_val = inkey;
yprk.key.keydat_len = inkeylen;
bzero((char *)&yprkv, sizeof yprkv);
r = clnt_call(ysd->dom_client, YPPROC_NEXT,
(xdrproc_t)xdr_ypreq_key, &yprk,
(xdrproc_t)xdr_ypresp_key_val, &yprkv, tv);
if (r != RPC_SUCCESS) {
clnt_perror(ysd->dom_client, "yp_next: clnt_call");
_yp_unbind(ysd);
retries++;
goto again;
}
if (!(r = ypprot_err(yprkv.stat))) {
*outkeylen = yprkv.key.keydat_len;
*outkey = (char *)malloc(*outkeylen+1);
if (*outkey == NULL) {
_yp_unbind(ysd);
*outkeylen = 0;
xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
YPUNLOCK();
return (YPERR_RESRC);
}
bcopy(yprkv.key.keydat_val, *outkey, *outkeylen);
(*outkey)[*outkeylen] = '\0';
*outvallen = yprkv.val.valdat_len;
*outval = (char *)malloc(*outvallen+1);
if (*outval == NULL) {
free(*outkey);
_yp_unbind(ysd);
*outkeylen = *outvallen = 0;
xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
YPUNLOCK();
return (YPERR_RESRC);
}
bcopy(yprkv.val.valdat_val, *outval, *outvallen);
(*outval)[*outvallen] = '\0';
}
xdr_free((xdrproc_t)xdr_ypresp_key_val, &yprkv);
YPUNLOCK();
return (r);
}
int
yp_all(char *indomain, char *inmap, struct ypall_callback *incallback)
{
struct ypreq_nokey yprnk;
struct dom_binding *ysd;
struct timeval tv;
struct sockaddr_in clnt_sin;
CLIENT *clnt;
u_long status, savstat;
int clnt_sock;
int retries = 0;
/* Sanity check */
if (indomain == NULL || !strlen(indomain) ||
inmap == NULL || !strlen(inmap))
return (YPERR_BADARGS);
YPLOCK();
again:
if (retries > MAX_RETRIES) {
YPUNLOCK();
return (YPERR_RPC);
}
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return (YPERR_DOMAIN);
}
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
/* YPPROC_ALL manufactures its own channel to ypserv using TCP */
clnt_sock = RPC_ANYSOCK;
clnt_sin = ysd->dom_server_addr;
clnt_sin.sin_port = 0;
clnt = clnttcp_create(&clnt_sin, YPPROG, YPVERS, &clnt_sock, 0, 0);
if (clnt == NULL) {
YPUNLOCK();
printf("clnttcp_create failed\n");
return (YPERR_PMAP);
}
yprnk.domain = indomain;
yprnk.map = inmap;
ypresp_allfn = incallback->foreach;
ypresp_data = (void *)incallback->data;
if (clnt_call(clnt, YPPROC_ALL,
(xdrproc_t)xdr_ypreq_nokey, &yprnk,
(xdrproc_t)xdr_ypresp_all_seq, &status, tv) != RPC_SUCCESS) {
clnt_perror(clnt, "yp_all: clnt_call");
clnt_destroy(clnt);
_yp_unbind(ysd);
retries++;
goto again;
}
clnt_destroy(clnt);
savstat = status;
xdr_free((xdrproc_t)xdr_ypresp_all_seq, &status); /* not really needed... */
YPUNLOCK();
if (savstat != YP_NOMORE)
return (ypprot_err(savstat));
return (0);
}
int
yp_order(char *indomain, char *inmap, int *outorder)
{
struct dom_binding *ysd;
struct ypresp_order ypro;
struct ypreq_nokey yprnk;
struct timeval tv;
int r;
/* Sanity check */
if (indomain == NULL || !strlen(indomain) ||
inmap == NULL || !strlen(inmap))
return (YPERR_BADARGS);
YPLOCK();
again:
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return (YPERR_DOMAIN);
}
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
yprnk.domain = indomain;
yprnk.map = inmap;
bzero((char *)(char *)&ypro, sizeof ypro);
r = clnt_call(ysd->dom_client, YPPROC_ORDER,
(xdrproc_t)xdr_ypreq_nokey, &yprnk,
(xdrproc_t)xdr_ypresp_order, &ypro, tv);
/*
* NIS+ in YP compat mode doesn't support the YPPROC_ORDER
* procedure.
*/
if (r == RPC_PROCUNAVAIL) {
YPUNLOCK();
return(YPERR_YPERR);
}
if (r != RPC_SUCCESS) {
clnt_perror(ysd->dom_client, "yp_order: clnt_call");
_yp_unbind(ysd);
goto again;
}
if (!(r = ypprot_err(ypro.stat))) {
*outorder = ypro.ordernum;
}
xdr_free((xdrproc_t)xdr_ypresp_order, &ypro);
YPUNLOCK();
return (r);
}
int
yp_master(char *indomain, char *inmap, char **outname)
{
struct dom_binding *ysd;
struct ypresp_master yprm;
struct ypreq_nokey yprnk;
struct timeval tv;
int r;
/* Sanity check */
if (indomain == NULL || !strlen(indomain) ||
inmap == NULL || !strlen(inmap))
return (YPERR_BADARGS);
YPLOCK();
again:
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return (YPERR_DOMAIN);
}
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
yprnk.domain = indomain;
yprnk.map = inmap;
bzero((char *)&yprm, sizeof yprm);
r = clnt_call(ysd->dom_client, YPPROC_MASTER,
(xdrproc_t)xdr_ypreq_nokey, &yprnk,
(xdrproc_t)xdr_ypresp_master, &yprm, tv);
if (r != RPC_SUCCESS) {
clnt_perror(ysd->dom_client, "yp_master: clnt_call");
_yp_unbind(ysd);
goto again;
}
if (!(r = ypprot_err(yprm.stat))) {
*outname = (char *)strdup(yprm.peer);
}
xdr_free((xdrproc_t)xdr_ypresp_master, &yprm);
YPUNLOCK();
return (r);
}
int
yp_maplist(char *indomain, struct ypmaplist **outmaplist)
{
struct dom_binding *ysd;
struct ypresp_maplist ypml;
struct timeval tv;
int r;
/* Sanity check */
if (indomain == NULL || !strlen(indomain))
return (YPERR_BADARGS);
YPLOCK();
again:
if (_yp_dobind(indomain, &ysd) != 0) {
YPUNLOCK();
return (YPERR_DOMAIN);
}
tv.tv_sec = _yplib_timeout;
tv.tv_usec = 0;
bzero((char *)&ypml, sizeof ypml);
r = clnt_call(ysd->dom_client, YPPROC_MAPLIST,
(xdrproc_t)xdr_domainname, &indomain,
(xdrproc_t)xdr_ypresp_maplist, &ypml,tv);
if (r != RPC_SUCCESS) {
clnt_perror(ysd->dom_client, "yp_maplist: clnt_call");
_yp_unbind(ysd);
goto again;
}
if (!(r = ypprot_err(ypml.stat))) {
*outmaplist = ypml.maps;
}
/* NO: xdr_free((xdrproc_t)xdr_ypresp_maplist, &ypml);*/
YPUNLOCK();
return (r);
}
const char *
yperr_string(int incode)
{
static char err[80];
switch (incode) {
case 0:
return ("Success");
case YPERR_BADARGS:
return ("Request arguments bad");
case YPERR_RPC:
return ("RPC failure");
case YPERR_DOMAIN:
return ("Can't bind to server which serves this domain");
case YPERR_MAP:
return ("No such map in server's domain");
case YPERR_KEY:
return ("No such key in map");
case YPERR_YPERR:
return ("YP server error");
case YPERR_RESRC:
return ("Local resource allocation failure");
case YPERR_NOMORE:
return ("No more records in map database");
case YPERR_PMAP:
return ("Can't communicate with portmapper");
case YPERR_YPBIND:
return ("Can't communicate with ypbind");
case YPERR_YPSERV:
return ("Can't communicate with ypserv");
case YPERR_NODOM:
return ("Local domain name not set");
case YPERR_BADDB:
return ("Server data base is bad");
case YPERR_VERS:
return ("YP server version mismatch - server can't supply service.");
case YPERR_ACCESS:
return ("Access violation");
case YPERR_BUSY:
return ("Database is busy");
}
sprintf(err, "YP unknown error %d\n", incode);
return (err);
}
int
ypprot_err(unsigned int incode)
{
switch (incode) {
case YP_TRUE:
return (0);
case YP_FALSE:
return (YPERR_YPBIND);
case YP_NOMORE:
return (YPERR_NOMORE);
case YP_NOMAP:
return (YPERR_MAP);
case YP_NODOM:
return (YPERR_DOMAIN);
case YP_NOKEY:
return (YPERR_KEY);
case YP_BADOP:
return (YPERR_YPERR);
case YP_BADDB:
return (YPERR_BADDB);
case YP_YPERR:
return (YPERR_YPERR);
case YP_BADARGS:
return (YPERR_BADARGS);
case YP_VERS:
return (YPERR_VERS);
}
return (YPERR_YPERR);
}
int
_yp_check(char **dom)
{
char *unused;
YPLOCK();
if (_yp_domain[0]=='\0')
if (yp_get_default_domain_locked(&unused)) {
YPUNLOCK();
return (0);
}
if (dom)
*dom = _yp_domain;
if (yp_bind_locked(_yp_domain) == 0) {
yp_unbind_locked(_yp_domain);
YPUNLOCK();
return (1);
}
YPUNLOCK();
return (0);
}

File Metadata

Mime Type
application/octet-stream
Expires
Mon, Jul 1, 11:01 AM (2 d)
Storage Engine
chunks
Storage Format
Chunks
Storage Handle
hPLLZ4RUWxkS
Default Alt Text
(5 MB)

Event Timeline