Compare commits

...

50 Commits

Author SHA1 Message Date
Guillem Jover
54796231c7 Release libbsd 0.11.4 2022-01-22 22:41:51 +01:00
Guillem Jover
7aed0edf73 man: Add missing comma in .Dd for tree(3)
Reported-by: Thorsten Glaser <tg@mirbsd.de>
2021-12-02 00:35:40 +01:00
Guillem Jover
fafcc397ac man: Update tree(3) man page from OpenBSD
This man page has a BSD-3-clause-author license instead of the old
BSD-4-clause license.
2021-12-01 04:17:11 +01:00
Guillem Jover
48107fc8c4 build: Clarify link-time warnings
Mention the involved function instead of stating an implicit "this
function". Mention libbsd when proposing using an alternative libmd
to make the context clear.
2021-12-01 04:17:11 +01:00
Guillem Jover
e7cf8c5785 Switch md5 compatibility logic back to direct linking
When using the recent dlsym() based wrapper, we are not requiring any
symbol from libmd, as we resolve those dynamically at run-time. We were
ending up linking against libmd because in another part of the code we
require (depending on the architecture) the SHA512 functions for the
getentropy() local implementation. But that function might be provided
by the system libc on some systems, which means we end up not linking
against libmd at all.

To solve this we go back to the previous simpler solution of linking
directly, which had the main drawback of then making programs fail to
link when not specifying -lmd (on platforms that need it). And then
switch the .so link point from a symlink to a linker script, so that we
can inject the -lmd library as-needed. This is similar to what glibc is
doing.

Fixes: commit 31f034e386
2021-12-01 04:14:35 +01:00
Guillem Jover
25d35625eb build: Split libmd dependency due to MD5 functions from SHA requirements
To be able to rework the md5 deprecation logic, we need to detangle when
we depend on libmd due to requiring MD5 functions, which might be
otherwise provided by libc, or when we require SHA functions for the
internal getentropy() implementation.
2021-11-28 22:40:58 +01:00
Guillem Jover
500b3080a2 build: Add new libbsd_symver_weak() macro
We will use it for the reworked md5 deprecation logic.
2021-11-28 22:34:59 +01:00
Guillem Jover
1eba406021 test: Check that strdup() does not fail
Warned-by: gcc
2021-11-27 23:42:37 +01:00
Guillem Jover
8ad7570c20 getentropy: Add missing prototype for BSD variant
Warned-by: gcc
2021-11-27 23:42:37 +01:00
Guillem Jover
43a8270317 nlist: Remove condition which is always true
The nlist() function is limited to handle ELF binaries of the same class
as size as the size_t of the architecture built.

In addition the SIZE_T_MAX macro is BSD specific, and was falling back
to the wrong constant on most 64-bit non-BSD systems.

Warned-by: gcc
2021-11-27 23:36:34 +01:00
Guillem Jover
6a71b24b63 build: Append __ after __attribute and __typeof keywords
Be consistent with other usages in the code base.
2021-11-27 22:53:32 +01:00
Guillem Jover
7389fe8d24 build: Ignore backup files 2021-11-27 06:54:49 +01:00
Victor Westerhuis
2716dfd0b7 test: Explicitly mark symbols as used
Because some of the symbols are not otherwise referenced, GCC would like
to remove them.

Closes: !14
Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-11-27 06:52:17 +01:00
Victor Westerhuis
54f8745657 build: Enable .init_array support when building with LTO
Because these symbols are not otherwise referenced, GCC would like
to remove them.

Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-11-27 06:51:02 +01:00
Guillem Jover
428be9e030 man: Fix .Nx macro usage
Its arguments are used as version numbers, so we need continue the
content on the next line.
2021-11-27 05:06:14 +01:00
Alexander Miller
c7a5d780ae build: Allow building with -flto on gcc-10 and newer
Global asm statements (like .symver directives) do not work reliably
in gcc with link time optimization. Use the symver attribute introduced
with gcc-10 to set symbol versions instead, if available.

[guillem@hadrons.org:
 - Simplify by using __has_attribute fallback from <sys/cdefs.h>.
 - Coding style changes. ]

Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-11-27 05:06:14 +01:00
Guillem Jover
1808d64b77 test: Fix pipe_feed() to allow checking fprintf format strings
Warned-by: gcc -W
2021-11-27 05:06:14 +01:00
Guillem Jover
beafad2657 build: Add missing proctitle unit test program 2021-11-27 05:06:14 +01:00
Guillem Jover
6145b56178 test: Do not pass NULL as the first funopen() argument
Warned-by: gcc -W
2021-11-27 05:06:14 +01:00
Guillem Jover
731b0a7739 build: Detect sed at configure time
Check whether sed is available and use the implementation matching the
requirements via the SED variable.
2021-11-27 05:06:14 +01:00
Guillem Jover
50b50a4330 vis: Add prototypes for strnvis() and strnunvis() variants
Warned-by: gcc
2021-11-27 05:06:14 +01:00
Guillem Jover
25e88f6479 test: Cast literal strings to (char *) on n_name assignment
The member is declared as n_name so we cannot directly assign a literal
string constant.

Warned-by: gcc
2021-11-27 05:06:14 +01:00
Guillem Jover
04a8fb2469 Add missing prototypes to functions
Warned-by: gcc
2021-11-27 05:06:14 +01:00
Guillem Jover
4f68a88f55 build: Add compiler warnings support
Detect as many warnings as possible during configure and enable them
if the user did not supply any, so that any such problem can be spotted
and fixed.
2021-11-27 05:06:14 +01:00
Guillem Jover
8f59221c4f nlist: Remove repeated shadowing variable declaration
Warned-by: gcc
2021-02-28 05:30:37 +01:00
Guillem Jover
72a82ee262 getentropy: Fix function cast for getauxval()
Warned-by: gcc
2021-02-28 05:30:37 +01:00
Guillem Jover
3c305f2873 test: Add proper prototypes for main() function
Warned-by: gcc
2021-02-28 05:30:31 +01:00
Guillem Jover
25278891d8 Mark local functions as static
Warned-by: gcc
2021-02-28 05:30:25 +01:00
Guillem Jover
e35d9141dc Add link-time warnings to MD5 wrapper functions
Let's get the word out that these functions are deprecated and should be
switched away from.
2021-02-28 05:28:57 +01:00
Guillem Jover
4feda87049 Require a semicolon for libbsd_link_warning() macro
Remove the semicolon in the macro definition to force adding one on the
call sites, to make the code look like an actual function.
2021-02-28 05:28:57 +01:00
Guillem Jover
d563a17430 man: Call the libbsd-ctor library by its name instead of bsd-ctor 2021-02-28 05:28:57 +01:00
Guillem Jover
785cf9d1e9 man: Fix pkg-config(1) references in libbsd(7) man page 2021-02-28 05:28:57 +01:00
Guillem Jover
15bd284b29 build: Add code coverage support in the GitLab CI 2021-02-28 05:28:49 +01:00
Guillem Jover
a9fc285988 build: Use apt-get instead of apt in the GitLab CI
The former is to be used programmatically, while the latter is intended
for interactive use.
2021-02-28 05:27:35 +01:00
Guillem Jover
c0d86a6412 build: Add a Libs.private field to overlay pkg-config file
We need to list all internal libraries there so that we can statically
link.

Fixes: commit 2374f409de
2021-02-09 08:36:01 +01:00
Guillem Jover
1fb25b7dca Release libbsd 0.11.3 2021-02-09 06:23:38 +01:00
Guillem Jover
31f034e386 Switch libmd wrapper to use dlsym()
Switch from the previous versioned symbol implementation which required
users to also link against the message digest provider explicitly, or
they would fail to find the symbols, to an implementation that loads
the symbols from the linked library providing the functions using
dlsym(), thus preserving backwards compatibility.
2021-02-09 06:23:38 +01:00
Guillem Jover
2374f409de build: Add a Libs.private field to pkg-config file
We need to list all internal libraries there so that we can statically
link.
2021-02-09 06:23:38 +01:00
Guillem Jover
a4e0db2b97 build: Use a single variable to track libraries to link against
Using various variables means we have to keep these in sync in various
places. Just use a single variable that we can use anywhere where this
is needed.
2021-02-09 06:23:38 +01:00
Guillem Jover
43d34c9d3b build: Fix message digest library checks
They were not failing when not finding the SHA-2 functions and
were hardcoding -lmd regardless of what library had been found.
2021-02-09 06:23:38 +01:00
Guillem Jover
1c3ff61699 Use uintptr_t and size_t instead of __-prefixed types in <sys/cdefs.h>
The __-prefixed types cannot be assumed to be defined. Use the standard
types instead.

Closes: #6
2021-02-09 06:23:27 +01:00
Guillem Jover
edea268ce9 Release libbsd 0.11.2 2021-02-08 04:02:46 +01:00
Guillem Jover
e832b7687e closefrom: Use close_range() on Linux when available
Closes: !11
Based-on-patch-by: cptpcrd <cptpcrd.git@gmail.com>
Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-02-08 04:02:46 +01:00
cptpcrd
c4fca5bb4f closefrom: Handle lowfd < 0 properly
More important if close_range() is going to be used, since casting
negative values to 'unsigned int' might hide the errors.

[guillem@hadrons.org: Minor coding style fix. ]

Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-02-08 04:02:46 +01:00
Guillem Jover
a1f79978e8 closefrom: Import some changes from sudo
Take most of the changes done in sudo, but preserve the existing local
changes and refactoring.

In addition, refactor pstat implementation into closefrom_pstat(), so
that the code is easier to read, and requires no conditional
declarations.
2021-02-08 04:02:46 +01:00
Faidon Liambotis
4676026286 Update <sys/queue.h> from FreeBSD
This brings <sys/queue.h> to the most up-to-date version from FreeBSD,
incorporating 18 commits from the past 5 years (2015-02-24 - 2021-01-25):

  $ git log --oneline 9090a24aed70..8d55837dc133 sys/sys/queue.h share/man/man3/queue.3

Only minimal changes compared to the FreeBSD version have been applied
(queue.3 -> queue.3bsd, _LIBBSD_ prefix).

[guillem@hadrons.org: Remove reference to kernel mode in man page. ]

Closes: !12
Signed-off-by: Guillem Jover <guillem@hadrons.org>
2021-02-08 04:02:16 +01:00
Guillem Jover
25f9b30678 test: Improve code coverage for strnstr(3) unit tests 2021-02-07 23:24:51 +01:00
Guillem Jover
18ebabf223 man: Update libbsd(7) man page with updates in 0.11.0 2021-02-07 15:17:33 +01:00
Guillem Jover
4ab11c7f48 build: Install libmd-dev in the gitlab CI 2021-02-07 10:37:18 +01:00
Guillem Jover
766c883e30 build: Switch gitlab CI to use a Debian buster 2021-02-07 10:35:57 +01:00
51 changed files with 1010 additions and 355 deletions

5
.gitignore vendored
View File

@@ -1,4 +1,5 @@
ChangeLog
*~
*.pc
*.la
*.lo
@@ -7,6 +8,8 @@ ChangeLog
*.a
*.log
*.trs
*.gcda
*.gcno
.dirstamp
.deps/
.libs/
@@ -17,6 +20,6 @@ autom4te.cache/
build-aux/
configure
config.*
format.ld
libtool
m4/
stamp-h1

View File

@@ -1,9 +1,19 @@
image: debian:stretch
image: debian:buster
test:
before_script:
- apt update -qq
- apt install -qq -y --no-install-recommends git gcc make autoconf automake libtool
before_script:
- apt-get update -qq
- apt-get install -qq -y --no-install-recommends
git gcc make autoconf automake libtool libmd-dev gcovr
unit-tests:
stage: test
script:
- ./autogen && ./configure
- make check
coverage:
stage: test
script:
- ./autogen && ./configure --disable-static
- make check CFLAGS="--coverage -O0 -ggdb" LDFLAGS="--coverage -O0 -ggdb"
- gcovr -s -e test/

View File

@@ -8,7 +8,6 @@ License: BSD-3-clause
Files:
man/arc4random.3bsd
man/tree.3bsd
Copyright:
Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
All rights reserved.
@@ -348,6 +347,7 @@ License: BSD-2-clause-verbatim
Files:
include/bsd/sys/tree.h
man/fparseln.3bsd
man/tree.3bsd
src/fparseln.c
Copyright:
Copyright © 1997 Christos Zoulas.

View File

@@ -13,7 +13,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])],
LIBBSD_ABI_MAJOR=0
LIBBSD_ABI_MINOR=11
LIBBSD_ABI_PATCH=1
LIBBSD_ABI_PATCH=4
LIBBSD_ABI="$LIBBSD_ABI_MAJOR:$LIBBSD_ABI_MINOR:$LIBBSD_ABI_PATCH"
AC_SUBST([LIBBSD_ABI])
@@ -48,13 +48,50 @@ AM_CONDITIONAL([HAVE_LINKER_VERSION_SCRIPT],
# Checks for programs.
AC_PROG_CC
AC_PROG_SED
AC_PROG_INSTALL
AC_PROG_LN_S
# Set default compiler variables
if test "$user_CFLAGS" = unset && test "$GCC" = yes; then
CFLAGS="$CFLAGS -Wall -Wextra -Wno-unused-variable -Wno-unused-parameter"
fi
AS_IF([test "$user_CFLAGS" = unset], [
LIBBSD_CHECK_COMPILER_FLAG([-Wall])
LIBBSD_CHECK_COMPILER_FLAG([-Wextra])
LIBBSD_CHECK_COMPILER_FLAG([-Wbad-function-cast])
LIBBSD_CHECK_COMPILER_FLAG([-Wc99-c11-compat])
LIBBSD_CHECK_COMPILER_FLAG([-Wcast-align])
LIBBSD_CHECK_COMPILER_FLAG([-Wdeclaration-after-statement])
LIBBSD_CHECK_COMPILER_FLAG([-Wdocumentation])
LIBBSD_CHECK_COMPILER_FLAG([-Wduplicated-branches])
LIBBSD_CHECK_COMPILER_FLAG([-Wduplicated-cond])
LIBBSD_CHECK_COMPILER_FLAG([-Wformat -Wformat-security])
LIBBSD_CHECK_COMPILER_FLAG([-Wformat=2])
LIBBSD_CHECK_COMPILER_FLAG([-Winit-self])
LIBBSD_CHECK_COMPILER_FLAG([-Wlogical-not-parentheses])
LIBBSD_CHECK_COMPILER_FLAG([-Wlogical-op])
LIBBSD_CHECK_COMPILER_FLAG([-Wmissing-declarations])
LIBBSD_CHECK_COMPILER_FLAG([-Wmissing-format-attribute])
LIBBSD_CHECK_COMPILER_FLAG([-Wmissing-prototypes])
LIBBSD_CHECK_COMPILER_FLAG([-Wnested-externs])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-missing-field-initializers])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-nonnull-compare])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-tautological-constant-out-of-range-compare])
LIBBSD_CHECK_COMPILER_FLAG([-Wno-unused-parameter])
LIBBSD_CHECK_COMPILER_FLAG([-Wnull-dereference])
LIBBSD_CHECK_COMPILER_FLAG([-Wold-style-definition])
LIBBSD_CHECK_COMPILER_FLAG([-Wpointer-arith])
LIBBSD_CHECK_COMPILER_FLAG([-Wregister])
LIBBSD_CHECK_COMPILER_FLAG([-Wrestrict])
LIBBSD_CHECK_COMPILER_FLAG([-Wshadow])
LIBBSD_CHECK_COMPILER_FLAG([-Wshift-negative-value])
LIBBSD_CHECK_COMPILER_FLAG([-Wsizeof-array-argument])
LIBBSD_CHECK_COMPILER_FLAG([-Wstrict-prototypes])
LIBBSD_CHECK_COMPILER_FLAG([-Wswitch-bool])
LIBBSD_CHECK_COMPILER_FLAG([-Wvla])
LIBBSD_CHECK_COMPILER_FLAG([-Wwrite-strings])
CFLAGS="$CFLAGS $LIBBSD_COMPILER_FLAGS"
])
# Checks for libraries.
AC_CHECK_LIB([testu01], [unif01_CreateExternGenBits],
@@ -65,15 +102,25 @@ AM_CONDITIONAL([HAVE_LIBTESTU01],
saved_LIBS="$LIBS"
AC_SEARCH_LIBS([MD5Update], [md], [
AC_SEARCH_LIBS([SHA512Update], [md], [
MD_LIBS="-lmd"
AS_IF([test "x$ac_cv_search_MD5Update" != "xnone required"], [
MD5_LIBS="$MD5_LIBS $ac_cv_search_MD5Update"
need_transparent_libmd=yes
])
], [
AC_MSG_ERROR([cannot find required message digest functions in libc or libmd])
AC_MSG_ERROR([cannot find required MD5 functions in libc or libmd])
])
AC_SEARCH_LIBS([SHA512Update], [md], [
AS_IF([test "x$ac_cv_search_SHA512Update" != "xnone required"], [
LIBBSD_LIBS="$LIBBSD_LIBS $ac_cv_search_SHA512Update"
])
], [
AC_MSG_ERROR([cannot find required SHA-2 functions in libc or libmd])
])
AC_SUBST([MD_LIBS])
LIBS="$saved_LIBS"
AM_CONDITIONAL([NEED_TRANSPARENT_LIBMD],
[test "x$need_transparent_libmd" = "xyes"])
is_windows=no
AS_CASE([$host_os],
[*-gnu*], [
@@ -81,10 +128,9 @@ AS_CASE([$host_os],
saved_LIBS="$LIBS"
AC_SEARCH_LIBS([clock_gettime], [rt], [
AS_IF([test "x$ac_cv_search_clock_gettime" != "xnone required"], [
CLOCK_GETTIME_LIBS="$ac_cv_search_clock_gettime"
LIBBSD_LIBS="$LIBBSD_LIBS $ac_cv_search_clock_gettime"
])
])
AC_SUBST([CLOCK_GETTIME_LIBS])
LIBS="$saved_LIBS"
],
[*-musl*], [
@@ -126,7 +172,7 @@ AC_CACHE_CHECK(
[[
static int rc = 1;
static void init(int argc) { if (argc == 1) rc = 0; }
void (*init_func)(int argc) __attribute__((__section__(".init_array"))) = init;
void (*init_func)(int argc) __attribute__((__section__(".init_array"), __used__)) = init;
int main() { return rc; }
]]
)],
@@ -192,8 +238,7 @@ AC_LINK_IFELSE(
[AC_DEFINE([HAVE___REGISTER_ATFORK], [1],
[Define to 1 if you have __register_atfork])
AC_MSG_RESULT([yes])],
[ARC4RANDOM_ATFORK_LIBS="-pthread"
AC_SUBST([ARC4RANDOM_ATFORK_LIBS])
[LIBBSD_LIBS="$LIBBSD_LIBS -pthread"
AC_MSG_RESULT([no])
])
@@ -202,6 +247,9 @@ AC_CHECK_FUNCS([clearenv dirfd fopencookie __fpurge \
pstat_getproc sysconf])
AM_CONDITIONAL([HAVE_GETENTROPY], [test "x$ac_cv_func_getentropy" = "xtrue"])
AC_SUBST([MD5_LIBS])
AC_SUBST([LIBBSD_LIBS])
AC_CONFIG_FILES([
Makefile
include/Makefile

View File

@@ -187,10 +187,10 @@
# else
# ifndef __cplusplus
# define __offsetof(type, field) \
((__size_t)(__uintptr_t)((const volatile void *)&((type *)0)->field))
((size_t)(uintptr_t)((const volatile void *)&((type *)0)->field))
# else
# define __offsetof(type, field) \
(__offsetof__ (reinterpret_cast <__size_t> \
(__offsetof__ (reinterpret_cast <size_t> \
(&reinterpret_cast <const volatile char &> \
(static_cast<type *> (0)->field))))
# endif
@@ -243,15 +243,15 @@
#endif
#ifndef __DECONST
#define __DECONST(type, var) ((type)(__uintptr_t)(const void *)(var))
#define __DECONST(type, var) ((type)(uintptr_t)(const void *)(var))
#endif
#ifndef __DEVOLATILE
#define __DEVOLATILE(type, var) ((type)(__uintptr_t)(volatile void *)(var))
#define __DEVOLATILE(type, var) ((type)(uintptr_t)(volatile void *)(var))
#endif
#ifndef __DEQUALIFY
#define __DEQUALIFY(type, var) ((type)(__uintptr_t)(const volatile void *)(var))
#define __DEQUALIFY(type, var) ((type)(uintptr_t)(const volatile void *)(var))
#endif
#endif

View File

@@ -1,4 +1,6 @@
/*-
* SPDX-License-Identifier: BSD-3-Clause
*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
*
@@ -10,7 +12,7 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 4. Neither the name of the University nor the names of its contributors
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
@@ -80,17 +82,25 @@
*
* For details on the use of these macros, see the queue(3) manual page.
*
* Below is a summary of implemented functions where:
* + means the macro is available
* - means the macro is not available
* s means the macro is available but is slow (runs in O(n) time)
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _CLASS_HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _CLASS_ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _END + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - + - +
* _LAST - - + +
* _LAST_FAST - - - +
* _FOREACH + + + +
* _FOREACH_FROM + + + +
* _FOREACH_SAFE + + + +
@@ -103,14 +113,20 @@
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _CONCAT s s + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
* _REMOVE s + s +
* _SWAP + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
#define QUEUE_MACRO_DEBUG_TRACE
#define QUEUE_MACRO_DEBUG_TRASH
#endif
#ifdef QUEUE_MACRO_DEBUG_TRACE
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
unsigned long lastline;
@@ -120,9 +136,7 @@ struct qm_trace {
};
#define TRACEBUF struct qm_trace trace;
#define TRACEBUF_INITIALIZER { __FILE__, __LINE__, NULL, 0 } ,
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define TRACEBUF_INITIALIZER { __LINE__, 0, __FILE__, NULL } ,
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
@@ -138,14 +152,31 @@ struct qm_trace {
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#else /* !QUEUE_MACRO_DEBUG_TRACE */
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define QMD_SAVELINK(name, link)
#define TRACEBUF
#define TRACEBUF_INITIALIZER
#endif /* QUEUE_MACRO_DEBUG_TRACE */
#ifdef QUEUE_MACRO_DEBUG_TRASH
#define QMD_SAVELINK(name, link) void **name = (void *)&(link)
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_IS_TRASHED(x) ((x) == (void *)(intptr_t)-1)
#else /* !QUEUE_MACRO_DEBUG_TRASH */
#define QMD_SAVELINK(name, link)
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
#define QMD_IS_TRASHED(x) 0
#endif /* QUEUE_MACRO_DEBUG_TRASH */
#ifdef __cplusplus
/*
* In C++ there can be structure lists and class lists:
*/
#define QUEUE_TYPEOF(type) type
#else
#define QUEUE_TYPEOF(type) struct type
#endif
/*
* Singly-linked List declarations.
@@ -155,6 +186,11 @@ struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_CLASS_HEAD(name, type) \
struct name { \
class type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
@@ -163,9 +199,37 @@ struct { \
struct type *sle_next; /* next element */ \
}
#define SLIST_CLASS_ENTRY(type) \
struct { \
class type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm) do { \
if (*(prevp) != (elm)) \
panic("Bad prevptr *(%p) == %p != %p", \
(prevp), *(prevp), (elm)); \
} while (0)
#else
#define QMD_SLIST_CHECK_PREVPTR(prevp, elm)
#endif
#define SLIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1); \
if (curelm == NULL) { \
if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL) \
SLIST_INIT(head2); \
} else if (SLIST_FIRST(head2) != NULL) { \
while (SLIST_NEXT(curelm, field) != NULL) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_NEXT(curelm, field) = SLIST_FIRST(head2); \
SLIST_INIT(head2); \
} \
} while (0)
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
@@ -217,7 +281,7 @@ struct { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = SLIST_FIRST((head)); \
QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
@@ -234,12 +298,20 @@ struct { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
#define SLIST_REMOVE_PREVPTR(prevp, elm, field) do { \
QMD_SLIST_CHECK_PREVPTR(prevp, elm); \
*(prevp) = SLIST_NEXT(elm, field); \
TRASHIT((elm)->field.sle_next); \
} while (0)
#define SLIST_SWAP(head1, head2, type) do { \
struct type *swap_first = SLIST_FIRST(head1); \
QUEUE_TYPEOF(type) *swap_first = SLIST_FIRST(head1); \
SLIST_FIRST(head1) = SLIST_FIRST(head2); \
SLIST_FIRST(head2) = swap_first; \
} while (0)
#define SLIST_END(head) NULL
/*
* Singly-linked Tail queue declarations.
*/
@@ -249,6 +321,12 @@ struct name { \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *stqh_first; /* first element */ \
class type **stqh_last; /* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
@@ -257,6 +335,11 @@ struct { \
struct type *stqe_next; /* next element */ \
}
#define STAILQ_CLASS_ENTRY(type) \
struct { \
class type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
@@ -315,9 +398,10 @@ struct { \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
__containerof((head)->stqh_last, struct type, field.stqe_next))
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? NULL : \
__containerof((head)->stqh_last, \
QUEUE_TYPEOF(type), field.stqe_next))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
@@ -327,7 +411,7 @@ struct { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
QUEUE_TYPEOF(type) *curelm = STAILQ_FIRST(head); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
@@ -348,8 +432,8 @@ struct { \
} while (0)
#define STAILQ_SWAP(head1, head2, type) do { \
struct type *swap_first = STAILQ_FIRST(head1); \
struct type **swap_last = (head1)->stqh_last; \
QUEUE_TYPEOF(type) *swap_first = STAILQ_FIRST(head1); \
QUEUE_TYPEOF(type) **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \
@@ -360,6 +444,8 @@ struct { \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
#define STAILQ_END(head) NULL
/*
* List declarations.
@@ -369,6 +455,11 @@ struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_CLASS_HEAD(name, type) \
struct name { \
class type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
@@ -378,11 +469,23 @@ struct { \
struct type **le_prev; /* address of previous next element */ \
}
#define LIST_CLASS_ENTRY(type) \
struct { \
class type *le_next; /* next element */ \
class type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
/*
* QMD_LIST_CHECK_HEAD(LIST_HEAD *head, LIST_ENTRY NAME)
*
* If the list is non-empty, validates that the first element of the list
* points back at 'head.'
*/
#define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
@@ -390,6 +493,12 @@ struct { \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
/*
* QMD_LIST_CHECK_NEXT(TYPE *elm, LIST_ENTRY NAME)
*
* If an element follows 'elm' in the list, validates that the next element
* points back at 'elm.'
*/
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
@@ -397,6 +506,11 @@ struct { \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
/*
* QMD_LIST_CHECK_PREV(TYPE *elm, LIST_ENTRY NAME)
*
* Validates that the previous element (or head of the list) points to 'elm.'
*/
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
@@ -407,6 +521,23 @@ struct { \
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_CONCAT(head1, head2, type, field) do { \
QUEUE_TYPEOF(type) *curelm = LIST_FIRST(head1); \
if (curelm == NULL) { \
if ((LIST_FIRST(head1) = LIST_FIRST(head2)) != NULL) { \
LIST_FIRST(head2)->field.le_prev = \
&LIST_FIRST((head1)); \
LIST_INIT(head2); \
} \
} else if (LIST_FIRST(head2) != NULL) { \
while (LIST_NEXT(curelm, field) != NULL) \
curelm = LIST_NEXT(curelm, field); \
LIST_NEXT(curelm, field) = LIST_FIRST(head2); \
LIST_FIRST(head2)->field.le_prev = &LIST_NEXT(curelm, field); \
LIST_INIT(head2); \
} \
} while (0)
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
@@ -462,9 +593,10 @@ struct { \
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_PREV(elm, head, type, field) \
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
__containerof((elm)->field.le_prev, struct type, field.le_next))
#define LIST_PREV(elm, head, type, field) \
((elm)->field.le_prev == &LIST_FIRST((head)) ? NULL : \
__containerof((elm)->field.le_prev, \
QUEUE_TYPEOF(type), field.le_next))
#define LIST_REMOVE(elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.le_next); \
@@ -480,7 +612,7 @@ struct { \
} while (0)
#define LIST_SWAP(head1, head2, type, field) do { \
struct type *swap_tmp = LIST_FIRST((head1)); \
QUEUE_TYPEOF(type) *swap_tmp = LIST_FIRST(head1); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
@@ -489,6 +621,8 @@ struct { \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
#define LIST_END(head) NULL
/*
* Tail queue declarations.
*/
@@ -499,6 +633,13 @@ struct name { \
TRACEBUF \
}
#define TAILQ_CLASS_HEAD(name, type) \
struct name { \
class type *tqh_first; /* first element */ \
class type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first, TRACEBUF_INITIALIZER }
@@ -509,10 +650,23 @@ struct { \
TRACEBUF \
}
#define TAILQ_CLASS_ENTRY(type) \
struct { \
class type *tqe_next; /* next element */ \
class type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
/*
* QMD_TAILQ_CHECK_HEAD(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
*
* If the tailq is non-empty, validates that the first element of the tailq
* points back at 'head.'
*/
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
@@ -520,11 +674,22 @@ struct { \
panic("Bad tailq head %p first->prev != head", (head)); \
} while (0)
/*
* QMD_TAILQ_CHECK_TAIL(TAILQ_HEAD *head, TAILQ_ENTRY NAME)
*
* Validates that the tail of the tailq is a pointer to pointer to NULL.
*/
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
/*
* QMD_TAILQ_CHECK_NEXT(TYPE *elm, TAILQ_ENTRY NAME)
*
* If an element follows 'elm' in the tailq, validates that the next element
* points back at 'elm.'
*/
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \
@@ -532,6 +697,11 @@ struct { \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
/*
* QMD_TAILQ_CHECK_PREV(TYPE *elm, TAILQ_ENTRY NAME)
*
* Validates that the previous element (or head of the tailq) points to 'elm.'
*/
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
@@ -616,7 +786,7 @@ struct { \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
QMD_TRACE_ELEM(&(listelm)->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
@@ -626,7 +796,7 @@ struct { \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
QMD_TRACE_ELEM(&(listelm)->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
@@ -655,11 +825,25 @@ struct { \
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
/*
* The FAST function is fast in that it causes no data access other
* then the access to the head. The standard LAST function above
* will cause a data access of both the element you want and
* the previous element. FAST is very useful for instances when
* you may want to prefetch the last data element.
*/
#define TAILQ_LAST_FAST(head, type, field) \
(TAILQ_EMPTY(head) ? NULL : __containerof((head)->tqh_last, QUEUE_TYPEOF(type), field.tqe_next))
#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next)
#define TAILQ_PREV(elm, headname, field) \
(*(((struct headname *)((elm)->field.tqe_prev))->tqh_last))
#define TAILQ_PREV_FAST(elm, head, type, field) \
((elm)->field.tqe_prev == &(head)->tqh_first ? NULL : \
__containerof((elm)->field.tqe_prev, QUEUE_TYPEOF(type), field.tqe_next))
#define TAILQ_REMOVE(head, elm, field) do { \
QMD_SAVELINK(oldnext, (elm)->field.tqe_next); \
QMD_SAVELINK(oldprev, (elm)->field.tqe_prev); \
@@ -679,8 +863,8 @@ struct { \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) do { \
struct type *swap_first = (head1)->tqh_first; \
struct type **swap_last = (head1)->tqh_last; \
QUEUE_TYPEOF(type) *swap_first = (head1)->tqh_first; \
QUEUE_TYPEOF(type) **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
@@ -695,4 +879,6 @@ struct { \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#define TAILQ_END(head) NULL
#endif /* !LIBBSD_SYS_QUEUE_H */

2
m4/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
*.m4
!libbsd*.m4

24
m4/libbsd-compiler.m4 Normal file
View File

@@ -0,0 +1,24 @@
# Copyright © 2021 Guillem Jover <guillem@hadrons.org>
# LIBBSD_CHECK_COMPILER_FLAG
# -------------------------
AC_DEFUN([LIBBSD_CHECK_COMPILER_FLAG], [
AS_VAR_PUSHDEF([libbsd_varname_cache], [libbsd_cv_cflags_$1])
AC_CACHE_CHECK([whether $CC accepts $1], [libbsd_varname_cache], [
m4_define([libbsd_check_flag], m4_bpatsubst([$1], [^-Wno-], [-W]))
AS_VAR_COPY([libbsd_save_CFLAGS], [CFLAGS])
AS_VAR_SET([CFLAGS], ["-Werror libbsd_check_flag"])
AC_COMPILE_IFELSE([
AC_LANG_SOURCE([[]])
], [
AS_VAR_SET([libbsd_varname_cache], [yes])
], [
AS_VAR_SET([libbsd_varname_cache], [no])
])
AS_VAR_COPY([CFLAGS], [libbsd_save_CFLAGS])
])
AS_VAR_IF([libbsd_varname_cache], [yes], [
AS_VAR_APPEND([LIBBSD_COMPILER_FLAGS], [" $1"])
])
AS_VAR_POPDEF([libbsd_varname_cache])
])

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

1
man/LIST_CLASS_HEAD.3bsd Normal file
View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -11,9 +11,11 @@ CLEANFILES = \
SED_MD5_SUBST = -e 's/mdX/md5/g' -e 's/mdY/md4/g' -e 's/MDX/MD5/g'
md5.3bsd: $(srcdir)/mdX.3bsd
$(AM_V_GEN) sed $(SED_MD5_SUBST) $< > $@
$(AM_V_GEN) $(SED) $(SED_MD5_SUBST) $< > $@
dist_man_MANS = \
LIST_CLASS_ENTRY.3bsd \
LIST_CLASS_HEAD.3bsd \
LIST_EMPTY.3bsd \
LIST_ENTRY.3bsd \
LIST_FIRST.3bsd \
@@ -54,6 +56,8 @@ dist_man_MANS = \
RB_REMOVE.3bsd \
RB_RIGHT.3bsd \
RB_ROOT.3bsd \
SLIST_CLASS_ENTRY.3bsd \
SLIST_CLASS_HEAD.3bsd \
SLIST_EMPTY.3bsd \
SLIST_ENTRY.3bsd \
SLIST_FIRST.3bsd \
@@ -70,6 +74,7 @@ dist_man_MANS = \
SLIST_REMOVE.3bsd \
SLIST_REMOVE_AFTER.3bsd \
SLIST_REMOVE_HEAD.3bsd \
SLIST_REMOVE_PREVPTR.3bsd \
SLIST_SWAP.3bsd \
SPLAY_EMPTY.3bsd \
SPLAY_ENTRY.3bsd \
@@ -88,6 +93,8 @@ dist_man_MANS = \
SPLAY_REMOVE.3bsd \
SPLAY_RIGHT.3bsd \
SPLAY_ROOT.3bsd \
STAILQ_CLASS_ENTRY.3bsd \
STAILQ_CLASS_HEAD.3bsd \
STAILQ_CONCAT.3bsd \
STAILQ_EMPTY.3bsd \
STAILQ_ENTRY.3bsd \
@@ -108,6 +115,8 @@ dist_man_MANS = \
STAILQ_REMOVE_AFTER.3bsd \
STAILQ_REMOVE_HEAD.3bsd \
STAILQ_SWAP.3bsd \
TAILQ_CLASS_ENTRY.3bsd \
TAILQ_CLASS_HEAD.3bsd \
TAILQ_CONCAT.3bsd \
TAILQ_EMPTY.3bsd \
TAILQ_ENTRY.3bsd \

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -0,0 +1 @@
.so man3/queue.3bsd

View File

@@ -1,6 +1,6 @@
.\" libbsd man page
.\"
.\" Copyright © 2017-2018 Guillem Jover <guillem@hadrons.org>
.\" Copyright © 2017-2021 Guillem Jover <guillem@hadrons.org>
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -24,7 +24,7 @@
.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 21, 2018
.Dd Feb 13, 2021
.Dt LIBBSD 7
.Os
.Sh NAME
@@ -42,7 +42,7 @@ The library can be used in an overlay mode, which is the preferred way, so
that the code is portable and requires no modification to the original BSD
code.
This can be done easily with the
.Xr pkg-config 3
.Xr pkg-config 1
library named
.Pa libbsd-overlay .
Or by adding the system-specific include directory with the
@@ -64,7 +64,7 @@ this is less portable as it makes using
mandatory and it will not work on BSD-based systems, and requires
modifying original BSD code.
This can be done with the
.Xr pkg-config 3
.Xr pkg-config 1
library named
.Pa libbsd .
The includes in this case should be namespaced with
@@ -73,13 +73,13 @@ such as
.In bsd/unistd.h .
.Pp
The package also provides a
.Pa bsd-ctor
.Nm libbsd-ctor
static library that can be used to inject automatic constructors into a
program so that the
.Fn setproctitle_init 3
function gets invoked automatically at startup time.
This can be done with the
.Xr pkg-config 3
.Xr pkg-config 1
library named
.Pa libbsd-ctor .
.Sh HEADERS
@@ -94,11 +94,13 @@ be prefixed with
.It In bitstring.h
.It In err.h
.It In getopt.h
.It In grp.h
.It In inttypes.h
.It In libutil.h
.It In md5.h
.It In netinet/ip_icmp.h
.It In nlist.h
.It In pwd.h
.It In readpassphrase.h
.It In stdio.h
.It In stdlib.h
@@ -107,6 +109,7 @@ be prefixed with
.It In sys/bitstring.h
.It In sys/cdefs.h
.It In sys/endian.h
.It In sys/param.h
.It In sys/poll.h
.It In sys/queue.h
.It In sys/time.h
@@ -125,6 +128,46 @@ It only works in non-overlay mode.
.Bl -tag -width 4m -compact
.It In bsd/bsd.h
.El
.Sh ALTERNATIVES
Some functions have different prototypes depending on the BSD where they
originated from, and these various implementations provided are selectable
at build-time.
.Pp
This is the list of functions that provide multiple implementations:
.Bl -tag -width 4m
.It Fn strnvis 3
.It Fn strnunvis 3
.Nx
added
.Fn strnvis 3
and
.Fn strnunvis 3
but unfortunately made it incompatible with the existing one in
.Ox
and Freedesktop's libbsd (the former having existed for over ten years).
Despite this incompatibility being reported during development (see
http://gnats.netbsd.org/44977) they still shipped it.
Even more unfortunately
.Fx
and later MacOS picked up this incompatible implementation.
.Pp
Provide both implementations and default for now to the historical one to
avoid breakage, but we will switch to the
.Nx
one in a later release, which is internally consistent with the other
.Xr vis 3
functions and is now more widespread.
Define
.Dv LIBBSD_NETBSD_VIS
to switch to the
.Nx
one now.
Define
.Dv LIBBSD_OPENBSD_VIS
to keep using the
.Ox
one.
.El
.Sh DEPRECATED
Some functions have been deprecated, they will emit warnings at compile time
and possibly while being linked at run-time.
@@ -216,6 +259,7 @@ This function is provided by
.Xr md5 3bsd ,
.Xr nlist 3bsd ,
.Xr pidfile 3bsd ,
.Xr pwcache 3bsd ,
.Xr queue 3bsd ,
.Xr radixsort 3bsd ,
.Xr readpassphrase 3bsd ,

View File

@@ -28,35 +28,40 @@
.\" @(#)queue.3 8.2 (Berkeley) 1/24/94
.\" $FreeBSD$
.\"
.Dd June 17, 2013
.Dd September 8, 2016
.Dt QUEUE 3bsd
.Os
.Sh NAME
.Nm SLIST_CLASS_ENTRY ,
.Nm SLIST_CLASS_HEAD ,
.Nm SLIST_CONCAT ,
.Nm SLIST_EMPTY ,
.Nm SLIST_ENTRY ,
.Nm SLIST_FIRST ,
.Nm SLIST_FOREACH ,
.Nm SLIST_FOREACH_FROM ,
.Nm SLIST_FOREACH_SAFE ,
.Nm SLIST_FOREACH_FROM_SAFE ,
.Nm SLIST_FOREACH_SAFE ,
.Nm SLIST_HEAD ,
.Nm SLIST_HEAD_INITIALIZER ,
.Nm SLIST_INIT ,
.Nm SLIST_INSERT_AFTER ,
.Nm SLIST_INSERT_HEAD ,
.Nm SLIST_NEXT ,
.Nm SLIST_REMOVE ,
.Nm SLIST_REMOVE_AFTER ,
.Nm SLIST_REMOVE_HEAD ,
.Nm SLIST_REMOVE ,
.Nm SLIST_SWAP ,
.Nm STAILQ_CLASS_ENTRY ,
.Nm STAILQ_CLASS_HEAD ,
.Nm STAILQ_CONCAT ,
.Nm STAILQ_EMPTY ,
.Nm STAILQ_ENTRY ,
.Nm STAILQ_FIRST ,
.Nm STAILQ_FOREACH ,
.Nm STAILQ_FOREACH_FROM ,
.Nm STAILQ_FOREACH_SAFE ,
.Nm STAILQ_FOREACH_FROM_SAFE ,
.Nm STAILQ_FOREACH_SAFE ,
.Nm STAILQ_HEAD ,
.Nm STAILQ_HEAD_INITIALIZER ,
.Nm STAILQ_INIT ,
@@ -65,17 +70,20 @@
.Nm STAILQ_INSERT_TAIL ,
.Nm STAILQ_LAST ,
.Nm STAILQ_NEXT ,
.Nm STAILQ_REMOVE ,
.Nm STAILQ_REMOVE_AFTER ,
.Nm STAILQ_REMOVE_HEAD ,
.Nm STAILQ_REMOVE ,
.Nm STAILQ_SWAP ,
.Nm LIST_CLASS_ENTRY ,
.Nm LIST_CLASS_HEAD ,
.Nm LIST_CONCAT ,
.Nm LIST_EMPTY ,
.Nm LIST_ENTRY ,
.Nm LIST_FIRST ,
.Nm LIST_FOREACH ,
.Nm LIST_FOREACH_FROM ,
.Nm LIST_FOREACH_SAFE ,
.Nm LIST_FOREACH_FROM_SAFE ,
.Nm LIST_FOREACH_SAFE ,
.Nm LIST_HEAD ,
.Nm LIST_HEAD_INITIALIZER ,
.Nm LIST_INIT ,
@@ -86,18 +94,20 @@
.Nm LIST_PREV ,
.Nm LIST_REMOVE ,
.Nm LIST_SWAP ,
.Nm TAILQ_CLASS_ENTRY ,
.Nm TAILQ_CLASS_HEAD ,
.Nm TAILQ_CONCAT ,
.Nm TAILQ_EMPTY ,
.Nm TAILQ_ENTRY ,
.Nm TAILQ_FIRST ,
.Nm TAILQ_FOREACH ,
.Nm TAILQ_FOREACH_FROM ,
.Nm TAILQ_FOREACH_SAFE ,
.Nm TAILQ_FOREACH_FROM_SAFE ,
.Nm TAILQ_FOREACH_REVERSE ,
.Nm TAILQ_FOREACH_REVERSE_FROM ,
.Nm TAILQ_FOREACH_REVERSE_SAFE ,
.Nm TAILQ_FOREACH_REVERSE_FROM_SAFE ,
.Nm TAILQ_FOREACH_REVERSE_SAFE ,
.Nm TAILQ_FOREACH_SAFE ,
.Nm TAILQ_HEAD ,
.Nm TAILQ_HEAD_INITIALIZER ,
.Nm TAILQ_INIT ,
@@ -122,52 +132,60 @@ lists and tail queues
.Xr libbsd 7
for include usage.)
.\"
.Fn SLIST_CLASS_ENTRY "CLASSTYPE"
.Fn SLIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn SLIST_CONCAT "SLIST_HEAD *head1" "SLIST_HEAD *head2" "TYPE" "SLIST_ENTRY NAME"
.Fn SLIST_EMPTY "SLIST_HEAD *head"
.Fn SLIST_ENTRY "TYPE"
.Fn SLIST_FIRST "SLIST_HEAD *head"
.Fn SLIST_FOREACH "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
.Fn SLIST_FOREACH_FROM "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME"
.Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
.Fn SLIST_FOREACH_FROM_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
.Fn SLIST_FOREACH_SAFE "TYPE *var" "SLIST_HEAD *head" "SLIST_ENTRY NAME" "TYPE *temp_var"
.Fn SLIST_HEAD "HEADNAME" "TYPE"
.Fn SLIST_HEAD_INITIALIZER "SLIST_HEAD head"
.Fn SLIST_INIT "SLIST_HEAD *head"
.Fn SLIST_INSERT_AFTER "TYPE *listelm" "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_INSERT_HEAD "SLIST_HEAD *head" "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_NEXT "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE_AFTER "TYPE *elm" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE_HEAD "SLIST_HEAD *head" "SLIST_ENTRY NAME"
.Fn SLIST_REMOVE "SLIST_HEAD *head" "TYPE *elm" "TYPE" "SLIST_ENTRY NAME"
.Fn SLIST_SWAP "SLIST_HEAD *head1" "SLIST_HEAD *head2" "SLIST_ENTRY NAME"
.Fn SLIST_SWAP "SLIST_HEAD *head1" "SLIST_HEAD *head2" "TYPE"
.\"
.Fn STAILQ_CLASS_ENTRY "CLASSTYPE"
.Fn STAILQ_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn STAILQ_CONCAT "STAILQ_HEAD *head1" "STAILQ_HEAD *head2"
.Fn STAILQ_EMPTY "STAILQ_HEAD *head"
.Fn STAILQ_ENTRY "TYPE"
.Fn STAILQ_FIRST "STAILQ_HEAD *head"
.Fn STAILQ_FOREACH "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
.Fn STAILQ_FOREACH_FROM "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
.Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn STAILQ_FOREACH_FROM_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn STAILQ_FOREACH_SAFE "TYPE *var" "STAILQ_HEAD *head" "STAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn STAILQ_HEAD "HEADNAME" "TYPE"
.Fn STAILQ_HEAD_INITIALIZER "STAILQ_HEAD head"
.Fn STAILQ_INIT "STAILQ_HEAD *head"
.Fn STAILQ_INSERT_AFTER "STAILQ_HEAD *head" "TYPE *listelm" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_INSERT_HEAD "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_INSERT_TAIL "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE" "STAILQ_ENTRY NAME"
.Fn STAILQ_LAST "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_NEXT "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE_AFTER "STAILQ_HEAD *head" "TYPE *elm" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE_HEAD "STAILQ_HEAD *head" "STAILQ_ENTRY NAME"
.Fn STAILQ_REMOVE "STAILQ_HEAD *head" "TYPE *elm" "TYPE" "STAILQ_ENTRY NAME"
.Fn STAILQ_SWAP "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" "STAILQ_ENTRY NAME"
.Fn STAILQ_SWAP "STAILQ_HEAD *head1" "STAILQ_HEAD *head2" "TYPE"
.\"
.Fn LIST_CLASS_ENTRY "CLASSTYPE"
.Fn LIST_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn LIST_CONCAT "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
.Fn LIST_EMPTY "LIST_HEAD *head"
.Fn LIST_ENTRY "TYPE"
.Fn LIST_FIRST "LIST_HEAD *head"
.Fn LIST_FOREACH "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
.Fn LIST_FOREACH_FROM "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME"
.Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
.Fn LIST_FOREACH_FROM_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
.Fn LIST_FOREACH_SAFE "TYPE *var" "LIST_HEAD *head" "LIST_ENTRY NAME" "TYPE *temp_var"
.Fn LIST_HEAD "HEADNAME" "TYPE"
.Fn LIST_HEAD_INITIALIZER "LIST_HEAD head"
.Fn LIST_INIT "LIST_HEAD *head"
@@ -179,18 +197,20 @@ for include usage.)
.Fn LIST_REMOVE "TYPE *elm" "LIST_ENTRY NAME"
.Fn LIST_SWAP "LIST_HEAD *head1" "LIST_HEAD *head2" "TYPE" "LIST_ENTRY NAME"
.\"
.Fn TAILQ_CLASS_ENTRY "CLASSTYPE"
.Fn TAILQ_CLASS_HEAD "HEADNAME" "CLASSTYPE"
.Fn TAILQ_CONCAT "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TAILQ_ENTRY NAME"
.Fn TAILQ_EMPTY "TAILQ_HEAD *head"
.Fn TAILQ_ENTRY "TYPE"
.Fn TAILQ_FIRST "TAILQ_HEAD *head"
.Fn TAILQ_FOREACH "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_FROM "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_REVERSE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_REVERSE_FROM "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME"
.Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_REVERSE_FROM_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_REVERSE_SAFE "TYPE *var" "TAILQ_HEAD *head" "HEADNAME" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_FOREACH_SAFE "TYPE *var" "TAILQ_HEAD *head" "TAILQ_ENTRY NAME" "TYPE *temp_var"
.Fn TAILQ_HEAD "HEADNAME" "TYPE"
.Fn TAILQ_HEAD_INITIALIZER "TAILQ_HEAD head"
.Fn TAILQ_INIT "TAILQ_HEAD *head"
@@ -205,8 +225,18 @@ for include usage.)
.Fn TAILQ_SWAP "TAILQ_HEAD *head1" "TAILQ_HEAD *head2" "TYPE" "TAILQ_ENTRY NAME"
.\"
.Sh DESCRIPTION
These macros define and operate on four types of data structures:
singly-linked lists, singly-linked tail queues, lists, and tail queues.
These macros define and operate on four types of data structures which
can be used in both C and C++ source code:
.Bl -enum -compact -offset indent
.It
Lists
.It
Singly-linked lists
.It
Singly-linked tail queues
.It
Tail queues
.El
All four structures support the following functionality:
.Bl -enum -compact -offset indent
.It
@@ -230,6 +260,8 @@ Singly-linked lists add the following functionality:
.Bl -enum -compact -offset indent
.It
O(n) removal of any entry in the list.
.It
O(n) concatenation of two lists.
.El
.Pp
Singly-linked tail queues add the following functionality:
@@ -277,6 +309,8 @@ Linked lists are the simplest of the doubly linked data structures.
They add the following functionality over the above:
.Bl -enum -compact -offset indent
.It
O(n) concatenation of two lists.
.It
They may be traversed backwards.
.El
However:
@@ -308,24 +342,39 @@ than singly-linked lists.
.Pp
In the macro definitions,
.Fa TYPE
is the name of a user defined structure,
that must contain a field of type
is the name of a user defined structure.
The structure must contain a field called
.Fa NAME
which is of type
.Li SLIST_ENTRY ,
.Li STAILQ_ENTRY ,
.Li LIST_ENTRY ,
or
.Li TAILQ_ENTRY ,
named
.Fa NAME .
.Li TAILQ_ENTRY .
In the macro definitions,
.Fa CLASSTYPE
is the name of a user defined class.
The class must contain a field called
.Fa NAME
which is of type
.Li SLIST_CLASS_ENTRY ,
.Li STAILQ_CLASS_ENTRY ,
.Li LIST_CLASS_ENTRY ,
or
.Li TAILQ_CLASS_ENTRY .
The argument
.Fa HEADNAME
is the name of a user defined structure that must be declared
using the macros
.Li SLIST_HEAD ,
.Li SLIST_CLASS_HEAD ,
.Li STAILQ_HEAD ,
.Li STAILQ_CLASS_HEAD ,
.Li LIST_HEAD ,
.Li LIST_CLASS_HEAD ,
.Li TAILQ_HEAD ,
or
.Li TAILQ_HEAD .
.Li TAILQ_CLASS_HEAD .
See the examples below for further explanation of how these
macros are used.
.Sh SINGLY-LINKED LISTS
@@ -367,6 +416,19 @@ evaluates to an initializer for the list
.Fa head .
.Pp
The macro
.Nm SLIST_CONCAT
concatenates the list headed by
.Fa head2
onto the end of the one headed by
.Fa head1
removing all entries from the former.
Use of this macro should be avoided as it traverses the entirety of the
.Fa head1
list.
A singly-linked tail queue should be used if this macro is needed in
high-usage code paths or to operate on long lists.
.Pp
The macro
.Nm SLIST_EMPTY
evaluates to true if there are no elements in the list.
.Pp
@@ -474,6 +536,9 @@ The macro
removes the element
.Fa elm
from the list.
Use of this macro should be avoided as it traverses the entire list.
A doubly-linked list should be used if this macro is needed in
high-usage code paths or to operate on long lists.
.Pp
The macro
.Nm SLIST_SWAP
@@ -690,6 +755,9 @@ The macro
removes the element
.Fa elm
from the tail queue.
Use of this macro should be avoided as it traverses the entire list.
A doubly-linked tail queue should be used if this macro is needed in
high-usage code paths or to operate on long tail queues.
.Pp
The macro
.Nm STAILQ_SWAP
@@ -789,6 +857,19 @@ evaluates to an initializer for the list
.Fa head .
.Pp
The macro
.Nm LIST_CONCAT
concatenates the list headed by
.Fa head2
onto the end of the one headed by
.Fa head1
removing all entries from the former.
Use of this macro should be avoided as it traverses the entirety of the
.Fa head1
list.
A tail queue should be used if this macro is needed in
high-usage code paths or to operate on long lists.
.Pp
The macro
.Nm LIST_EMPTY
evaluates to true if there are no elements in the list.
.Pp
@@ -1210,6 +1291,26 @@ while (n1 != NULL) {
}
TAILQ_INIT(&head);
.Ed
.Sh DIAGNOSTICS
When debugging
.Nm queue(3) ,
it can be useful to trace queue changes.
To enable tracing, define the macro
.Va QUEUE_MACRO_DEBUG_TRACE
at compile time.
.Pp
It can also be useful to trash pointers that have been unlinked from a queue,
to detect use after removal.
To enable pointer trashing, define the macro
.Va QUEUE_MACRO_DEBUG_TRASH
at compile time.
The macro
.Fn QMD_IS_TRASHED "void *ptr"
returns true if
.Fa ptr
has been trashed by the
.Va QUEUE_MACRO_DEBUG_TRASH
option.
.Sh SEE ALSO
.Xr tree 3bsd
.Sh HISTORY

View File

@@ -1,36 +1,29 @@
.\" $OpenBSD: tree.3,v 1.7 2002/06/12 01:09:20 provos Exp $
.\"
.\" Copyright 2002 Niels Provos <provos@citi.umich.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 Niels Provos.
.\" 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.
.\"
.\" $FreeBSD$
.\"
.Dd December 27, 2007
.\" $OpenBSD: tree.3,v 1.30 2019/05/10 13:13:14 florian Exp $
.\"/*
.\" * Copyright 2002 Niels Provos <provos@citi.umich.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 ``AS IS'' AND ANY EXPRESS OR
.\" * IMPLIED WARRANTIES, 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.
.\" */
.Dd May 10, 2019
.Dt TREE 3bsd
.Os
.Sh NAME
@@ -70,7 +63,9 @@
.Nm RB_RIGHT ,
.Nm RB_PARENT ,
.Nm RB_FOREACH ,
.Nm RB_FOREACH_SAFE ,
.Nm RB_FOREACH_REVERSE ,
.Nm RB_FOREACH_REVERSE_SAFE ,
.Nm RB_INIT ,
.Nm RB_INSERT ,
.Nm RB_REMOVE
@@ -84,88 +79,92 @@
(See
.Xr libbsd 7
for include usage.)
.Fn SPLAY_PROTOTYPE NAME TYPE FIELD CMP
.Fn SPLAY_GENERATE NAME TYPE FIELD CMP
.Fn SPLAY_ENTRY TYPE
.Fn SPLAY_HEAD HEADNAME TYPE
.Pp
.Fn SPLAY_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP"
.Fn SPLAY_GENERATE "NAME" "TYPE" "FIELD" "CMP"
.Fn SPLAY_ENTRY "TYPE"
.Fn SPLAY_HEAD "HEADNAME" "TYPE"
.Ft "struct TYPE *"
.Fn SPLAY_INITIALIZER "SPLAY_HEAD *head"
.Fn SPLAY_ROOT "SPLAY_HEAD *head"
.Ft bool
.Ft "int"
.Fn SPLAY_EMPTY "SPLAY_HEAD *head"
.Ft "struct TYPE *"
.Fn SPLAY_NEXT NAME "SPLAY_HEAD *head" "struct TYPE *elm"
.Fn SPLAY_NEXT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn SPLAY_MIN NAME "SPLAY_HEAD *head"
.Fn SPLAY_MIN "NAME" "SPLAY_HEAD *head"
.Ft "struct TYPE *"
.Fn SPLAY_MAX NAME "SPLAY_HEAD *head"
.Fn SPLAY_MAX "NAME" "SPLAY_HEAD *head"
.Ft "struct TYPE *"
.Fn SPLAY_FIND NAME "SPLAY_HEAD *head" "struct TYPE *elm"
.Fn SPLAY_FIND "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn SPLAY_LEFT "struct TYPE *elm" "SPLAY_ENTRY NAME"
.Ft "struct TYPE *"
.Fn SPLAY_RIGHT "struct TYPE *elm" "SPLAY_ENTRY NAME"
.Fn SPLAY_FOREACH VARNAME NAME "SPLAY_HEAD *head"
.Fn SPLAY_FOREACH "VARNAME" "NAME" "SPLAY_HEAD *head"
.Ft void
.Fn SPLAY_INIT "SPLAY_HEAD *head"
.Ft "struct TYPE *"
.Fn SPLAY_INSERT NAME "SPLAY_HEAD *head" "struct TYPE *elm"
.Fn SPLAY_INSERT "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn SPLAY_REMOVE NAME "SPLAY_HEAD *head" "struct TYPE *elm"
.Fn RB_PROTOTYPE NAME TYPE FIELD CMP
.Fn RB_PROTOTYPE_STATIC NAME TYPE FIELD CMP
.Fn RB_GENERATE NAME TYPE FIELD CMP
.Fn RB_GENERATE_STATIC NAME TYPE FIELD CMP
.Fn RB_ENTRY TYPE
.Fn RB_HEAD HEADNAME TYPE
.Fn SPLAY_REMOVE "NAME" "SPLAY_HEAD *head" "struct TYPE *elm"
.Pp
.Fn RB_PROTOTYPE "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_PROTOTYPE_STATIC "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_GENERATE "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_GENERATE_STATIC "NAME" "TYPE" "FIELD" "CMP"
.Fn RB_ENTRY "TYPE"
.Fn RB_HEAD "HEADNAME" "TYPE"
.Fn RB_INITIALIZER "RB_HEAD *head"
.Ft "struct TYPE *"
.Fn RB_ROOT "RB_HEAD *head"
.Ft "bool"
.Ft "int"
.Fn RB_EMPTY "RB_HEAD *head"
.Ft "struct TYPE *"
.Fn RB_NEXT NAME "RB_HEAD *head" "struct TYPE *elm"
.Fn RB_NEXT "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn RB_PREV NAME "RB_HEAD *head" "struct TYPE *elm"
.Fn RB_PREV "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn RB_MIN NAME "RB_HEAD *head"
.Fn RB_MIN "NAME" "RB_HEAD *head"
.Ft "struct TYPE *"
.Fn RB_MAX NAME "RB_HEAD *head"
.Fn RB_MAX "NAME" "RB_HEAD *head"
.Ft "struct TYPE *"
.Fn RB_FIND NAME "RB_HEAD *head" "struct TYPE *elm"
.Fn RB_FIND "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn RB_NFIND NAME "RB_HEAD *head" "struct TYPE *elm"
.Fn RB_NFIND "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn RB_LEFT "struct TYPE *elm" "RB_ENTRY NAME"
.Ft "struct TYPE *"
.Fn RB_RIGHT "struct TYPE *elm" "RB_ENTRY NAME"
.Ft "struct TYPE *"
.Fn RB_PARENT "struct TYPE *elm" "RB_ENTRY NAME"
.Fn RB_FOREACH VARNAME NAME "RB_HEAD *head"
.Fn RB_FOREACH_REVERSE VARNAME NAME "RB_HEAD *head"
.Fn RB_FOREACH "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Fn RB_FOREACH_REVERSE "VARNAME" "NAME" "RB_HEAD *head"
.Fn RB_FOREACH_REVERSE_SAFE "VARNAME" "NAME" "RB_HEAD *head" "TEMP_VARNAME"
.Ft void
.Fn RB_INIT "RB_HEAD *head"
.Ft "struct TYPE *"
.Fn RB_INSERT NAME "RB_HEAD *head" "struct TYPE *elm"
.Fn RB_INSERT "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Ft "struct TYPE *"
.Fn RB_REMOVE NAME "RB_HEAD *head" "struct TYPE *elm"
.Fn RB_REMOVE "NAME" "RB_HEAD *head" "struct TYPE *elm"
.Sh DESCRIPTION
These macros define data structures for different types of trees:
splay trees and red-black trees.
.Pp
In the macro definitions,
.Fa TYPE
is the name tag of a user defined structure that must contain a field of type
.Vt SPLAY_ENTRY ,
is the name tag of a user defined structure that must contain a field named
.Fa FIELD ,
of type
.Li SPLAY_ENTRY
or
.Vt RB_ENTRY ,
named
.Fa ENTRYNAME .
.Li RB_ENTRY .
The argument
.Fa HEADNAME
is the name tag of a user defined structure that must be declared
using the macros
.Fn SPLAY_HEAD ,
.Fn SPLAY_HEAD
or
.Fn RB_HEAD .
The argument
@@ -173,46 +172,38 @@ The argument
has to be a unique name prefix for every tree that is defined.
.Pp
The function prototypes are declared with
.Fn SPLAY_PROTOTYPE ,
.Fn RB_PROTOTYPE ,
.Li SPLAY_PROTOTYPE ,
.Li RB_PROTOTYPE ,
or
.Fn RB_PROTOTYPE_STATIC .
.Li RB_PROTOTYPE_STATIC .
The function bodies are generated with
.Fn SPLAY_GENERATE ,
.Fn RB_GENERATE ,
.Li SPLAY_GENERATE ,
.Li RB_GENERATE ,
or
.Fn RB_GENERATE_STATIC .
.Li RB_GENERATE_STATIC .
See the examples below for further explanation of how these macros are used.
.Sh SPLAY TREES
A splay tree is a self-organizing data structure.
Every operation on the tree causes a splay to happen.
The splay moves the requested
node to the root of the tree and partly rebalances it.
The splay moves the requested node to the root of the tree and partly
rebalances it.
.Pp
This has the benefit that request locality causes faster lookups as
the requested nodes move to the top of the tree.
On the other hand, every lookup causes memory writes.
.Pp
The Balance Theorem bounds the total access time for
.Ar m
operations and
.Ar n
inserts on an initially empty tree as
.Fn O "\*[lp]m + n\*[rp]lg n" .
The
amortized cost for a sequence of
.Ar m
accesses to a splay tree is
.Fn O "lg n" .
The Balance Theorem bounds the total access time for m operations
and n inserts on an initially empty tree as O((m + n)lg n).
The amortized cost for a sequence of m accesses to a splay tree is O(lg n).
.Pp
A splay tree is headed by a structure defined by the
.Fn SPLAY_HEAD
macro.
A
.Fa SPLAY_HEAD
structure is declared as follows:
.Bd -ragged -offset indent
.Fn SPLAY_HEAD HEADNAME TYPE
.Va head ;
.Bd -literal -offset indent
SPLAY_HEAD(HEADNAME, TYPE) head;
.Ed
.Pp
where
@@ -251,16 +242,15 @@ macro, but should be used only once.
Finally,
the
.Fa CMP
argument is the name of a function used to compare tree nodes
argument is the name of a function used to compare trees' nodes
with each other.
The function takes two arguments of type
.Vt "struct TYPE *" .
.Fa "struct TYPE *" .
If the first argument is smaller than the second, the function returns a
value smaller than zero.
If they are equal, the function returns zero.
Otherwise, it should return a value greater than zero.
The compare
function defines the order of the tree elements.
The compare function defines the order of the tree elements.
.Pp
The
.Fn SPLAY_INIT
@@ -270,11 +260,8 @@ macro initializes the tree referenced by
The splay tree can also be initialized statically by using the
.Fn SPLAY_INITIALIZER
macro like this:
.Bd -ragged -offset indent
.Fn SPLAY_HEAD HEADNAME TYPE
.Va head
=
.Fn SPLAY_INITIALIZER &head ;
.Bd -literal -offset indent
SPLAY_HEAD(HEADNAME, TYPE) head = SPLAY_INITIALIZER(&head);
.Ed
.Pp
The
@@ -282,6 +269,11 @@ The
macro inserts the new element
.Fa elm
into the tree.
Upon success,
.Va NULL
is returned.
If a matching element already exists in the tree, the insertion is
aborted, and a pointer to the existing element is returned.
.Pp
The
.Fn SPLAY_REMOVE
@@ -289,6 +281,11 @@ macro removes the element
.Fa elm
from the tree pointed by
.Fa head .
Upon success, a pointer to the removed element is returned.
.Va NULL
is returned if
.Fa elm
is not present in the tree.
.Pp
The
.Fn SPLAY_FIND
@@ -296,7 +293,7 @@ macro can be used to find a particular element in the tree.
.Bd -literal -offset indent
struct TYPE find, *res;
find.key = 30;
res = SPLAY_FIND(NAME, head, &find);
res = SPLAY_FIND(NAME, &head, &find);
.Ed
.Pp
The
@@ -313,8 +310,8 @@ for (np = SPLAY_MIN(NAME, &head); np != NULL; np = SPLAY_NEXT(NAME, &head, np))
Or, for simplicity, one can use the
.Fn SPLAY_FOREACH
macro:
.Bd -ragged -offset indent
.Fn SPLAY_FOREACH np NAME head
.Bd -literal -offset indent
SPLAY_FOREACH(np, NAME, &head)
.Ed
.Pp
The
@@ -324,29 +321,28 @@ macro should be used to check whether a splay tree is empty.
A red-black tree is a binary search tree with the node color as an
extra attribute.
It fulfills a set of conditions:
.Bl -enum -offset indent
.Pp
.Bl -enum -compact -offset indent
.It
Every search path from the root to a leaf consists of the same number of
black nodes.
every search path from the root to a leaf consists of the same number of
black nodes,
.It
Each red node (except for the root) has a black parent.
each red node (except for the root) has a black parent,
.It
Each leaf node is black.
each leaf node is black.
.El
.Pp
Every operation on a red-black tree is bounded as
.Fn O "lg n" .
The maximum height of a red-black tree is
.Fn 2lg "n + 1" .
Every operation on a red-black tree is bounded as O(lg n).
The maximum height of a red-black tree is 2lg (n+1).
.Pp
A red-black tree is headed by a structure defined by the
.Fn RB_HEAD
macro.
A
.Fa RB_HEAD
structure is declared as follows:
.Bd -ragged -offset indent
.Fn RB_HEAD HEADNAME TYPE
.Va head ;
.Bd -literal -offset indent
RB_HEAD(HEADNAME, TYPE) head;
.Ed
.Pp
where
@@ -364,7 +360,7 @@ their prototypes need to be declared with the
.Fn RB_PROTOTYPE
or
.Fn RB_PROTOTYPE_STATIC
macro,
macros,
where
.Fa NAME
is a unique identifier for this particular tree.
@@ -381,7 +377,7 @@ The function bodies are generated with the
.Fn RB_GENERATE
or
.Fn RB_GENERATE_STATIC
macro.
macros.
These macros take the same arguments as the
.Fn RB_PROTOTYPE
and
@@ -391,16 +387,15 @@ macros, but should be used only once.
Finally,
the
.Fa CMP
argument is the name of a function used to compare tree nodes
argument is the name of a function used to compare trees' nodes
with each other.
The function takes two arguments of type
.Vt "struct TYPE *" .
.Fa "struct TYPE *" .
If the first argument is smaller than the second, the function returns a
value smaller than zero.
If they are equal, the function returns zero.
Otherwise, it should return a value greater than zero.
The compare
function defines the order of the tree elements.
The compare function defines the order of the tree elements.
.Pp
The
.Fn RB_INIT
@@ -410,11 +405,8 @@ macro initializes the tree referenced by
The red-black tree can also be initialized statically by using the
.Fn RB_INITIALIZER
macro like this:
.Bd -ragged -offset indent
.Fn RB_HEAD HEADNAME TYPE
.Va head
=
.Fn RB_INITIALIZER &head ;
.Bd -literal -offset indent
RB_HEAD(HEADNAME, TYPE) head = RB_INITIALIZER(&head);
.Ed
.Pp
The
@@ -422,6 +414,11 @@ The
macro inserts the new element
.Fa elm
into the tree.
Upon success,
.Va NULL
is returned.
If a matching element already exists in the tree, the insertion is
aborted, and a pointer to the existing element is returned.
.Pp
The
.Fn RB_REMOVE
@@ -429,16 +426,24 @@ macro removes the element
.Fa elm
from the tree pointed by
.Fa head .
.Fn RB_REMOVE
returns
.Fa elm .
.Pp
The
.Fn RB_FIND
and
.Fn RB_NFIND
macros can be used to find a particular element in the tree.
.Fn RB_FIND
finds the node with the same key as
.Fa elm .
.Fn RB_NFIND
finds the first node greater than or equal to the search key.
.Bd -literal -offset indent
struct TYPE find, *res;
find.key = 30;
res = RB_FIND(NAME, head, &find);
res = RB_FIND(NAME, &head, &find);
.Ed
.Pp
The
@@ -449,26 +454,119 @@ The
and
.Fn RB_PREV
macros can be used to traverse the tree:
.Pp
.Dl "for (np = RB_MIN(NAME, &head); np != NULL; np = RB_NEXT(NAME, &head, np))"
.Bd -literal -offset indent
for (np = RB_MIN(NAME, &head); np != NULL; np = RB_NEXT(NAME, &head, np))
.Ed
.Pp
Or, for simplicity, one can use the
.Fn RB_FOREACH
or
.Fn RB_FOREACH_REVERSE
macro:
.Bd -ragged -offset indent
.Fn RB_FOREACH np NAME head
macros:
.Bd -literal -offset indent
RB_FOREACH(np, NAME, &head)
.Ed
.Pp
The macros
.Fn RB_FOREACH_SAFE
and
.Fn RB_FOREACH_REVERSE_SAFE
traverse the tree referenced by head
in a forward or reverse direction respectively,
assigning each element in turn to np.
However, unlike their unsafe counterparts,
they permit both the removal of np
as well as freeing it from within the loop safely
without interfering with the traversal.
.Pp
The
.Fn RB_EMPTY
macro should be used to check whether a red-black tree is empty.
.Sh EXAMPLES
The following example demonstrates how to declare a red-black tree
holding integers.
Values are inserted into it and the contents of the tree are printed
in order.
Lastly, the internal structure of the tree is printed.
.Bd -literal -offset 3n
#include <sys/tree.h>
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
struct node {
RB_ENTRY(node) entry;
int i;
};
int intcmp(struct node *, struct node *);
void print_tree(struct node *);
int
intcmp(struct node *e1, struct node *e2)
{
return (e1->i < e2->i ? -1 : e1->i > e2->i);
}
RB_HEAD(inttree, node) head = RB_INITIALIZER(&head);
RB_PROTOTYPE(inttree, node, entry, intcmp)
RB_GENERATE(inttree, node, entry, intcmp)
int testdata[] = {
20, 16, 17, 13, 3, 6, 1, 8, 2, 4, 10, 19, 5, 9, 12, 15, 18,
7, 11, 14
};
void
print_tree(struct node *n)
{
struct node *left, *right;
if (n == NULL) {
printf("nil");
return;
}
left = RB_LEFT(n, entry);
right = RB_RIGHT(n, entry);
if (left == NULL && right == NULL)
printf("%d", n->i);
else {
printf("%d(", n->i);
print_tree(left);
printf(",");
print_tree(right);
printf(")");
}
}
int
main(void)
{
int i;
struct node *n;
for (i = 0; i < sizeof(testdata) / sizeof(testdata[0]); i++) {
if ((n = malloc(sizeof(struct node))) == NULL)
err(1, NULL);
n->i = testdata[i];
RB_INSERT(inttree, &head, n);
}
RB_FOREACH(n, inttree, &head) {
printf("%d\en", n->i);
}
print_tree(RB_ROOT(&head));
printf("\en");
return (0);
}
.Ed
.Sh SEE ALSO
.Xr queue 3bsd
.Sh NOTES
Trying to free a tree in the following way is a common error:
.Bd -literal -offset indent
SPLAY_FOREACH(var, NAME, head) {
SPLAY_REMOVE(NAME, head, var);
SPLAY_FOREACH(var, NAME, &head) {
SPLAY_REMOVE(NAME, &head, var);
free(var);
}
free(head);
@@ -476,36 +574,17 @@ free(head);
.Pp
Since
.Va var
is freed, the
is free'd, the
.Fn FOREACH
macro refers to a pointer that may have been reallocated already.
Proper code needs a second variable.
.Bd -literal -offset indent
for (var = SPLAY_MIN(NAME, head); var != NULL; var = nxt) {
nxt = SPLAY_NEXT(NAME, head, var);
SPLAY_REMOVE(NAME, head, var);
for (var = SPLAY_MIN(NAME, &head); var != NULL; var = nxt) {
nxt = SPLAY_NEXT(NAME, &head, var);
SPLAY_REMOVE(NAME, &head, var);
free(var);
}
.Ed
.Pp
Both
.Fn RB_INSERT
and
.Fn SPLAY_INSERT
return
.Dv NULL
if the element was inserted in the tree successfully, otherwise they
return a pointer to the element with the colliding key.
.Pp
Accordingly,
.Fn RB_REMOVE
and
.Fn SPLAY_REMOVE
return the pointer to the removed element otherwise they return
.Dv NULL
to indicate an error.
.Sh SEE ALSO
.Xr queue 3bsd
.Sh AUTHORS
The author of the tree macros is
.An Niels Provos .

View File

@@ -25,6 +25,7 @@ libbsd_la_included_sources = \
getentropy_win.c \
$(nil)
CLEANFILES =
EXTRA_DIST = \
libbsd.map \
libbsd.pc.in \
@@ -52,9 +53,8 @@ libbsd_la_DEPENDENCIES = \
$(libbsd_la_included_sources) \
libbsd.map
libbsd_la_LIBADD = \
$(MD_LIBS) \
$(CLOCK_GETTIME_LIBS) \
$(ARC4RANDOM_ATFORK_LIBS) \
$(MD5_LIBS) \
$(LIBBSD_LIBS) \
$(nil)
libbsd_la_LDFLAGS = \
-version-number $(LIBBSD_ABI)
@@ -126,22 +126,51 @@ libbsd_la_SOURCES += \
$(nil)
endif
if NEED_TRANSPARENT_LIBMD
CLEANFILES += \
format.ld \
# EOL
endif
libbsd_ctor_a_SOURCES = \
setproctitle_ctor.c \
$(nil)
if NEED_TRANSPARENT_LIBMD
TRANSPARENT_LIBMD_DEPENDS = format.ld
format.ld:
$(CC) -shared -nostdlib -nostartfiles -x assembler /dev/null -o $@.so
objdump -f $@.so | sed -n 's/.*file format \(.*\)/OUTPUT_FORMAT(\1)/;T;p' > $@
rm -f $@.so
endif
runtimelibdir = $(libdir)
install-exec-hook:
install-exec-hook: $(TRANSPARENT_LIBMD_DEPENDS)
if [ "$(libdir)" != "$(runtimelibdir)" ]; then \
$(MKDIR_P) $(DESTDIR)$(runtimelibdir); \
mv $(DESTDIR)$(libdir)/libbsd*.so.* \
$(DESTDIR)$(runtimelibdir)/; \
fi
if NEED_TRANSPARENT_LIBMD
# The "GNU ld script" magic is required so that GNU ldconfig does not complain
# about an unknown format file.
soname=`readlink $(DESTDIR)$(libdir)/libbsd.so`; \
$(RM) $(DESTDIR)$(libdir)/libbsd.so; \
(echo '/* GNU ld script'; \
echo ' * The MD5 functions are provided by the libmd library. */'; \
cat format.ld; \
echo "GROUP($(runtimelibdir)/$$soname AS_NEEDED($(MD5_LIBS)))"; \
)>$(DESTDIR)$(libdir)/libbsd.so
else
if [ "$(libdir)" != "$(runtimelibdir)" ]; then \
soname=`readlink $(DESTDIR)$(libdir)/libbsd.so`; \
sorelprefix=`echo $(libdir) | sed -r -e 's:(^/)?[^/]+:..:g'`; \
sorelprefix=`echo $(libdir) | $(SED) -r -e 's:(^/)?[^/]+:..:g'`; \
ln -sf $$sorelprefix$(runtimelibdir)/$$soname \
$(DESTDIR)$(libdir)/libbsd.so; \
fi
endif
uninstall-hook:
rm -f $(DESTDIR)$(runtimelibdir)/libbsd*.so*

View File

@@ -1,6 +1,8 @@
/*
* Copyright (c) 2004-2005, 2007, 2010, 2012-2014
* Todd C. Miller <Todd.Miller@courtesan.com>
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
* Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -17,19 +19,17 @@
#include <config.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#ifdef STDC_HEADERS
# include <stdlib.h>
# include <stddef.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
#ifdef __linux__
# include <sys/syscall.h>
# if defined(__NR_close_range) && !defined(SYS_close_range)
# define SYS_close_range __NR_close_range
# endif
#endif /* STDC_HEADERS */
#endif
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#ifdef HAVE_PSTAT_GETPROC
# include <sys/param.h>
# include <sys/pstat.h>
@@ -56,10 +56,6 @@
# define OPEN_MAX 256
#endif
#if defined(HAVE_FCNTL_CLOSEM) && !defined(HAVE_DIRFD)
# define closefrom closefrom_fallback
#endif
static inline void
closefrom_close(int fd)
{
@@ -71,56 +67,64 @@ closefrom_close(int fd)
#endif
}
#if defined(__linux__) && defined(SYS_close_range)
static inline int
sys_close_range(unsigned int fd, unsigned int max_fd, unsigned int flags)
{
return syscall(SYS_close_range, fd, max_fd, flags);
}
#endif
/*
* Close all file descriptors greater than or equal to lowfd.
* This is the expensive (fallback) method.
*/
void
static void
closefrom_fallback(int lowfd)
{
long fd, maxfd;
/*
* Fall back on sysconf() or getdtablesize(). We avoid checking
* resource limits since it is possible to open a file descriptor
* and then drop the rlimit such that it is below the open fd.
* Fall back on sysconf(_SC_OPEN_MAX) or getdtablesize(). This is
* equivalent to checking the RLIMIT_NOFILE soft limit. It is
* possible for there to be open file descriptors past this limit
* but there is not much we can do about that since the hard limit
* may be RLIM_INFINITY (LLONG_MAX or ULLONG_MAX on modern systems).
*/
#ifdef HAVE_SYSCONF
maxfd = sysconf(_SC_OPEN_MAX);
#else
maxfd = getdtablesize();
#endif /* HAVE_SYSCONF */
if (maxfd < 0)
if (maxfd < OPEN_MAX)
maxfd = OPEN_MAX;
/* Make sure we did not get RLIM_INFINITY as the upper limit. */
if (maxfd > INT_MAX)
maxfd = INT_MAX;
for (fd = lowfd; fd < maxfd; fd++)
closefrom_close(fd);
}
/*
* Close all file descriptors greater than or equal to lowfd.
* We try the fast way first, falling back on the slow method.
*/
#if defined(HAVE_FCNTL_CLOSEM)
void
closefrom(int lowfd)
#if defined(HAVE_PSTAT_GETPROC)
static int
closefrom_pstat(int lowfd)
{
if (fcntl(lowfd, F_CLOSEM, 0) == -1)
closefrom_fallback(lowfd);
}
#elif defined(HAVE_PSTAT_GETPROC)
void
closefrom(int lowfd)
{
struct pst_status pstat;
struct pst_status pst;
int fd;
if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1) {
for (fd = lowfd; fd <= pstat.pst_highestfd; fd++)
/*
* EOVERFLOW is not a fatal error for the fields we use.
* See the "EOVERFLOW Error" section of pstat_getvminfo(3).
*/
if (pstat_getproc(&pst, sizeof(pst), 0, getpid()) != -1 ||
errno == EOVERFLOW) {
for (fd = lowfd; fd <= pst.pst_highestfd; fd++)
(void)close(fd);
} else {
closefrom_fallback(lowfd);
return 0;
}
return -1;
}
#elif defined(HAVE_DIRFD)
static int
@@ -135,8 +139,8 @@ closefrom_procfs(int lowfd)
int ret = 0;
int i;
/* Use /proc/self/fd (or /dev/fd on FreeBSD) if it exists. */
# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
/* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */
# ifdef __APPLE__
path = "/dev/fd";
# else
path = "/proc/self/fd";
@@ -180,13 +184,36 @@ closefrom_procfs(int lowfd)
return ret;
}
#endif
/*
* Close all file descriptors greater than or equal to lowfd.
* We try the fast way first, falling back on the slow method.
*/
void
closefrom(int lowfd)
{
if (closefrom_procfs(lowfd) == 0)
return;
if (lowfd < 0)
lowfd = 0;
/* Try the fast methods first, if possible. */
#if defined(HAVE_FCNTL_CLOSEM)
if (fcntl(lowfd, F_CLOSEM, 0) != -1)
return;
#endif /* HAVE_FCNTL_CLOSEM */
#if defined(__linux__) && defined(SYS_close_range)
if (sys_close_range(lowfd, UINT_MAX, 0) == 0)
return;
#endif
#if defined(HAVE_PSTAT_GETPROC)
if (closefrom_pstat(lowfd) != -1)
return;
#elif defined(HAVE_DIRFD)
if (closefrom_procfs(lowfd) != -1)
return;
#endif /* HAVE_DIRFD */
/* Do things the slow way. */
closefrom_fallback(lowfd);
}
#endif /* HAVE_FCNTL_CLOSEM */

View File

@@ -1,4 +1,4 @@
/* $OpenBSD: explicit_bzero.c,v 1.3 2014/06/21 02:34:26 matthew Exp $ */
/* $OpenBSD: explicit_bzero.c,v 1.4 2015/08/31 02:53:57 guenther Exp $ */
/*
* Public domain.
* Written by Matthew Dempsky.
@@ -6,6 +6,9 @@
#include <string.h>
__attribute__((__weak__)) void
__explicit_bzero_hook(void *, size_t);
__attribute__((__weak__)) void
__explicit_bzero_hook(void *buf, size_t len)
{

View File

@@ -76,8 +76,8 @@ fgetln(FILE *stream, size_t *len)
}
}
libbsd_link_warning(fgetln,
"This function cannot be safely ported, use getline(3) "
"instead, as it is supported by GNU and POSIX.1-2008.")
"The fgetln() function cannot be safely ported, use getline(3) "
"instead, as it is supported by GNU and POSIX.1-2008.");
#else
#error "Function fgetln() needs to be ported."
#endif

View File

@@ -88,5 +88,5 @@ fgetwln(FILE *stream, size_t *lenp)
return wused ? fb->wbuf : NULL;
}
libbsd_link_warning(fgetwln,
"This function cannot be safely ported, use fgetwc(3) "
"instead, as it is supported by C99 and POSIX.1-2001.")
"The fgetwln() function cannot be safely ported, use fgetwc(3) "
"instead, as it is supported by C99 and POSIX.1-2001.");

View File

@@ -26,6 +26,8 @@
#include <errno.h>
#include <stddef.h>
int getentropy(void *buf, size_t len);
/*
* Derived from lib/libc/gen/arc4random.c from FreeBSD.
*/

View File

@@ -520,17 +520,17 @@ getentropy_fallback(void *buf, size_t len)
#ifdef HAVE_GETAUXVAL
#ifdef AT_RANDOM
/* Not as random as you think but we take what we are given */
p = (char *) getauxval(AT_RANDOM);
p = (char *) ((intptr_t) getauxval(AT_RANDOM));
if (p)
HR(p, 16);
#endif
#ifdef AT_SYSINFO_EHDR
p = (char *) getauxval(AT_SYSINFO_EHDR);
p = (char *) ((intptr_t) getauxval(AT_SYSINFO_EHDR));
if (p)
HR(p, pgs);
#endif
#ifdef AT_BASE
p = (char *) getauxval(AT_BASE);
p = (char *) ((intptr_t) getauxval(AT_BASE));
if (p)
HD(p);
#endif

View File

@@ -8,4 +8,5 @@ Description: Utility functions from BSD systems (overlay)
Version: @VERSION@
URL: https://libbsd.freedesktop.org/
Libs: -L${libdir} -lbsd
Libs.private: @LIBBSD_LIBS@ @MD5_LIBS@
Cflags: -isystem ${includedir}/bsd -DLIBBSD_OVERLAY

View File

@@ -8,4 +8,5 @@ Description: Utility functions from BSD systems
Version: @VERSION@
URL: https://libbsd.freedesktop.org/
Libs: -L${libdir} -lbsd
Libs.private: @LIBBSD_LIBS@ @MD5_LIBS@
Cflags: -I${includedir}

View File

@@ -27,21 +27,44 @@
#ifndef LIBBSD_LOCAL_LINK_H
#define LIBBSD_LOCAL_LINK_H
#include <sys/cdefs.h>
#define libbsd_link_warning(symbol, msg) \
static const char libbsd_emit_link_warning_##symbol[] \
__attribute__((__used__,__section__(".gnu.warning." #symbol))) = msg;
__attribute__((__used__,__section__(".gnu.warning." #symbol))) = msg
#ifdef __ELF__
# if __has_attribute(symver)
/* The symver attribute is supported since gcc 10.x. */
#define libbsd_symver_default(alias, symbol, version) \
extern __typeof__(symbol) symbol \
__attribute__((__symver__(#alias "@@" #version)))
#define libbsd_symver_variant(alias, symbol, version) \
extern __typeof__(symbol) symbol \
__attribute__((__symver__(#alias "@" #version)))
#define libbsd_symver_weak(alias, symbol, version) \
extern __typeof__(symbol) symbol \
__attribute__((__symver__(#alias "@" #version), __weak__))
# else
#define libbsd_symver_default(alias, symbol, version) \
__asm__(".symver " #symbol "," #alias "@@" #version)
#define libbsd_symver_variant(alias, symbol, version) \
__asm__(".symver " #symbol "," #alias "@" #version)
#define libbsd_symver_weak(alias, symbol, version) \
libbsd_symver_variant(alias, symbol, version); \
extern __typeof__(symbol) alias \
__attribute__((__weak__))
# endif
#else
#define libbsd_symver_default(alias, symbol, version) \
extern __typeof(symbol) alias __attribute__((__alias__(#symbol)))
extern __typeof__(symbol) alias __attribute__((__alias__(#symbol)))
#define libbsd_symver_variant(alias, symbol, version)
#define libbsd_symver_weak(alias, symbol, version)
#endif
#endif

View File

@@ -27,65 +27,94 @@
#include <md5.h>
#include "local-link.h"
#pragma GCC diagnostic ignored "-Wmissing-prototypes"
void
bsd_MD5Init(MD5_CTX *context)
libbsd_MD5Init(MD5_CTX *context)
{
MD5Init(context);
}
libbsd_symver_variant(MD5Init, bsd_MD5Init, LIBBSD_0.0);
libbsd_link_warning(MD5Init,
"The MD5Init() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Init, libbsd_MD5Init, LIBBSD_0.0);
void
bsd_MD5Update(MD5_CTX *context, const uint8_t *data, size_t len)
libbsd_MD5Update(MD5_CTX *context, const uint8_t *data, size_t len)
{
MD5Update(context, data, len);
}
libbsd_symver_variant(MD5Update, bsd_MD5Update, LIBBSD_0.0);
libbsd_link_warning(MD5Update,
"The MD5Update() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Update, libbsd_MD5Update, LIBBSD_0.0);
void
bsd_MD5Pad(MD5_CTX *context)
libbsd_MD5Pad(MD5_CTX *context)
{
MD5Pad(context);
}
libbsd_symver_variant(MD5Pad, bsd_MD5Pad, LIBBSD_0.0);
libbsd_link_warning(MD5Pad,
"The MD5Pad() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Pad, libbsd_MD5Pad, LIBBSD_0.0);
void
bsd_MD5Final(uint8_t digest[MD5_DIGEST_LENGTH], MD5_CTX *context)
libbsd_MD5Final(uint8_t digest[MD5_DIGEST_LENGTH], MD5_CTX *context)
{
MD5Final(digest, context);
}
libbsd_symver_variant(MD5Final, bsd_MD5Final, LIBBSD_0.0);
libbsd_link_warning(MD5Final,
"The MD5Final() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Final, libbsd_MD5Final, LIBBSD_0.0);
void
bsd_MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
libbsd_MD5Transform(uint32_t state[4], const uint8_t block[MD5_BLOCK_LENGTH])
{
MD5Transform(state, block);
}
libbsd_symver_variant(MD5Transform, bsd_MD5Transform, LIBBSD_0.0);
libbsd_link_warning(MD5Transform,
"The MD5Transform() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Transform, libbsd_MD5Transform, LIBBSD_0.0);
char *
bsd_MD5End(MD5_CTX *context, char *buf)
libbsd_MD5End(MD5_CTX *context, char *buf)
{
return MD5End(context, buf);
}
libbsd_symver_variant(MD5End, bsd_MD5End, LIBBSD_0.0);
libbsd_link_warning(MD5End,
"The MD5End() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5End, libbsd_MD5End, LIBBSD_0.0);
char *
bsd_MD5File(const char *filename, char *buf)
libbsd_MD5File(const char *filename, char *buf)
{
return MD5File(filename, buf);
}
libbsd_symver_variant(MD5File, bsd_MD5File, LIBBSD_0.0);
libbsd_link_warning(MD5File,
"The MD5File() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5File, libbsd_MD5File, LIBBSD_0.0);
char *
bsd_MD5FileChunk(const char *filename, char *buf, off_t offset, off_t length)
libbsd_MD5FileChunk(const char *filename, char *buf, off_t offset, off_t length)
{
return MD5FileChunk(filename, buf, offset, length);
}
libbsd_symver_variant(MD5FileChunk, bsd_MD5FileChunk, LIBBSD_0.0);
libbsd_link_warning(MD5FileChunk,
"The MD5FileChunk() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5FileChunk, libbsd_MD5FileChunk, LIBBSD_0.0);
char *
bsd_MD5Data(const uint8_t *data, size_t len, char *buf)
libbsd_MD5Data(const uint8_t *data, size_t len, char *buf)
{
return MD5Data(data, len, buf);
}
libbsd_symver_variant(MD5Data, bsd_MD5Data, LIBBSD_0.0);
libbsd_link_warning(MD5Data,
"The MD5Data() function in libbsd is a deprecated wrapper, "
"use libmd instead.");
libbsd_symver_weak(MD5Data, libbsd_MD5Data, LIBBSD_0.0);

View File

@@ -43,10 +43,6 @@
#include "local-elf.h"
#ifndef SIZE_T_MAX
#define SIZE_T_MAX 0xffffffffU
#endif
/* Note: This function is used by libkvm0, so we need to export it.
* It is not declared in the include files though. */
int __fdnlist(int, struct nlist *);
@@ -153,7 +149,7 @@ __fdnlist(int fd, struct nlist *list)
shdr_size = ehdr.e_shentsize * ehdr.e_shnum;
/* Make sure it's not too big to mmap */
if (shdr_size > SIZE_T_MAX || shdr_size > st.st_size) {
if (shdr_size > st.st_size) {
errno = EFBIG;
return (-1);
}
@@ -186,7 +182,7 @@ __fdnlist(int fd, struct nlist *list)
}
/* Check for files too large to mmap. */
if (symstrsize > SIZE_T_MAX || symstrsize > st.st_size) {
if (symstrsize > st.st_size) {
errno = EFBIG;
goto done;
}
@@ -239,7 +235,6 @@ __fdnlist(int fd, struct nlist *list)
for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) {
char *name;
Elf_Word size;
struct nlist *p;
name = strtab + s->st_name;
if (name[0] == '\0')

View File

@@ -222,6 +222,10 @@ setproctitle_init(int argc, char *argv[], char *envp[])
#define SPT_MAXTITLE 255
#endif
__printflike(1, 2)
void
setproctitle_impl(const char *fmt, ...);
void
setproctitle_impl(const char *fmt, ...)
{

View File

@@ -49,4 +49,4 @@
* move them from .ctors to .init_array.
*/
void (*libbsd_init_func)(int argc, char *argv[], char *envp[])
__attribute__((__section__(".init_array"))) = setproctitle_init;
__attribute__((__section__(".init_array"), __used__)) = setproctitle_init;

View File

@@ -564,12 +564,16 @@ strunvis(char *dst, const char *src)
* NetBSD: 2012, strnunvis(char *dst, size_t dlen, const char *src);
*/
ssize_t
strnunvis_openbsd(char *, const char *, size_t);
ssize_t
strnunvis_openbsd(char *dst, const char *src, size_t dlen)
{
return strnunvisx(dst, dlen, src, 0);
}
libbsd_symver_default(strnunvis, strnunvis_openbsd, LIBBSD_0.2);
int
strnunvis_netbsd(char *, size_t, const char *);
int
strnunvis_netbsd(char *dst, size_t dlen, const char *src)
{

View File

@@ -733,12 +733,16 @@ strvis(char *mbdst, const char *mbsrc, int flags)
* NetBSD: 2012, strnvis(char *dst, size_t dlen, const char *src, int flag);
*/
int
strnvis_openbsd(char *, const char *, size_t, int);
int
strnvis_openbsd(char *mbdst, const char *mbsrc, size_t dlen, int flags)
{
return istrsenvisxl(mbdst, &dlen, mbsrc, flags, "", NULL);
}
libbsd_symver_default(strnvis, strnvis_openbsd, LIBBSD_0.2);
int
strnvis_netbsd(char *, size_t, const char *, int);
int
strnvis_netbsd(char *mbdst, size_t dlen, const char *mbsrc, int flags)
{

View File

@@ -41,6 +41,7 @@ check_PROGRAMS = \
fpurge \
md5 \
nlist \
proctitle \
proctitle-init \
progname \
pwcache \
@@ -52,8 +53,6 @@ check_PROGRAMS = \
vis-openbsd \
$(nil)
md5_LDADD = $(LDADD) $(MD_LIBS)
if HAVE_LIBTESTU01
arc4random_LDADD = $(LDADD) $(TESTU01_LIBS)
@@ -70,6 +69,11 @@ proctitle_LDFLAGS = \
check_PROGRAMS += proctitle
endif
if NEED_TRANSPARENT_LIBMD
# On the installed system this is handled via the ld script.
md5_LDADD = $(LDADD) $(MD5_LIBS)
endif
fgetln_SOURCES = test-stream.c test-stream.h fgetln.c
fgetln_CFLAGS = -Wno-deprecated-declarations
fparseln_SOURCES = test-stream.c test-stream.h fparseln.c

View File

@@ -28,7 +28,7 @@
#include <string.h>
int
main()
main(int argc, char *argv[])
{
unsigned char array[40];
size_t i;

View File

@@ -31,7 +31,7 @@
#include <stdio.h>
int
main()
main(int argc, char *argv[])
{
int i;
int fd;

View File

@@ -30,7 +30,7 @@
#include <string.h>
int
main()
main(int argc, char *argv[])
{
unsigned char decstream[] = {
0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,

View File

@@ -75,7 +75,7 @@ test_fgetln_single(void)
size_t len;
int i;
fp = pipe_feed("%s", (const void **)data_ascii, DATA_LINES);
fp = pipe_feed(PIPE_DATA_ASCII, (const void **)data_ascii, DATA_LINES);
for (i = 0; i < DATA_LINES; i++) {
char *str = fgetln(fp, &len);
@@ -96,13 +96,14 @@ test_fgetln_multi(void)
char *str;
str = strdup("A\n");
assert(str);
str[0] += i;
files[i].line_alloc = str;
files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *));
files[i].lines[0] = str;
files[i].lines[1] = str;
files[i].fp = pipe_feed("%s", files[i].lines, LINE_COUNT);
files[i].fp = pipe_feed(PIPE_DATA_ASCII, files[i].lines, LINE_COUNT);
}
for (l = 0; l < LINE_COUNT; l++) {
@@ -139,7 +140,7 @@ test_fgetwln_single(void)
size_t len;
int i;
fp = pipe_feed("%ls", (const void **)data_wide, DATA_LINES);
fp = pipe_feed(PIPE_DATA_WIDE, (const void **)data_wide, DATA_LINES);
for (i = 0; i < DATA_LINES; i++) {
wchar_t *wstr;
@@ -168,7 +169,7 @@ test_fgetwln_multi(void)
files[i].lines = reallocarray(NULL, LINE_COUNT, sizeof(char *));
files[i].lines[0] = wstr;
files[i].lines[1] = wstr;
files[i].fp = pipe_feed("%ls", files[i].lines, LINE_COUNT);
files[i].fp = pipe_feed(PIPE_DATA_WIDE, files[i].lines, LINE_COUNT);
}
for (l = 0; l < LINE_COUNT; l++) {

View File

@@ -68,7 +68,7 @@ test_fparseln(const char **data_expect, int flags)
FILE *fp;
size_t i, len, lineno = 0;
fp = pipe_feed("%s", (const void **)data_test, TEST_LINES);
fp = pipe_feed(PIPE_DATA_ASCII, (const void **)data_test, TEST_LINES);
for (i = 0; i < EXPECT_LINES; i++) {
char *str = fparseln(fp, &len, &lineno, NULL, flags);

View File

@@ -27,7 +27,7 @@
#include <stdio.h>
int
main()
main(int argc, char *argv[])
{
static FILE fp_bad;
FILE *fp;

View File

@@ -37,7 +37,7 @@ struct test_cookie {
int index;
};
int
static int
test_readfn(void *cookie, char *buf, int size)
{
struct test_cookie *tc = cookie;
@@ -56,7 +56,7 @@ test_readfn(void *cookie, char *buf, int size)
return size;
}
int
static int
test_writefn(void *cookie, const char *buf, int size)
{
struct test_cookie *tc = cookie;
@@ -75,7 +75,7 @@ test_writefn(void *cookie, const char *buf, int size)
return size;
}
off_t
static off_t
test_seekfn(void *cookie, off_t offset, int whence)
{
struct test_cookie *tc = cookie;
@@ -95,7 +95,7 @@ test_seekfn(void *cookie, off_t offset, int whence)
return tc->index;
}
int
static int
test_closefn(void *cookie)
{
struct test_cookie *tc = cookie;
@@ -114,7 +114,7 @@ main(int argc, char **argv)
size_t i;
/* Test invalid hooks. */
fp = funopen(&tc, NULL, NULL, NULL, NULL);
fp = funopen(NULL, NULL, NULL, NULL, NULL);
assert(fp == NULL);
assert(errno == EINVAL);

View File

@@ -28,7 +28,7 @@
#include <md5.h>
#include <string.h>
void
static void
test_md5(const char *digest, const char *string)
{
char result[MD5_DIGEST_STRING_LENGTH];
@@ -37,7 +37,7 @@ test_md5(const char *digest, const char *string)
}
int
main()
main(int argc, char *argv[])
{
test_md5("d41d8cd98f00b204e9800998ecf8427e", "");
test_md5("900150983cd24fb0d6963f7d28e17f72", "abc");

View File

@@ -39,11 +39,11 @@ extern int data_pub_uninit[2048];
extern int *data_pub_ptr;
int *data_pub_ptr = &data_prv_init;
int data_pub_init = 10;
int data_pub_uninit[2048];
int data_pub_init __attribute__((__used__)) = 10;
int data_pub_uninit[2048] __attribute__((__used__));
extern int
func_pub(void);
func_pub(void) __attribute__((__used__)) ;
int
func_pub(void)
@@ -55,11 +55,11 @@ int
main(int argc, char **argv)
{
struct nlist nl[] = {
{ .n_un.n_name = "main" },
{ .n_un.n_name = "func_pub" },
{ .n_un.n_name = "data_pub_uninit" },
{ .n_un.n_name = "data_pub_init" },
{ .n_un.n_name = "data_prv_init" },
{ .n_un.n_name = (char *)"main" },
{ .n_un.n_name = (char *)"func_pub" },
{ .n_un.n_name = (char *)"data_pub_uninit" },
{ .n_un.n_name = (char *)"data_pub_init" },
{ .n_un.n_name = (char *)"data_prv_init" },
{ .n_un.n_name = NULL },
};
int rc;

View File

@@ -45,7 +45,7 @@
#include <unistd.h>
int
main()
main(int argc, char *argv[])
{
/* Test that we do not get partial definitions. */
fflush(stdout);

View File

@@ -35,11 +35,15 @@ main(int argc, char **argv)
assert(strnstr(large, "", strlen(large)) == large);
assert(strnstr(large, "far", strlen(large)) == NULL);
assert(strnstr(large, "quux", strlen(large)) == NULL);
assert(strnstr(large, small, 4) == NULL);
assert(strnstr(large, small, strlen(large)) == (large + 4));
assert(strnstr("quux", large, strlen("quux")) == NULL);
assert(strnstr("foo", large, strlen("foo")) == NULL);
return 0;
}

View File

@@ -27,12 +27,13 @@
#include <sys/wait.h>
#include <assert.h>
#include <unistd.h>
#include <wchar.h>
#include <stdio.h>
#include "test-stream.h"
FILE *
pipe_feed(const char *fmt, const void **buf, int buf_nmemb)
pipe_feed(enum pipe_data_mode mode, const void **buf, int buf_nmemb)
{
FILE *fp;
int rc;
@@ -56,7 +57,10 @@ pipe_feed(const char *fmt, const void **buf, int buf_nmemb)
assert(fp);
for (line = 0; line < buf_nmemb; line++) {
rc = fprintf(fp, fmt, buf[line]);
if (mode == PIPE_DATA_ASCII)
rc = fprintf(fp, "%s", (const char *)buf[line]);
else
rc = fprintf(fp, "%ls", (const wchar_t *)buf[line]);
assert(rc >= 0);
}

View File

@@ -29,8 +29,13 @@
#include <stdio.h>
enum pipe_data_mode {
PIPE_DATA_ASCII,
PIPE_DATA_WIDE,
};
FILE *
pipe_feed(const char *fmt, const void **buf, int buf_nmemb);
pipe_feed(enum pipe_data_mode mode, const void **buf, int buf_nmemb);
void
pipe_close(FILE *fp);