Compare commits

...

36 Commits
0.1.6 ... 0.2.0

Author SHA1 Message Date
Guillem Jover
ddebbd6792 Release libbsd 0.2.0 2010-01-10 15:29:51 +01:00
Guillem Jover
abe0a4a7e6 Reformat code to KNF 2010-01-10 15:29:51 +01:00
Guillem Jover
2872bfa151 Add vis and unvis man pages
Taken from OpenBSD.
2010-01-10 15:29:51 +01:00
Guillem Jover
e544a41f62 Add dehumanize_number man page link 2010-01-10 15:29:51 +01:00
Guillem Jover
7b3873bc1e Update vis and unvis modules from OpenBSD 2010-01-10 15:29:51 +01:00
Guillem Jover
8103fe1486 Update strlcat and strlcpy from OpenBSD 2010-01-10 15:29:51 +01:00
Guillem Jover
d63e081303 Add arc4random_buf and arc4random_uniform functions
Update arc4random module from FreeBSD.
2010-01-10 15:29:50 +01:00
Guillem Jover
3fed78e5b0 Replace setproctitle dummy macro with a function stub
This way we can replace it later on with a real implementation so that
applications can immediately benefit from it w/o the need to recompile
them.
2010-01-10 15:29:50 +01:00
Guillem Jover
2a81893cc0 Add pidfile functions
Taken from FreeBSD.

Remove MAXPATHLEN from ‘struct pidfh’ and allocate pf_path dynamically,
as some systems do not have such limits. Use dev_t instead of __dev_t.
Replace EDOOFUS with EINVAL.
2010-01-10 15:29:46 +01:00
Guillem Jover
98a2479f0b Add flopen function
Taken from FreeBSD.
2010-01-10 13:36:38 +01:00
Guillem Jover
57cc5326cf Move man pages to the same directory as the source code
This matches BSD style source tree, and makes it easier to see what's
missing.
2010-01-10 13:36:38 +01:00
Guillem Jover
9e4adc4633 build: Untangle the package version from the soversion
Add a new script to generate the package version from git. Use that for
the pkg-config file and the tarball name.
2010-01-10 13:36:38 +01:00
Guillem Jover
db406fe24c build: Make dist use files from git plus few autogenerated ones
To avoid forgetting to include files, we'll use “git ls-files” and will
include few precious autogenerated files that cannot be generated later
on w/o git. This includes mainly the ChangeLog.
2010-01-10 13:36:35 +01:00
Guillem Jover
9396cc62cf build: Do not duplicate generated filenames in several variables 2010-01-09 19:56:45 +01:00
Guillem Jover
7a70f1b019 Move fmtcheck and fgetln declarations to <bsd/stdio.h>
This is were they are located on the BSDs.
2009-12-12 01:13:29 +01:00
Guillem Jover
ca28f28046 Move setmode and getmode declarations to <bsd/unistd.h>
This is were they are located on the BSDs.
2009-12-12 01:11:56 +01:00
Guillem Jover
dd2756e000 Mark inclusion of <time.h> from <bsd/bsd.h> deprecated
This will be removed at some point in the future.
2009-12-12 01:11:08 +01:00
Guillem Jover
3c9182b85e Move arc4random declarations to <bsd/stdlib.h>
This is were they are located on the BSDs.
2009-12-12 01:11:08 +01:00
Guillem Jover
4d17a18db5 Deprecate <bsd/inet.h>
The only function declared in that header file was inet_net_pton, which
is already provided by glibc. Will be removed on the next SONAME bump.
2009-12-12 01:11:08 +01:00
Guillem Jover
7da57b293f Remove traces of fgetwln, it was never included
This function was exposed in the header file and the versioning symbol
file, but the actual code was never here.
2009-12-12 01:11:08 +01:00
Guillem Jover
254808d9ef Define NetBSD version 5.0 for .Nx to avoid groff warning
This is a temporary workaround, the proper fix is to get groff to know
newest BSD versions.
2009-12-12 01:11:08 +01:00
Guillem Jover
183cc3cbf1 Correct library name in man pages 2009-12-11 21:31:48 +01:00
Thorsten Glaser
c17c7e13c3 Expand on API guarantee for fgetln
OpenBSD has begun using the API guarantee that *len is not 0 if
the fgetln(3) return value is not NULL; document this explicitly
in the manpage and add a comment to the function implementation
that this doesn’t need to be checked because getdelim/getline have
similar guarantees.

Signed-off-by: Thorsten Glaser <tg@mirbsd.org>
2009-12-10 21:07:02 +01:00
Thorsten Glaser
a5dbef45e7 Make RCS macros take arguments
This was breaking code actually using those macros.

Signed-off-by: Thorsten Glaser <tg@mirbsd.org>
2009-12-10 21:05:52 +01:00
Thorsten Glaser
27842d7f77 Track bug IDs for __unused collision
Signed-off-by: Thorsten Glaser <tg@mirbsd.org>
2009-12-10 21:05:33 +01:00
Guillem Jover
c5398adfe2 Add readpassphrase function
Taken from OpenBSD.
2009-12-10 20:54:03 +01:00
Guillem Jover
538bc87998 Add dehumanize_number function
Taken from NetBSD.
2009-12-10 20:54:00 +01:00
Guillem Jover
04250f6a7c Add strnvis and strnunvis functions
Taken from OpenBSD.
2009-10-24 01:47:26 +02:00
Guillem Jover
5c078ce2f5 Move <bsd/ip_icmp.h> to <bsd/netinet/ip_icmp.h>
This maps more closely the location of the real header. For
transitional purposes keep a <bsd/ip_icmp.h> that warns and includes
<bsd/netinet/ip_icmp.h>.
2009-10-24 01:47:26 +02:00
Guillem Jover
614eb0402a Add new <bsd/sys/tree.h> header 2009-10-24 01:47:25 +02:00
Guillem Jover
b6e8469059 Move <bsd/queue.h> to <bsd/sys/queue.h>
This maps more closely the location of the real header. For
transitional purposes keep a <bsd/queue.h> that warns and includes
<bsd/sys/queue.h>.
2009-10-24 01:47:25 +02:00
Guillem Jover
d3e14ea99e Move <bsd/cdefs.h> to <bsd/sys/cdefs.h>
This maps more closely the location of the real header. For
transitional purposes keep a <bsd/cdefs.h> that warns and includes
<bsd/sys/cdefs.h>.
2009-10-24 01:47:22 +02:00
Guillem Jover
e51be45c40 Update <sys/queue.h>
Taken from FreeBSD.
2009-10-24 01:11:23 +02:00
Guillem Jover
56ddcfe65a Add strtonum function
Taken from FreeBSD.
2009-10-24 01:11:23 +02:00
Guillem Jover
1bf8b96ac8 Do not append a slash after DESTDIR 2009-10-24 01:11:23 +02:00
Guillem Jover
16e6ac99fe Update git web interface URL
FreeDesktop.Org switched from gitweb to cgit.
2009-10-11 20:54:36 +02:00
59 changed files with 4368 additions and 1074 deletions

100
Makefile
View File

@@ -1,7 +1,9 @@
VERSION := $(shell ./get-version)
LIB_NAME := libbsd
LIB_VERSION_MAJOR := 0
LIB_VERSION_MINOR := 1
LIB_VERSION_MICRO := 6
LIB_VERSION_MINOR := 2
LIB_VERSION_MICRO := 0
LIB_VERSION := $(LIB_VERSION_MAJOR).$(LIB_VERSION_MINOR).$(LIB_VERSION_MICRO)
LIB_PKGCONFIG := $(LIB_NAME).pc
@@ -10,69 +12,90 @@ LIB_SHARED_SO := $(LIB_NAME).so
LIB_SONAME := $(LIB_SHARED_SO).$(LIB_VERSION_MAJOR)
LIB_SHARED := $(LIB_SONAME).$(LIB_VERSION_MINOR).$(LIB_VERSION_MICRO)
TAR_NAME := $(LIB_NAME)-$(LIB_VERSION)
TAR_NAME := $(LIB_NAME)-$(VERSION)
TAR_FILE := $(TAR_NAME).tar.gz
LIB_DIST := \
Makefile \
README \
ChangeLog \
Versions \
$(LIB_PKGCONFIG).in
ChangeLog
LIB_SRCS_GEN := \
hash/md5hl.c
LIB_SRCS := \
arc4random.c \
bsd_getopt.c \
err.c \
fgetln.c \
flopen.c \
heapsort.c \
humanize_number.c \
dehumanize_number.c \
inet_net_pton.c \
hash/md5.c hash/md5hl.c \
hash/md5.c \
pidfile.c \
readpassphrase.c \
setmode.c \
setproctitle.c \
strmode.c \
strtonum.c \
strlcat.c strlcpy.c \
fmtcheck.c \
nlist.c \
progname.c \
vis.c unvis.c
vis.c unvis.c \
$(LIB_SRCS_GEN)
LIB_SRCS_GEN := $(patsubst %,src/%,$(LIB_SRCS_GEN))
LIB_SRCS := $(patsubst %,src/%,$(LIB_SRCS))
LIB_GEN_SRCS := \
man/md5.3bsd \
src/hash/md5hl.c
LIB_INCLUDES := \
bsd/cdefs.h \
bsd/queue.h \
bsd/ip_icmp.h \
bsd/sys/cdefs.h \
bsd/sys/queue.h \
bsd/sys/tree.h \
bsd/netinet/ip_icmp.h \
bsd/err.h \
bsd/getopt.h \
bsd/inet.h \
bsd/ip_icmp.h \
bsd/random.h \
bsd/queue.h \
bsd/md5.h \
bsd/string.h \
bsd/bsd.h \
bsd/cdefs.h \
bsd/stdio.h \
bsd/stdlib.h \
bsd/readpassphrase.h \
bsd/unistd.h \
nlist.h \
vis.h \
libutil.h
LIB_MANS_GEN := \
md5.3bsd
LIB_MANS := \
arc4random.3 \
arc4random_addrandom.3 \
arc4random_buf.3 \
arc4random_stir.3 \
arc4random_uniform.3 \
dehumanize_number.3 \
strtonum.3 \
strlcpy.3 \
strlcat.3 \
fgetln.3 \
flopen.3 \
readpassphrase.3 \
humanize_number.3 \
fmtcheck.3 \
nlist.3 \
pidfile.3 \
setmode.3 \
getmode.3 \
strmode.3 \
md5.3bsd
LIB_MANS := $(patsubst %,man/%,$(LIB_MANS))
unvis.3 \
vis.3 \
$(LIB_MANS_GEN)
LIB_MANS_GEN := $(patsubst %,src/%,$(LIB_MANS_GEN))
LIB_MANS := $(patsubst %,src/%,$(LIB_MANS))
LIB_STATIC_OBJS := $(LIB_SRCS:%.c=%.o)
LIB_SHARED_OBJS := $(LIB_SRCS:%.c=%.lo)
@@ -102,14 +125,14 @@ man: $(LIB_MANS)
%.o: %.c
$(CC) -o $@ $(MK_CFLAGS) $(CFLAGS) -c $<
man/md5.3bsd: man/mdX.3
src/md5.3bsd: src/mdX.3
sed -e 's/mdX/md5/g' -e 's/mdY/md4/g' -e 's/MDX/MD5/g' $< > $@
src/hash/md5hl.c: src/hash/helper.c
sed -e 's:hashinc:bsd/md5.h:g' -e 's:HASH:MD5:g' $< > $@
$(LIB_PKGCONFIG): $(LIB_PKGCONFIG).in
sed -e 's:@VERSION@:$(LIB_VERSION):' \
sed -e 's:@VERSION@:$(VERSION):' \
-e 's:@prefix@:$(value prefix):' \
-e 's:@exec_prefix@:$(value exec_prefix):' \
-e 's:@libdir@:$(value usrlibdir):' \
@@ -136,40 +159,43 @@ ChangeLog:
-git log --stat -C >$@
.PHONY: dist
dist: ChangeLog
dist: $(LIB_DIST)
mkdir $(TAR_NAME)
cp -a include src man $(LIB_DIST) $(TAR_NAME)
echo $(VERSION) >$(TAR_NAME)/.dist-version
cp -a --parents $(LIB_DIST) `git ls-files` $(TAR_NAME)
tar czf $(TAR_FILE) --exclude=.gitignore $(TAR_NAME)
rm -rf $(TAR_NAME)
gpg -a -b $(TAR_FILE)
.PHONY: install
install: libs man
mkdir -p $(DESTDIR)/$(libdir)
mkdir -p $(DESTDIR)/$(usrlibdir)
mkdir -p $(DESTDIR)/$(includedir)/bsd/
mkdir -p $(DESTDIR)/$(mandir)/man3
mkdir -p $(DESTDIR)/$(pkgconfigdir)
install -m644 $(LIB_STATIC) $(DESTDIR)/$(usrlibdir)
install -m644 $(LIB_SHARED) $(DESTDIR)/$(libdir)
mkdir -p $(DESTDIR)$(libdir)
mkdir -p $(DESTDIR)$(usrlibdir)
mkdir -p $(DESTDIR)$(includedir)/bsd/
mkdir -p $(DESTDIR)$(includedir)/bsd/sys/
mkdir -p $(DESTDIR)$(includedir)/bsd/netinet/
mkdir -p $(DESTDIR)$(mandir)/man3
mkdir -p $(DESTDIR)$(pkgconfigdir)
install -m644 $(LIB_STATIC) $(DESTDIR)$(usrlibdir)
install -m644 $(LIB_SHARED) $(DESTDIR)$(libdir)
for i in $(LIB_INCLUDES); do \
install -m644 include/$$i $(DESTDIR)/$(includedir)/$$i; \
install -m644 include/$$i $(DESTDIR)$(includedir)/$$i; \
done
install -m644 $(LIB_MANS) $(DESTDIR)/$(mandir)/man3
install -m644 $(LIB_PKGCONFIG) $(DESTDIR)/$(pkgconfigdir)
install -m644 $(LIB_MANS) $(DESTDIR)$(mandir)/man3
install -m644 $(LIB_PKGCONFIG) $(DESTDIR)$(pkgconfigdir)
ifeq ($(libdir),$(usrlibdir))
# If both dirs are the same, do a relative symlink.
ln -sf $(LIB_SHARED) $(DESTDIR)/$(usrlibdir)/$(LIB_SHARED_SO)
ln -sf $(LIB_SHARED) $(DESTDIR)$(usrlibdir)/$(LIB_SHARED_SO)
else
# Otherwise, do an absolute one.
ln -sf $(libdir)/$(LIB_SHARED) $(DESTDIR)/$(usrlibdir)/$(LIB_SHARED_SO)
ln -sf $(libdir)/$(LIB_SHARED) $(DESTDIR)$(usrlibdir)/$(LIB_SHARED_SO)
endif
ln -sf $(LIB_SHARED) $(DESTDIR)/$(libdir)/$(LIB_SONAME)
ln -sf $(LIB_SHARED) $(DESTDIR)$(libdir)/$(LIB_SONAME)
.PHONY: clean
clean:
rm -f $(LIB_PKGCONFIG)
rm -f $(LIB_GEN_SRCS)
rm -f $(LIB_SRCS_GEN) $(LIB_MANS_GEN)
rm -f $(LIB_STATIC_OBJS)
rm -f $(LIB_STATIC)
rm -f $(LIB_SHARED_OBJS)

2
README
View File

@@ -27,6 +27,6 @@ The mail address is:
Source Repository
-----------------
<http://gitweb.freedesktop.org/?p=libbsd.git>
<http://cgit.freedesktop.org/libbsd>
<git://anongit.freedesktop.org/git/libbsd>

View File

@@ -6,11 +6,11 @@ LIBBSD_0.0 {
bsd_getopt; optreset;
errc; warnc; verrc; vwarnc;
fgetln;
fgetwln;
fmtcheck;
heapsort;
humanize_number;
inet_net_pton;
inet_net_pton; /* XXX: Already provided by glibc, remove. */
getprogname; setprogname;
strlcpy;
@@ -42,3 +42,26 @@ LIBBSD_0.1 {
nlist;
} LIBBSD_0.0;
LIBBSD_0.2 {
strtonum;
strnvis;
strnunvis;
dehumanize_number;
readpassphrase;
flopen;
pidfile_open;
pidfile_write;
pidfile_close;
pidfile_remove;
setproctitle;
arc4random_buf;
arc4random_uniform;
} LIBBSD_0.1;

48
get-version Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/sh
#
# get-version
#
# Copyright © 2009 Guillem Jover <guillem@hadrons.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. 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.
if [ -f .dist-version ]; then
# Get the version from the file distributed in the tarball.
version=$(cat .dist-version)
elif [ -d .git ]; then
# Ger the version from the git repository.
version=$(git describe --abbrev=4 HEAD 2>/dev/null)
# Check if we are on a dirty checkout.
git update-index --refresh -q >/dev/null
dirty=$(git diff-index --name-only HEAD 2>/dev/null)
if [ -n "$dirty" ]; then
version="$version-dirty"
fi
else
echo "error: cannot get project version." 1>&2
exit 1
fi
echo "$version"

View File

@@ -31,15 +31,17 @@
* Include all bsd compat headers.
*/
#include <bsd/cdefs.h>
#include <bsd/sys/cdefs.h>
#include <bsd/sys/queue.h>
#include <bsd/sys/tree.h>
#include <bsd/netinet/ip_icmp.h>
#include <bsd/stdlib.h>
#include <bsd/string.h>
#include <bsd/err.h>
#include <bsd/getopt.h>
#include <bsd/random.h>
#include <bsd/md5.h>
#include <bsd/queue.h>
#include <bsd/ip_icmp.h>
/* FIXME: Will be removed in the future. */
#include <time.h>
#endif

View File

@@ -1,5 +1,5 @@
/*
* Copyright © 2004, 2005, 2006, 2009 Guillem Jover
* Copyright © 2009 Guillem Jover
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -24,69 +24,12 @@
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef LIBBSD_CDEFS_H
#define LIBBSD_CDEFS_H
#ifndef LIBBSD_BSD_CDEFS_H
#define LIBBSD_BSD_CDEFS_H
#include <sys/cdefs.h>
#warning "This header is deprecated, use the one in bsd/sys/cdefs.h instead."
#ifndef setproctitle
# define setproctitle(fmt, args...)
#endif
#ifndef __dead2
# define __dead2
#endif
#ifndef __pure2
# define __pure2
#endif
/* Linux headers define a struct with a member names __unused.
* Disable for now. */
#if 0
#ifndef __unused
# ifdef __GNUC__
# define __unused __attribute__((unused))
# else
# define __unused
# endif
#endif
#endif
#ifndef __printflike
# ifdef __GNUC__
# define __printflike(x, y) __attribute((format(printf, (x), (y))))
# else
# define __printflike(x, y)
# endif
#endif
#ifndef __bounded__
# define __bounded__(x, y, z)
#endif
#ifndef __RCSID
# define __RCSID(x)
#endif
#ifndef __FBSDID
# define __FBSDID(x)
#endif
#ifndef __RCSID
# define __RCSID(x)
#endif
#ifndef __RCSID_SOURCE
# define __RCSID_SOURCE
#endif
#ifndef __SCCSID
# define __SCCSID
#endif
#ifndef __COPYRIGHT
# define __COPYRIGHT
#endif
#include <bsd/sys/cdefs.h>
#endif

View File

@@ -27,12 +27,9 @@
#ifndef LIBBSD_INET_H
#define LIBBSD_INET_H
#include <sys/cdefs.h>
#include <stddef.h>
#warning "This header is deprecated, use the one in arpa/inet.h instead."
__BEGIN_DECLS
int inet_net_pton(int af, const char *src, void *dst, siez_t size);
__END_DECLS
#include <arpa/inet.h>
#endif

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 1982, 1986, 1993
* The Regents of the University of California. All rights reserved.
* Copyright © 2009 Guillem Jover
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,194 +9,27 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
* $FreeBSD: src/sys/netinet/ip_icmp.h,v 1.22 2004/04/07 20:46:13 imp Exp $
* 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.
*/
#ifndef _NETINET_IP_ICMP_H_
#define _NETINET_IP_ICMP_H_
#ifndef LIBBSD_BSD_IP_ICMP_H
#define LIBBSD_BSD_IP_ICMP_H
#include <sys/types.h> /* u_int32_t, u_char */
#include <netinet/in.h> /* in_addr */
#include <netinet/in_systm.h> /* n_short */
#include <netinet/ip.h> /* idi_ip */
#warning "This header is deprecated, use <bsd/netinet/ip_icmp.h> instead."
/*
* Interface Control Message Protocol Definitions.
* Per RFC 792, September 1981.
*/
#include <bsd/netinet/ip_icmp.h>
/*
* Internal of an ICMP Router Advertisement
*/
struct icmp_ra_addr {
u_int32_t ira_addr;
u_int32_t ira_preference;
};
/*
* Structure of an icmp header.
*/
struct icmp {
u_char icmp_type; /* type of message, see below */
u_char icmp_code; /* type sub code */
u_short icmp_cksum; /* ones complement cksum of struct */
union {
u_char ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
struct ih_idseq {
n_short icd_id;
n_short icd_seq;
} ih_idseq;
int ih_void;
/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu {
n_short ipm_void;
n_short ipm_nextmtu;
} ih_pmtu;
struct ih_rtradv {
u_char irt_num_addrs;
u_char irt_wpa;
u_int16_t irt_lifetime;
} ih_rtradv;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
#define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
union {
struct id_ts { /* ICMP Timestamp */
n_time its_otime; /* Originate */
n_time its_rtime; /* Receive */
n_time its_ttime; /* Transmit */
} id_ts;
struct id_ip {
struct ip idi_ip;
/* options and then 64 bits of data */
} id_ip;
struct icmp_ra_addr id_radv;
u_int32_t id_mask;
char id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
};
/*
* Lower bounds on packet lengths for various types.
* For the error advice packets must first insure that the
* packet is large enough to contain the returned ip header.
* Only then can we do the check to see if 64 bits of packet
* data have been returned, since we need to check the returned
* ip header length.
*/
#define ICMP_MINLEN 8 /* abs minimum */
#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */
#define ICMP_MASKLEN 12 /* address mask */
#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */
#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
/* N.B.: must separately check that ip_hl >= 5 */
/*
* Definition of type and code field values.
*/
#define ICMP_ECHOREPLY 0 /* echo reply */
#define ICMP_UNREACH 3 /* dest unreachable, codes: */
#define ICMP_UNREACH_NET 0 /* bad net */
#define ICMP_UNREACH_HOST 1 /* bad host */
#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
#define ICMP_UNREACH_PORT 3 /* bad port */
#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */
#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */
#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */
#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */
#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */
#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
#define ICMP_REDIRECT 5 /* shorter route, codes: */
#define ICMP_REDIRECT_NET 0 /* for network */
#define ICMP_REDIRECT_HOST 1 /* for host */
#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
#define ICMP_ALTHOSTADDR 6 /* alternate host address */
#define ICMP_ECHO 8 /* echo service */
#define ICMP_ROUTERADVERT 9 /* router advertisement */
#define ICMP_ROUTERADVERT_NORMAL 0 /* normal advertisement */
#define ICMP_ROUTERADVERT_NOROUTE_COMMON 16 /* selective routing */
#define ICMP_ROUTERSOLICIT 10 /* router solicitation */
#define ICMP_TIMXCEED 11 /* time exceeded, code: */
#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
#define ICMP_PARAMPROB 12 /* ip header bad */
#define ICMP_PARAMPROB_ERRATPTR 0 /* error at param ptr */
#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */
#define ICMP_PARAMPROB_LENGTH 2 /* bad length */
#define ICMP_TSTAMP 13 /* timestamp request */
#define ICMP_TSTAMPREPLY 14 /* timestamp reply */
#define ICMP_IREQ 15 /* information request */
#define ICMP_IREQREPLY 16 /* information reply */
#define ICMP_MASKREQ 17 /* address mask request */
#define ICMP_MASKREPLY 18 /* address mask reply */
#define ICMP_TRACEROUTE 30 /* traceroute */
#define ICMP_DATACONVERR 31 /* data conversion error */
#define ICMP_MOBILE_REDIRECT 32 /* mobile host redirect */
#define ICMP_IPV6_WHEREAREYOU 33 /* IPv6 where-are-you */
#define ICMP_IPV6_IAMHERE 34 /* IPv6 i-am-here */
#define ICMP_MOBILE_REGREQUEST 35 /* mobile registration req */
#define ICMP_MOBILE_REGREPLY 36 /* mobile registration reply */
#define ICMP_SKIP 39 /* SKIP */
#define ICMP_PHOTURIS 40 /* Photuris */
#define ICMP_PHOTURIS_UNKNOWN_INDEX 1 /* unknown sec index */
#define ICMP_PHOTURIS_AUTH_FAILED 2 /* auth failed */
#define ICMP_PHOTURIS_DECRYPT_FAILED 3 /* decrypt failed */
#define ICMP_MAXTYPE 40
#define ICMP_INFOTYPE(type) \
((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
(type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
#ifdef _KERNEL
void icmp_error(struct mbuf *, int, int, n_long, struct ifnet *);
void icmp_input(struct mbuf *, int);
#endif
#endif

View File

@@ -0,0 +1,203 @@
/*
* Copyright (c) 1982, 1986, 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.
*
* @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93
* $FreeBSD: src/sys/netinet/ip_icmp.h,v 1.22 2004/04/07 20:46:13 imp Exp $
*/
#ifndef _NETINET_IP_ICMP_H_
#define _NETINET_IP_ICMP_H_
#include <sys/types.h> /* u_int32_t, u_char */
#include <netinet/in.h> /* in_addr */
#include <netinet/in_systm.h> /* n_short */
#include <netinet/ip.h> /* idi_ip */
/*
* Interface Control Message Protocol Definitions.
* Per RFC 792, September 1981.
*/
/*
* Internal of an ICMP Router Advertisement
*/
struct icmp_ra_addr {
u_int32_t ira_addr;
u_int32_t ira_preference;
};
/*
* Structure of an icmp header.
*/
struct icmp {
u_char icmp_type; /* type of message, see below */
u_char icmp_code; /* type sub code */
u_short icmp_cksum; /* ones complement cksum of struct */
union {
u_char ih_pptr; /* ICMP_PARAMPROB */
struct in_addr ih_gwaddr; /* ICMP_REDIRECT */
struct ih_idseq {
n_short icd_id;
n_short icd_seq;
} ih_idseq;
int ih_void;
/* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */
struct ih_pmtu {
n_short ipm_void;
n_short ipm_nextmtu;
} ih_pmtu;
struct ih_rtradv {
u_char irt_num_addrs;
u_char irt_wpa;
u_int16_t irt_lifetime;
} ih_rtradv;
} icmp_hun;
#define icmp_pptr icmp_hun.ih_pptr
#define icmp_gwaddr icmp_hun.ih_gwaddr
#define icmp_id icmp_hun.ih_idseq.icd_id
#define icmp_seq icmp_hun.ih_idseq.icd_seq
#define icmp_void icmp_hun.ih_void
#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void
#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu
#define icmp_num_addrs icmp_hun.ih_rtradv.irt_num_addrs
#define icmp_wpa icmp_hun.ih_rtradv.irt_wpa
#define icmp_lifetime icmp_hun.ih_rtradv.irt_lifetime
union {
struct id_ts { /* ICMP Timestamp */
n_time its_otime; /* Originate */
n_time its_rtime; /* Receive */
n_time its_ttime; /* Transmit */
} id_ts;
struct id_ip {
struct ip idi_ip;
/* options and then 64 bits of data */
} id_ip;
struct icmp_ra_addr id_radv;
u_int32_t id_mask;
char id_data[1];
} icmp_dun;
#define icmp_otime icmp_dun.id_ts.its_otime
#define icmp_rtime icmp_dun.id_ts.its_rtime
#define icmp_ttime icmp_dun.id_ts.its_ttime
#define icmp_ip icmp_dun.id_ip.idi_ip
#define icmp_radv icmp_dun.id_radv
#define icmp_mask icmp_dun.id_mask
#define icmp_data icmp_dun.id_data
};
/*
* Lower bounds on packet lengths for various types.
* For the error advice packets must first insure that the
* packet is large enough to contain the returned ip header.
* Only then can we do the check to see if 64 bits of packet
* data have been returned, since we need to check the returned
* ip header length.
*/
#define ICMP_MINLEN 8 /* abs minimum */
#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */
#define ICMP_MASKLEN 12 /* address mask */
#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */
#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8)
/* N.B.: must separately check that ip_hl >= 5 */
/*
* Definition of type and code field values.
*/
#define ICMP_ECHOREPLY 0 /* echo reply */
#define ICMP_UNREACH 3 /* dest unreachable, codes: */
#define ICMP_UNREACH_NET 0 /* bad net */
#define ICMP_UNREACH_HOST 1 /* bad host */
#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */
#define ICMP_UNREACH_PORT 3 /* bad port */
#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */
#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */
#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */
#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */
#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */
#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */
#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */
#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */
#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */
#define ICMP_UNREACH_FILTER_PROHIB 13 /* admin prohib */
#define ICMP_UNREACH_HOST_PRECEDENCE 14 /* host prec vio. */
#define ICMP_UNREACH_PRECEDENCE_CUTOFF 15 /* prec cutoff */
#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */
#define ICMP_REDIRECT 5 /* shorter route, codes: */
#define ICMP_REDIRECT_NET 0 /* for network */
#define ICMP_REDIRECT_HOST 1 /* for host */
#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */
#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */
#define ICMP_ALTHOSTADDR 6 /* alternate host address */
#define ICMP_ECHO 8 /* echo service */
#define ICMP_ROUTERADVERT 9 /* router advertisement */
#define ICMP_ROUTERADVERT_NORMAL 0 /* normal advertisement */
#define ICMP_ROUTERADVERT_NOROUTE_COMMON 16 /* selective routing */
#define ICMP_ROUTERSOLICIT 10 /* router solicitation */
#define ICMP_TIMXCEED 11 /* time exceeded, code: */
#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */
#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */
#define ICMP_PARAMPROB 12 /* ip header bad */
#define ICMP_PARAMPROB_ERRATPTR 0 /* error at param ptr */
#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */
#define ICMP_PARAMPROB_LENGTH 2 /* bad length */
#define ICMP_TSTAMP 13 /* timestamp request */
#define ICMP_TSTAMPREPLY 14 /* timestamp reply */
#define ICMP_IREQ 15 /* information request */
#define ICMP_IREQREPLY 16 /* information reply */
#define ICMP_MASKREQ 17 /* address mask request */
#define ICMP_MASKREPLY 18 /* address mask reply */
#define ICMP_TRACEROUTE 30 /* traceroute */
#define ICMP_DATACONVERR 31 /* data conversion error */
#define ICMP_MOBILE_REDIRECT 32 /* mobile host redirect */
#define ICMP_IPV6_WHEREAREYOU 33 /* IPv6 where-are-you */
#define ICMP_IPV6_IAMHERE 34 /* IPv6 i-am-here */
#define ICMP_MOBILE_REGREQUEST 35 /* mobile registration req */
#define ICMP_MOBILE_REGREPLY 36 /* mobile registration reply */
#define ICMP_SKIP 39 /* SKIP */
#define ICMP_PHOTURIS 40 /* Photuris */
#define ICMP_PHOTURIS_UNKNOWN_INDEX 1 /* unknown sec index */
#define ICMP_PHOTURIS_AUTH_FAILED 2 /* auth failed */
#define ICMP_PHOTURIS_DECRYPT_FAILED 3 /* decrypt failed */
#define ICMP_MAXTYPE 40
#define ICMP_INFOTYPE(type) \
((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \
(type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \
(type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \
(type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \
(type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY)
#ifdef _KERNEL
void icmp_error(struct mbuf *, int, int, n_long, struct ifnet *);
void icmp_input(struct mbuf *, int);
#endif
#endif

View File

@@ -1,6 +1,5 @@
/*
* Copyright (c) 1991, 1993
* The Regents of the University of California. All rights reserved.
* Copyright © 2009 Guillem Jover
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -10,544 +9,27 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD: src/sys/sys/queue.h,v 1.58 2004/04/07 04:19:49 imp Exp $
* 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.
*/
#ifndef _SYS_QUEUE_H
#define _SYS_QUEUE_H
#ifndef LIBBSD_BSD_QUEUE_H
#define LIBBSD_BSD_QUEUE_H
#include <sys/cdefs.h>
#warning "This header is deprecated, use the one in bsd/sys/queue.h instead."
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - - - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
*
*/
#define QUEUE_MACRO_DEBUG 0
#if QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
char * lastfile;
int lastline;
char * prevfile;
int prevline;
};
#include <bsd/sys/queue.h>
#define TRACEBUF struct qm_trace trace;
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#endif
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define TRACEBUF
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_NEXT(curelm, field) = \
SLIST_NEXT(SLIST_NEXT(curelm, field), field); \
} \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? \
NULL : \
((struct type *)(void *) \
((char *)((head)->stqh_last) - __offsetof(struct type, field))))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
if ((STAILQ_NEXT(curelm, field) = \
STAILQ_NEXT(STAILQ_NEXT(curelm, field), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((curelm), field);\
} \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_REMOVE_HEAD_UNTIL(head, elm, field) do { \
if ((STAILQ_FIRST((head)) = STAILQ_NEXT((elm), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#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_REMOVE(head, elm, field) do { \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT((elm)->field.tqe_next); \
TRASHIT((elm)->field.tqe_prev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#ifdef _KERNEL
/*
* XXX insque() and remque() are an old way of handling certain queues.
* They bogusly assumes that all queue heads look alike.
*/
struct quehead {
struct quehead *qh_link;
struct quehead *qh_rlink;
};
#if defined(__GNUC__) || defined(__INTEL_COMPILER)
static __inline void
insque(void *a, void *b)
{
struct quehead *element = (struct quehead *)a,
*head = (struct quehead *)b;
element->qh_link = head->qh_link;
element->qh_rlink = head;
head->qh_link = element;
element->qh_link->qh_rlink = element;
}
static __inline void
remque(void *a)
{
struct quehead *element = (struct quehead *)a;
element->qh_link->qh_rlink = element->qh_rlink;
element->qh_rlink->qh_link = element->qh_link;
element->qh_rlink = 0;
}
#else /* !(__GNUC__ || __INTEL_COMPILER) */
void insque(void *a, void *b);
void remque(void *a);
#endif /* __GNUC__ || __INTEL_COMPILER */
#endif /* _KERNEL */
#endif /* !_SYS_QUEUE_H */

View File

@@ -27,14 +27,9 @@
#ifndef LIBBSD_RANDOM_H
#define LIBBSD_RANDOM_H
#include <sys/cdefs.h>
#include <sys/types.h>
#warning "This header is deprecated, use the one in bsd/stdlib.h instead."
__BEGIN_DECLS
u_int32_t arc4random();
void arc4random_stir();
void arc4random_addrandom(u_char *dat, int datlen);
__END_DECLS
#include <bsd/stdlib.h>
#endif

View File

@@ -0,0 +1,41 @@
/* $OpenBSD: readpassphrase.h,v 1.4 2003/06/03 01:52:39 millert Exp $ */
/*
* Copyright (c) 2000, 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.
*/
#ifndef _READPASSPHRASE_H_
#define _READPASSPHRASE_H_
#define RPP_ECHO_OFF 0x00 /* Turn off echo (default). */
#define RPP_ECHO_ON 0x01 /* Leave echo on. */
#define RPP_REQUIRE_TTY 0x02 /* Fail if there is no tty. */
#define RPP_FORCELOWER 0x04 /* Force input to lower case. */
#define RPP_FORCEUPPER 0x08 /* Force input to upper case. */
#define RPP_SEVENBIT 0x10 /* Strip the high bit from input. */
#define RPP_STDIN 0x20 /* Read from stdin, not /dev/tty */
#include <sys/cdefs.h>
#include <sys/types.h>
__BEGIN_DECLS
char * readpassphrase(const char *, char *, size_t, int);
__END_DECLS
#endif /* !_READPASSPHRASE_H_ */

40
include/bsd/stdio.h Normal file
View File

@@ -0,0 +1,40 @@
/*
* Copyright © 2004, 2005, 2009 Guillem Jover
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce 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.
*/
#ifndef LIBBSD_STDIO_H
#define LIBBSD_STDIO_H
#include <sys/cdefs.h>
#include <sys/types.h>
#include <stdio.h>
__BEGIN_DECLS
const char *fmtcheck(const char *, const char *);
char *fgetln(FILE *fp, size_t *lenp);
__END_DECLS
#endif

View File

@@ -31,22 +31,30 @@
#include <sys/cdefs.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdlib.h>
/* For compatibility with NetBSD, which defines humanize_number here. */
#include <libutil.h>
/* FIXME: Temporary inclusions to avoid API breakage, will be removed soon. */
#include <bsd/stdio.h>
#include <bsd/unistd.h>
__BEGIN_DECLS
const char *fmtcheck (const char *, const char *);
u_int32_t arc4random();
void arc4random_stir();
void arc4random_addrandom(u_char *dat, int datlen);
int dehumanize_number(const char *str, int64_t *size);
char *getprogname ();
void setprogname (char *);
int heapsort (void *, size_t, size_t, int (*)(const void *, const void *));
#ifndef S_ISTXT
#define S_ISTXT S_ISVTX
#endif
mode_t getmode(const void *set, mode_t mode);
void *setmode(const char *mode_str);
long long strtonum(const char *nptr, long long minval, long long maxval,
const char **errstr);
__END_DECLS
#endif

View File

@@ -29,15 +29,13 @@
#include <sys/cdefs.h>
#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
/* FIXME: Temporary inclusion to avoid API breakage, will be removed soon. */
#include <bsd/stdio.h>
__BEGIN_DECLS
size_t strlcpy(char *dst, const char *src, size_t siz);
size_t strlcat(char *dst, const char *src, size_t siz);
char *fgetln(FILE *fp, size_t *lenp);
wchar_t *fgetwln(FILE * __restrict fp, size_t *lenp);
void strmode(mode_t mode, char *str);
__END_DECLS

89
include/bsd/sys/cdefs.h Normal file
View File

@@ -0,0 +1,89 @@
/*
* Copyright © 2004, 2005, 2006, 2009 Guillem Jover
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce 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.
*/
#ifndef LIBBSD_CDEFS_H
#define LIBBSD_CDEFS_H
#include <sys/cdefs.h>
#ifndef __dead2
# define __dead2
#endif
#ifndef __pure2
# define __pure2
#endif
/* Linux headers define a struct with a member names __unused.
* Debian bugs: #522773 (linux), #522774 (libc).
* Disable for now. */
#if 0
#ifndef __unused
# ifdef __GNUC__
# define __unused __attribute__((unused))
# else
# define __unused
# endif
#endif
#endif
#ifndef __printflike
# ifdef __GNUC__
# define __printflike(x, y) __attribute((format(printf, (x), (y))))
# else
# define __printflike(x, y)
# endif
#endif
#ifndef __bounded__
# define __bounded__(x, y, z)
#endif
#ifndef __RCSID
# define __RCSID(x)
#endif
#ifndef __FBSDID
# define __FBSDID(x)
#endif
#ifndef __RCSID
# define __RCSID(x)
#endif
#ifndef __RCSID_SOURCE
# define __RCSID_SOURCE(x)
#endif
#ifndef __SCCSID
# define __SCCSID(x)
#endif
#ifndef __COPYRIGHT
# define __COPYRIGHT(x)
#endif
#endif

622
include/bsd/sys/queue.h Normal file
View File

@@ -0,0 +1,622 @@
/*-
* 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.
* 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* @(#)queue.h 8.5 (Berkeley) 8/20/94
* $FreeBSD$
*/
#ifndef _SYS_QUEUE_H_
#define _SYS_QUEUE_H_
#include <sys/cdefs.h>
/*
* This file defines four types of data structures: singly-linked lists,
* singly-linked tail queues, lists and tail queues.
*
* A singly-linked list is headed by a single forward pointer. The elements
* are singly linked for minimum space and pointer manipulation overhead at
* the expense of O(n) removal for arbitrary elements. New elements can be
* added to the list after an existing element or at the head of the list.
* Elements being removed from the head of the list should use the explicit
* macro for this purpose for optimum efficiency. A singly-linked list may
* only be traversed in the forward direction. Singly-linked lists are ideal
* for applications with large datasets and few or no removals or for
* implementing a LIFO queue.
*
* A singly-linked tail queue is headed by a pair of pointers, one to the
* head of the list and the other to the tail of the list. The elements are
* singly linked for minimum space and pointer manipulation overhead at the
* expense of O(n) removal for arbitrary elements. New elements can be added
* to the list after an existing element, at the head of the list, or at the
* end of the list. Elements being removed from the head of the tail queue
* should use the explicit macro for this purpose for optimum efficiency.
* A singly-linked tail queue may only be traversed in the forward direction.
* Singly-linked tail queues are ideal for applications with large datasets
* and few or no removals or for implementing a FIFO queue.
*
* A list is headed by a single forward pointer (or an array of forward
* pointers for a hash table header). The elements are doubly linked
* so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before
* or after an existing element or at the head of the list. A list
* may only be traversed in the forward direction.
*
* A tail queue is headed by a pair of pointers, one to the head of the
* list and the other to the tail of the list. The elements are doubly
* linked so that an arbitrary element can be removed without a need to
* traverse the list. New elements can be added to the list before or
* after an existing element, at the head of the list, or at the end of
* the list. A tail queue may be traversed in either direction.
*
* For details on the use of these macros, see the queue(3) manual page.
*
*
* SLIST LIST STAILQ TAILQ
* _HEAD + + + +
* _HEAD_INITIALIZER + + + +
* _ENTRY + + + +
* _INIT + + + +
* _EMPTY + + + +
* _FIRST + + + +
* _NEXT + + + +
* _PREV - - - +
* _LAST - - + +
* _FOREACH + + + +
* _FOREACH_SAFE + + + +
* _FOREACH_REVERSE - - - +
* _FOREACH_REVERSE_SAFE - - - +
* _INSERT_HEAD + + + +
* _INSERT_BEFORE - + - +
* _INSERT_AFTER + + + +
* _INSERT_TAIL - - + +
* _CONCAT - - + +
* _REMOVE_AFTER + - + -
* _REMOVE_HEAD + - + -
* _REMOVE + + + +
*
*/
#ifdef QUEUE_MACRO_DEBUG
/* Store the last 2 places the queue element or head was altered */
struct qm_trace {
char * lastfile;
int lastline;
char * prevfile;
int prevline;
};
#define TRACEBUF struct qm_trace trace;
#define TRASHIT(x) do {(x) = (void *)-1;} while (0)
#define QMD_TRACE_HEAD(head) do { \
(head)->trace.prevline = (head)->trace.lastline; \
(head)->trace.prevfile = (head)->trace.lastfile; \
(head)->trace.lastline = __LINE__; \
(head)->trace.lastfile = __FILE__; \
} while (0)
#define QMD_TRACE_ELEM(elem) do { \
(elem)->trace.prevline = (elem)->trace.lastline; \
(elem)->trace.prevfile = (elem)->trace.lastfile; \
(elem)->trace.lastline = __LINE__; \
(elem)->trace.lastfile = __FILE__; \
} while (0)
#else
#define QMD_TRACE_ELEM(elem)
#define QMD_TRACE_HEAD(head)
#define TRACEBUF
#define TRASHIT(x)
#endif /* QUEUE_MACRO_DEBUG */
/*
* Singly-linked List declarations.
*/
#define SLIST_HEAD(name, type) \
struct name { \
struct type *slh_first; /* first element */ \
}
#define SLIST_HEAD_INITIALIZER(head) \
{ NULL }
#define SLIST_ENTRY(type) \
struct { \
struct type *sle_next; /* next element */ \
}
/*
* Singly-linked List functions.
*/
#define SLIST_EMPTY(head) ((head)->slh_first == NULL)
#define SLIST_FIRST(head) ((head)->slh_first)
#define SLIST_FOREACH(var, head, field) \
for ((var) = SLIST_FIRST((head)); \
(var); \
(var) = SLIST_NEXT((var), field))
#define SLIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = SLIST_FIRST((head)); \
(var) && ((tvar) = SLIST_NEXT((var), field), 1); \
(var) = (tvar))
#define SLIST_FOREACH_PREVPTR(var, varp, head, field) \
for ((varp) = &SLIST_FIRST((head)); \
((var) = *(varp)) != NULL; \
(varp) = &SLIST_NEXT((var), field))
#define SLIST_INIT(head) do { \
SLIST_FIRST((head)) = NULL; \
} while (0)
#define SLIST_INSERT_AFTER(slistelm, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \
SLIST_NEXT((slistelm), field) = (elm); \
} while (0)
#define SLIST_INSERT_HEAD(head, elm, field) do { \
SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \
SLIST_FIRST((head)) = (elm); \
} while (0)
#define SLIST_NEXT(elm, field) ((elm)->field.sle_next)
#define SLIST_REMOVE(head, elm, type, field) do { \
if (SLIST_FIRST((head)) == (elm)) { \
SLIST_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = SLIST_FIRST((head)); \
while (SLIST_NEXT(curelm, field) != (elm)) \
curelm = SLIST_NEXT(curelm, field); \
SLIST_REMOVE_AFTER(curelm, field); \
} \
TRASHIT((elm)->field.sle_next); \
} while (0)
#define SLIST_REMOVE_AFTER(elm, field) do { \
SLIST_NEXT(elm, field) = \
SLIST_NEXT(SLIST_NEXT(elm, field), field); \
} while (0)
#define SLIST_REMOVE_HEAD(head, field) do { \
SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \
} while (0)
/*
* Singly-linked Tail queue declarations.
*/
#define STAILQ_HEAD(name, type) \
struct name { \
struct type *stqh_first;/* first element */ \
struct type **stqh_last;/* addr of last next element */ \
}
#define STAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).stqh_first }
#define STAILQ_ENTRY(type) \
struct { \
struct type *stqe_next; /* next element */ \
}
/*
* Singly-linked Tail queue functions.
*/
#define STAILQ_CONCAT(head1, head2) do { \
if (!STAILQ_EMPTY((head2))) { \
*(head1)->stqh_last = (head2)->stqh_first; \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_INIT((head2)); \
} \
} while (0)
#define STAILQ_EMPTY(head) ((head)->stqh_first == NULL)
#define STAILQ_FIRST(head) ((head)->stqh_first)
#define STAILQ_FOREACH(var, head, field) \
for((var) = STAILQ_FIRST((head)); \
(var); \
(var) = STAILQ_NEXT((var), field))
#define STAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = STAILQ_FIRST((head)); \
(var) && ((tvar) = STAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define STAILQ_INIT(head) do { \
STAILQ_FIRST((head)) = NULL; \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_NEXT((tqelm), field) = (elm); \
} while (0)
#define STAILQ_INSERT_HEAD(head, elm, field) do { \
if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
STAILQ_FIRST((head)) = (elm); \
} while (0)
#define STAILQ_INSERT_TAIL(head, elm, field) do { \
STAILQ_NEXT((elm), field) = NULL; \
*(head)->stqh_last = (elm); \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_LAST(head, type, field) \
(STAILQ_EMPTY((head)) ? \
NULL : \
((struct type *)(void *) \
((char *)((head)->stqh_last) - __offsetof(struct type, field))))
#define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next)
#define STAILQ_REMOVE(head, elm, type, field) do { \
if (STAILQ_FIRST((head)) == (elm)) { \
STAILQ_REMOVE_HEAD((head), field); \
} \
else { \
struct type *curelm = STAILQ_FIRST((head)); \
while (STAILQ_NEXT(curelm, field) != (elm)) \
curelm = STAILQ_NEXT(curelm, field); \
STAILQ_REMOVE_AFTER(head, curelm, field); \
} \
TRASHIT((elm)->field.stqe_next); \
} while (0)
#define STAILQ_REMOVE_HEAD(head, field) do { \
if ((STAILQ_FIRST((head)) = \
STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \
(head)->stqh_last = &STAILQ_FIRST((head)); \
} while (0)
#define STAILQ_REMOVE_AFTER(head, elm, field) do { \
if ((STAILQ_NEXT(elm, field) = \
STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \
(head)->stqh_last = &STAILQ_NEXT((elm), field); \
} while (0)
#define STAILQ_SWAP(head1, head2, type) do { \
struct type *swap_first = STAILQ_FIRST(head1); \
struct type **swap_last = (head1)->stqh_last; \
STAILQ_FIRST(head1) = STAILQ_FIRST(head2); \
(head1)->stqh_last = (head2)->stqh_last; \
STAILQ_FIRST(head2) = swap_first; \
(head2)->stqh_last = swap_last; \
if (STAILQ_EMPTY(head1)) \
(head1)->stqh_last = &STAILQ_FIRST(head1); \
if (STAILQ_EMPTY(head2)) \
(head2)->stqh_last = &STAILQ_FIRST(head2); \
} while (0)
/*
* List declarations.
*/
#define LIST_HEAD(name, type) \
struct name { \
struct type *lh_first; /* first element */ \
}
#define LIST_HEAD_INITIALIZER(head) \
{ NULL }
#define LIST_ENTRY(type) \
struct { \
struct type *le_next; /* next element */ \
struct type **le_prev; /* address of previous next element */ \
}
/*
* List functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_LIST_CHECK_HEAD(head, field) do { \
if (LIST_FIRST((head)) != NULL && \
LIST_FIRST((head))->field.le_prev != \
&LIST_FIRST((head))) \
panic("Bad list head %p first->prev != head", (head)); \
} while (0)
#define QMD_LIST_CHECK_NEXT(elm, field) do { \
if (LIST_NEXT((elm), field) != NULL && \
LIST_NEXT((elm), field)->field.le_prev != \
&((elm)->field.le_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_LIST_CHECK_PREV(elm, field) do { \
if (*(elm)->field.le_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_LIST_CHECK_HEAD(head, field)
#define QMD_LIST_CHECK_NEXT(elm, field)
#define QMD_LIST_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define LIST_EMPTY(head) ((head)->lh_first == NULL)
#define LIST_FIRST(head) ((head)->lh_first)
#define LIST_FOREACH(var, head, field) \
for ((var) = LIST_FIRST((head)); \
(var); \
(var) = LIST_NEXT((var), field))
#define LIST_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = LIST_FIRST((head)); \
(var) && ((tvar) = LIST_NEXT((var), field), 1); \
(var) = (tvar))
#define LIST_INIT(head) do { \
LIST_FIRST((head)) = NULL; \
} while (0)
#define LIST_INSERT_AFTER(listelm, elm, field) do { \
QMD_LIST_CHECK_NEXT(listelm, field); \
if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\
LIST_NEXT((listelm), field)->field.le_prev = \
&LIST_NEXT((elm), field); \
LIST_NEXT((listelm), field) = (elm); \
(elm)->field.le_prev = &LIST_NEXT((listelm), field); \
} while (0)
#define LIST_INSERT_BEFORE(listelm, elm, field) do { \
QMD_LIST_CHECK_PREV(listelm, field); \
(elm)->field.le_prev = (listelm)->field.le_prev; \
LIST_NEXT((elm), field) = (listelm); \
*(listelm)->field.le_prev = (elm); \
(listelm)->field.le_prev = &LIST_NEXT((elm), field); \
} while (0)
#define LIST_INSERT_HEAD(head, elm, field) do { \
QMD_LIST_CHECK_HEAD((head), field); \
if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \
LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\
LIST_FIRST((head)) = (elm); \
(elm)->field.le_prev = &LIST_FIRST((head)); \
} while (0)
#define LIST_NEXT(elm, field) ((elm)->field.le_next)
#define LIST_REMOVE(elm, field) do { \
QMD_LIST_CHECK_NEXT(elm, field); \
QMD_LIST_CHECK_PREV(elm, field); \
if (LIST_NEXT((elm), field) != NULL) \
LIST_NEXT((elm), field)->field.le_prev = \
(elm)->field.le_prev; \
*(elm)->field.le_prev = LIST_NEXT((elm), field); \
TRASHIT((elm)->field.le_next); \
TRASHIT((elm)->field.le_prev); \
} while (0)
#define LIST_SWAP(head1, head2, type, field) do { \
struct type *swap_tmp = LIST_FIRST((head1)); \
LIST_FIRST((head1)) = LIST_FIRST((head2)); \
LIST_FIRST((head2)) = swap_tmp; \
if ((swap_tmp = LIST_FIRST((head1))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head1)); \
if ((swap_tmp = LIST_FIRST((head2))) != NULL) \
swap_tmp->field.le_prev = &LIST_FIRST((head2)); \
} while (0)
/*
* Tail queue declarations.
*/
#define TAILQ_HEAD(name, type) \
struct name { \
struct type *tqh_first; /* first element */ \
struct type **tqh_last; /* addr of last next element */ \
TRACEBUF \
}
#define TAILQ_HEAD_INITIALIZER(head) \
{ NULL, &(head).tqh_first }
#define TAILQ_ENTRY(type) \
struct { \
struct type *tqe_next; /* next element */ \
struct type **tqe_prev; /* address of previous next element */ \
TRACEBUF \
}
/*
* Tail queue functions.
*/
#if (defined(_KERNEL) && defined(INVARIANTS))
#define QMD_TAILQ_CHECK_HEAD(head, field) do { \
if (!TAILQ_EMPTY(head) && \
TAILQ_FIRST((head))->field.tqe_prev != \
&TAILQ_FIRST((head))) \
panic("Bad tailq head %p first->prev != head", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_TAIL(head, field) do { \
if (*(head)->tqh_last != NULL) \
panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \
} while (0)
#define QMD_TAILQ_CHECK_NEXT(elm, field) do { \
if (TAILQ_NEXT((elm), field) != NULL && \
TAILQ_NEXT((elm), field)->field.tqe_prev != \
&((elm)->field.tqe_next)) \
panic("Bad link elm %p next->prev != elm", (elm)); \
} while (0)
#define QMD_TAILQ_CHECK_PREV(elm, field) do { \
if (*(elm)->field.tqe_prev != (elm)) \
panic("Bad link elm %p prev->next != elm", (elm)); \
} while (0)
#else
#define QMD_TAILQ_CHECK_HEAD(head, field)
#define QMD_TAILQ_CHECK_TAIL(head, headname)
#define QMD_TAILQ_CHECK_NEXT(elm, field)
#define QMD_TAILQ_CHECK_PREV(elm, field)
#endif /* (_KERNEL && INVARIANTS) */
#define TAILQ_CONCAT(head1, head2, field) do { \
if (!TAILQ_EMPTY(head2)) { \
*(head1)->tqh_last = (head2)->tqh_first; \
(head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \
(head1)->tqh_last = (head2)->tqh_last; \
TAILQ_INIT((head2)); \
QMD_TRACE_HEAD(head1); \
QMD_TRACE_HEAD(head2); \
} \
} while (0)
#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL)
#define TAILQ_FIRST(head) ((head)->tqh_first)
#define TAILQ_FOREACH(var, head, field) \
for ((var) = TAILQ_FIRST((head)); \
(var); \
(var) = TAILQ_NEXT((var), field))
#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \
for ((var) = TAILQ_FIRST((head)); \
(var) && ((tvar) = TAILQ_NEXT((var), field), 1); \
(var) = (tvar))
#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \
for ((var) = TAILQ_LAST((head), headname); \
(var); \
(var) = TAILQ_PREV((var), headname, field))
#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \
for ((var) = TAILQ_LAST((head), headname); \
(var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \
(var) = (tvar))
#define TAILQ_INIT(head) do { \
TAILQ_FIRST((head)) = NULL; \
(head)->tqh_last = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
} while (0)
#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(listelm, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\
TAILQ_NEXT((elm), field)->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else { \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
} \
TAILQ_NEXT((listelm), field) = (elm); \
(elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \
QMD_TAILQ_CHECK_PREV(listelm, field); \
(elm)->field.tqe_prev = (listelm)->field.tqe_prev; \
TAILQ_NEXT((elm), field) = (listelm); \
*(listelm)->field.tqe_prev = (elm); \
(listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \
QMD_TRACE_ELEM(&(elm)->field); \
QMD_TRACE_ELEM(&listelm->field); \
} while (0)
#define TAILQ_INSERT_HEAD(head, elm, field) do { \
QMD_TAILQ_CHECK_HEAD(head, field); \
if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \
TAILQ_FIRST((head))->field.tqe_prev = \
&TAILQ_NEXT((elm), field); \
else \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
TAILQ_FIRST((head)) = (elm); \
(elm)->field.tqe_prev = &TAILQ_FIRST((head)); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_INSERT_TAIL(head, elm, field) do { \
QMD_TAILQ_CHECK_TAIL(head, field); \
TAILQ_NEXT((elm), field) = NULL; \
(elm)->field.tqe_prev = (head)->tqh_last; \
*(head)->tqh_last = (elm); \
(head)->tqh_last = &TAILQ_NEXT((elm), field); \
QMD_TRACE_HEAD(head); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_LAST(head, headname) \
(*(((struct headname *)((head)->tqh_last))->tqh_last))
#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_REMOVE(head, elm, field) do { \
QMD_TAILQ_CHECK_NEXT(elm, field); \
QMD_TAILQ_CHECK_PREV(elm, field); \
if ((TAILQ_NEXT((elm), field)) != NULL) \
TAILQ_NEXT((elm), field)->field.tqe_prev = \
(elm)->field.tqe_prev; \
else { \
(head)->tqh_last = (elm)->field.tqe_prev; \
QMD_TRACE_HEAD(head); \
} \
*(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \
TRASHIT((elm)->field.tqe_next); \
TRASHIT((elm)->field.tqe_prev); \
QMD_TRACE_ELEM(&(elm)->field); \
} while (0)
#define TAILQ_SWAP(head1, head2, type, field) do { \
struct type *swap_first = (head1)->tqh_first; \
struct type **swap_last = (head1)->tqh_last; \
(head1)->tqh_first = (head2)->tqh_first; \
(head1)->tqh_last = (head2)->tqh_last; \
(head2)->tqh_first = swap_first; \
(head2)->tqh_last = swap_last; \
if ((swap_first = (head1)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head1)->tqh_first; \
else \
(head1)->tqh_last = &(head1)->tqh_first; \
if ((swap_first = (head2)->tqh_first) != NULL) \
swap_first->field.tqe_prev = &(head2)->tqh_first; \
else \
(head2)->tqh_last = &(head2)->tqh_first; \
} while (0)
#endif /* !_SYS_QUEUE_H_ */

765
include/bsd/sys/tree.h Normal file
View File

@@ -0,0 +1,765 @@
/* $NetBSD: tree.h,v 1.8 2004/03/28 19:38:30 provos Exp $ */
/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */
/* $FreeBSD$ */
/*-
* 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.
*/
#ifndef _SYS_TREE_H_
#define _SYS_TREE_H_
#include <sys/cdefs.h>
/*
* This file defines data structures for different types of trees:
* splay trees and red-black 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.
*
* 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.
*
* 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);
*
* A red-black tree is a binary search tree with the node color as an
* extra attribute. It fulfills a set of conditions:
* - every search path from the root to a leaf consists of the
* same number of black nodes,
* - each red node (except for the root) has a black parent,
* - each leaf node is black.
*
* 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).
*/
#define SPLAY_HEAD(name, type) \
struct name { \
struct type *sph_root; /* root of the tree */ \
}
#define SPLAY_INITIALIZER(root) \
{ NULL }
#define SPLAY_INIT(root) do { \
(root)->sph_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ENTRY(type) \
struct { \
struct type *spe_left; /* left element */ \
struct type *spe_right; /* right element */ \
}
#define SPLAY_LEFT(elm, field) (elm)->field.spe_left
#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right
#define SPLAY_ROOT(head) (head)->sph_root
#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL)
/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */
#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
(head)->sph_root = tmp; \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKLEFT(head, tmp, field) do { \
SPLAY_LEFT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_LINKRIGHT(head, tmp, field) do { \
SPLAY_RIGHT(tmp, field) = (head)->sph_root; \
tmp = (head)->sph_root; \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \
} while (/*CONSTCOND*/ 0)
#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \
SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \
SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \
SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define SPLAY_PROTOTYPE(name, type, field, cmp) \
void name##_SPLAY(struct name *, struct type *); \
void name##_SPLAY_MINMAX(struct name *, int); \
struct type *name##_SPLAY_INSERT(struct name *, struct type *); \
struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \
\
/* Finds the node with the same key as elm */ \
static __inline struct type * \
name##_SPLAY_FIND(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) \
return(NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) \
return (head->sph_root); \
return (NULL); \
} \
\
static __inline struct type * \
name##_SPLAY_NEXT(struct name *head, struct type *elm) \
{ \
name##_SPLAY(head, elm); \
if (SPLAY_RIGHT(elm, field) != NULL) { \
elm = SPLAY_RIGHT(elm, field); \
while (SPLAY_LEFT(elm, field) != NULL) { \
elm = SPLAY_LEFT(elm, field); \
} \
} else \
elm = NULL; \
return (elm); \
} \
\
static __inline struct type * \
name##_SPLAY_MIN_MAX(struct name *head, int val) \
{ \
name##_SPLAY_MINMAX(head, val); \
return (SPLAY_ROOT(head)); \
}
/* Main splay operation.
* Moves node close to the key of elm to top
*/
#define SPLAY_GENERATE(name, type, field, cmp) \
struct type * \
name##_SPLAY_INSERT(struct name *head, struct type *elm) \
{ \
if (SPLAY_EMPTY(head)) { \
SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \
} else { \
int __comp; \
name##_SPLAY(head, elm); \
__comp = (cmp)(elm, (head)->sph_root); \
if(__comp < 0) { \
SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\
SPLAY_RIGHT(elm, field) = (head)->sph_root; \
SPLAY_LEFT((head)->sph_root, field) = NULL; \
} else if (__comp > 0) { \
SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\
SPLAY_LEFT(elm, field) = (head)->sph_root; \
SPLAY_RIGHT((head)->sph_root, field) = NULL; \
} else \
return ((head)->sph_root); \
} \
(head)->sph_root = (elm); \
return (NULL); \
} \
\
struct type * \
name##_SPLAY_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *__tmp; \
if (SPLAY_EMPTY(head)) \
return (NULL); \
name##_SPLAY(head, elm); \
if ((cmp)(elm, (head)->sph_root) == 0) { \
if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \
(head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\
} else { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
(head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\
name##_SPLAY(head, elm); \
SPLAY_RIGHT((head)->sph_root, field) = __tmp; \
} \
return (elm); \
} \
return (NULL); \
} \
\
void \
name##_SPLAY(struct name *head, struct type *elm) \
{ \
struct type __node, *__left, *__right, *__tmp; \
int __comp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if ((cmp)(elm, __tmp) > 0){ \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
} \
\
/* Splay with either the minimum or the maximum element \
* Used to find minimum or maximum element in tree. \
*/ \
void name##_SPLAY_MINMAX(struct name *head, int __comp) \
{ \
struct type __node, *__left, *__right, *__tmp; \
\
SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\
__left = __right = &__node; \
\
while (1) { \
if (__comp < 0) { \
__tmp = SPLAY_LEFT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp < 0){ \
SPLAY_ROTATE_RIGHT(head, __tmp, field); \
if (SPLAY_LEFT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKLEFT(head, __right, field); \
} else if (__comp > 0) { \
__tmp = SPLAY_RIGHT((head)->sph_root, field); \
if (__tmp == NULL) \
break; \
if (__comp > 0) { \
SPLAY_ROTATE_LEFT(head, __tmp, field); \
if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\
break; \
} \
SPLAY_LINKRIGHT(head, __left, field); \
} \
} \
SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \
}
#define SPLAY_NEGINF -1
#define SPLAY_INF 1
#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y)
#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y)
#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y)
#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y)
#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF))
#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \
: name##_SPLAY_MIN_MAX(x, SPLAY_INF))
#define SPLAY_FOREACH(x, name, head) \
for ((x) = SPLAY_MIN(name, head); \
(x) != NULL; \
(x) = SPLAY_NEXT(name, head, x))
/* Macros that define a red-black tree */
#define RB_HEAD(name, type) \
struct name { \
struct type *rbh_root; /* root of the tree */ \
}
#define RB_INITIALIZER(root) \
{ NULL }
#define RB_INIT(root) do { \
(root)->rbh_root = NULL; \
} while (/*CONSTCOND*/ 0)
#define RB_BLACK 0
#define RB_RED 1
#define RB_ENTRY(type) \
struct { \
struct type *rbe_left; /* left element */ \
struct type *rbe_right; /* right element */ \
struct type *rbe_parent; /* parent element */ \
int rbe_color; /* node color */ \
}
#define RB_LEFT(elm, field) (elm)->field.rbe_left
#define RB_RIGHT(elm, field) (elm)->field.rbe_right
#define RB_PARENT(elm, field) (elm)->field.rbe_parent
#define RB_COLOR(elm, field) (elm)->field.rbe_color
#define RB_ROOT(head) (head)->rbh_root
#define RB_EMPTY(head) (RB_ROOT(head) == NULL)
#define RB_SET(elm, parent, field) do { \
RB_PARENT(elm, field) = parent; \
RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \
RB_COLOR(elm, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
#define RB_SET_BLACKRED(black, red, field) do { \
RB_COLOR(black, field) = RB_BLACK; \
RB_COLOR(red, field) = RB_RED; \
} while (/*CONSTCOND*/ 0)
#ifndef RB_AUGMENT
#define RB_AUGMENT(x) do {} while (0)
#endif
#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \
(tmp) = RB_RIGHT(elm, field); \
if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \
RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_LEFT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \
(tmp) = RB_LEFT(elm, field); \
if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \
RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \
} \
RB_AUGMENT(elm); \
if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \
if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \
RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \
else \
RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \
} else \
(head)->rbh_root = (tmp); \
RB_RIGHT(tmp, field) = (elm); \
RB_PARENT(elm, field) = (tmp); \
RB_AUGMENT(tmp); \
if ((RB_PARENT(tmp, field))) \
RB_AUGMENT(RB_PARENT(tmp, field)); \
} while (/*CONSTCOND*/ 0)
/* Generates prototypes and inline functions */
#define RB_PROTOTYPE(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp,)
#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \
RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \
attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \
attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\
attr struct type *name##_RB_REMOVE(struct name *, struct type *); \
attr struct type *name##_RB_INSERT(struct name *, struct type *); \
attr struct type *name##_RB_FIND(struct name *, struct type *); \
attr struct type *name##_RB_NFIND(struct name *, struct type *); \
attr struct type *name##_RB_NEXT(struct type *); \
attr struct type *name##_RB_PREV(struct type *); \
attr struct type *name##_RB_MINMAX(struct name *, int); \
\
/* Main rb operation.
* Moves node close to the key of elm to top
*/
#define RB_GENERATE(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp,)
#define RB_GENERATE_STATIC(name, type, field, cmp) \
RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static)
#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \
attr void \
name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \
{ \
struct type *parent, *gparent, *tmp; \
while ((parent = RB_PARENT(elm, field)) != NULL && \
RB_COLOR(parent, field) == RB_RED) { \
gparent = RB_PARENT(parent, field); \
if (parent == RB_LEFT(gparent, field)) { \
tmp = RB_RIGHT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_RIGHT(parent, field) == elm) { \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_RIGHT(head, gparent, tmp, field); \
} else { \
tmp = RB_LEFT(gparent, field); \
if (tmp && RB_COLOR(tmp, field) == RB_RED) { \
RB_COLOR(tmp, field) = RB_BLACK; \
RB_SET_BLACKRED(parent, gparent, field);\
elm = gparent; \
continue; \
} \
if (RB_LEFT(parent, field) == elm) { \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = parent; \
parent = elm; \
elm = tmp; \
} \
RB_SET_BLACKRED(parent, gparent, field); \
RB_ROTATE_LEFT(head, gparent, tmp, field); \
} \
} \
RB_COLOR(head->rbh_root, field) = RB_BLACK; \
} \
\
attr void \
name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \
{ \
struct type *tmp; \
while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \
elm != RB_ROOT(head)) { \
if (RB_LEFT(parent, field) == elm) { \
tmp = RB_RIGHT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_LEFT(head, parent, tmp, field);\
tmp = RB_RIGHT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\
struct type *oleft; \
if ((oleft = RB_LEFT(tmp, field)) \
!= NULL) \
RB_COLOR(oleft, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_RIGHT(head, tmp, oleft, field);\
tmp = RB_RIGHT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_RIGHT(tmp, field)) \
RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_LEFT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} else { \
tmp = RB_LEFT(parent, field); \
if (RB_COLOR(tmp, field) == RB_RED) { \
RB_SET_BLACKRED(tmp, parent, field); \
RB_ROTATE_RIGHT(head, parent, tmp, field);\
tmp = RB_LEFT(parent, field); \
} \
if ((RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\
(RB_RIGHT(tmp, field) == NULL || \
RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\
RB_COLOR(tmp, field) = RB_RED; \
elm = parent; \
parent = RB_PARENT(elm, field); \
} else { \
if (RB_LEFT(tmp, field) == NULL || \
RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\
struct type *oright; \
if ((oright = RB_RIGHT(tmp, field)) \
!= NULL) \
RB_COLOR(oright, field) = RB_BLACK;\
RB_COLOR(tmp, field) = RB_RED; \
RB_ROTATE_LEFT(head, tmp, oright, field);\
tmp = RB_LEFT(parent, field); \
} \
RB_COLOR(tmp, field) = RB_COLOR(parent, field);\
RB_COLOR(parent, field) = RB_BLACK; \
if (RB_LEFT(tmp, field)) \
RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\
RB_ROTATE_RIGHT(head, parent, tmp, field);\
elm = RB_ROOT(head); \
break; \
} \
} \
} \
if (elm) \
RB_COLOR(elm, field) = RB_BLACK; \
} \
\
attr struct type * \
name##_RB_REMOVE(struct name *head, struct type *elm) \
{ \
struct type *child, *parent, *old = elm; \
int color; \
if (RB_LEFT(elm, field) == NULL) \
child = RB_RIGHT(elm, field); \
else if (RB_RIGHT(elm, field) == NULL) \
child = RB_LEFT(elm, field); \
else { \
struct type *left; \
elm = RB_RIGHT(elm, field); \
while ((left = RB_LEFT(elm, field)) != NULL) \
elm = left; \
child = RB_RIGHT(elm, field); \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
if (RB_PARENT(elm, field) == old) \
parent = elm; \
(elm)->field = (old)->field; \
if (RB_PARENT(old, field)) { \
if (RB_LEFT(RB_PARENT(old, field), field) == old)\
RB_LEFT(RB_PARENT(old, field), field) = elm;\
else \
RB_RIGHT(RB_PARENT(old, field), field) = elm;\
RB_AUGMENT(RB_PARENT(old, field)); \
} else \
RB_ROOT(head) = elm; \
RB_PARENT(RB_LEFT(old, field), field) = elm; \
if (RB_RIGHT(old, field)) \
RB_PARENT(RB_RIGHT(old, field), field) = elm; \
if (parent) { \
left = parent; \
do { \
RB_AUGMENT(left); \
} while ((left = RB_PARENT(left, field)) != NULL); \
} \
goto color; \
} \
parent = RB_PARENT(elm, field); \
color = RB_COLOR(elm, field); \
if (child) \
RB_PARENT(child, field) = parent; \
if (parent) { \
if (RB_LEFT(parent, field) == elm) \
RB_LEFT(parent, field) = child; \
else \
RB_RIGHT(parent, field) = child; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = child; \
color: \
if (color == RB_BLACK) \
name##_RB_REMOVE_COLOR(head, parent, child); \
return (old); \
} \
\
/* Inserts a node into the RB tree */ \
attr struct type * \
name##_RB_INSERT(struct name *head, struct type *elm) \
{ \
struct type *tmp; \
struct type *parent = NULL; \
int comp = 0; \
tmp = RB_ROOT(head); \
while (tmp) { \
parent = tmp; \
comp = (cmp)(elm, parent); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
RB_SET(elm, parent, field); \
if (parent != NULL) { \
if (comp < 0) \
RB_LEFT(parent, field) = elm; \
else \
RB_RIGHT(parent, field) = elm; \
RB_AUGMENT(parent); \
} else \
RB_ROOT(head) = elm; \
name##_RB_INSERT_COLOR(head, elm); \
return (NULL); \
} \
\
/* Finds the node with the same key as elm */ \
attr struct type * \
name##_RB_FIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
} \
\
/* Finds the first node greater than or equal to the search key */ \
attr struct type * \
name##_RB_NFIND(struct name *head, struct type *elm) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *res = NULL; \
int comp; \
while (tmp) { \
comp = cmp(elm, tmp); \
if (comp < 0) { \
res = tmp; \
tmp = RB_LEFT(tmp, field); \
} \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (res); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_NEXT(struct type *elm) \
{ \
if (RB_RIGHT(elm, field)) { \
elm = RB_RIGHT(elm, field); \
while (RB_LEFT(elm, field)) \
elm = RB_LEFT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
/* ARGSUSED */ \
attr struct type * \
name##_RB_PREV(struct type *elm) \
{ \
if (RB_LEFT(elm, field)) { \
elm = RB_LEFT(elm, field); \
while (RB_RIGHT(elm, field)) \
elm = RB_RIGHT(elm, field); \
} else { \
if (RB_PARENT(elm, field) && \
(elm == RB_RIGHT(RB_PARENT(elm, field), field))) \
elm = RB_PARENT(elm, field); \
else { \
while (RB_PARENT(elm, field) && \
(elm == RB_LEFT(RB_PARENT(elm, field), field)))\
elm = RB_PARENT(elm, field); \
elm = RB_PARENT(elm, field); \
} \
} \
return (elm); \
} \
\
attr struct type * \
name##_RB_MINMAX(struct name *head, int val) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *parent = NULL; \
while (tmp) { \
parent = tmp; \
if (val < 0) \
tmp = RB_LEFT(tmp, field); \
else \
tmp = RB_RIGHT(tmp, field); \
} \
return (parent); \
}
#define RB_NEGINF -1
#define RB_INF 1
#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y)
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)
#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF)
#define RB_FOREACH(x, name, head) \
for ((x) = RB_MIN(name, head); \
(x) != NULL; \
(x) = name##_RB_NEXT(x))
#define RB_FOREACH_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_SAFE(x, name, head, y) \
for ((x) = RB_MIN(name, head); \
((x) != NULL) && ((y) = name##_RB_NEXT(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE(x, name, head) \
for ((x) = RB_MAX(name, head); \
(x) != NULL; \
(x) = name##_RB_PREV(x))
#define RB_FOREACH_REVERSE_FROM(x, name, y) \
for ((x) = (y); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#define RB_FOREACH_REVERSE_SAFE(x, name, head, y) \
for ((x) = RB_MAX(name, head); \
((x) != NULL) && ((y) = name##_RB_PREV(x), (x) != NULL); \
(x) = (y))
#endif /* _SYS_TREE_H_ */

44
include/bsd/unistd.h Normal file
View File

@@ -0,0 +1,44 @@
/*
* Copyright © 2008, 2009 Guillem Jover
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce 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.
*/
#ifndef LIBBSD_UNISTD_H
#define LIBBSD_UNISTD_H
#include <sys/cdefs.h>
#include <sys/stat.h>
#ifndef S_ISTXT
#define S_ISTXT S_ISVTX
#endif
__BEGIN_DECLS
mode_t getmode(const void *set, mode_t mode);
void *setmode(const char *mode_str);
void setproctitle(const char *fmt, ...);
__END_DECLS
#endif

View File

@@ -42,10 +42,24 @@
#include <features.h>
#include <sys/types.h>
/* for pidfile.c */
struct pidfh {
int pf_fd;
char *pf_path;
dev_t pf_dev;
ino_t pf_ino;
};
__BEGIN_DECLS
int humanize_number(char *buf, size_t len, int64_t bytes,
const char *suffix, int scale, int flags);
int flopen(const char *_path, int _flags, ...);
struct pidfh *pidfile_open(const char *path, mode_t mode, pid_t *pidptr);
int pidfile_write(struct pidfh *pfh);
int pidfile_close(struct pidfh *pfh);
int pidfile_remove(struct pidfh *pfh);
__END_DECLS
/* humanize_number(3) */

View File

@@ -78,8 +78,10 @@ __BEGIN_DECLS
char *vis(char *, int, int, int);
int strvis(char *, const char *, int);
int strvisx(char *, const char *, size_t, int);
int strnvis(char *, const char *, size_t, int);
int strunvis(char *, const char *);
int strunvisx(char *, const char *, int);
ssize_t strnunvis(char *, const char *, size_t);
int unvis(char *, int, int *, int);
__END_DECLS

View File

View File

@@ -28,23 +28,30 @@
.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
.\"
.\" Manual page, using -mandoc macros
.\" $FreeBSD: /repoman/r/ncvs/src/lib/libc/gen/arc4random.3,v 1.16 2003/07/31 06:18:24 das Exp $
.\" $FreeBSD$
.\"
.Dd April 15, 1997
.Dt ARC4RANDOM 3
.Os
.Sh NAME
.Nm arc4random ,
.Nm arc4random_buf ,
.Nm arc4random_uniform ,
.Nm arc4random_stir ,
.Nm arc4random_addrandom
.Nd arc4 random number generator
.Sh LIBRARY
.Lb libc
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In stdlib.h
.Ft u_int32_t
.Fn arc4random "void"
.Ft void
.Fn arc4random_buf "void *buf" "size_t nbytes"
.Ft u_int32_t
.Fn arc4random_uniform "u_int32_t upper_bound"
.Ft void
.Fn arc4random_stir "void"
.Ft void
.Fn arc4random_addrandom "unsigned char *dat" "int datlen"
@@ -68,6 +75,21 @@ and therefore has twice the range of
and
.Xr random 3 .
.Pp
.Fn arc4random_buf
function fills the region
.Fa buf
of length
.Fa nbytes
with ARC4-derived random data.
.Pp
.Fn arc4random_uniform
will return a uniformly distributed random number less than
.Fa upper_bound .
.Fn arc4random_uniform
is recommended over constructions like
.Dq Li arc4random() % upper_bound
as it avoids "modulo bias" when the upper bound is not a power of two.
.Pp
The
.Fn arc4random_stir
function reads data from
@@ -78,10 +100,9 @@ and uses it to permute the S-Boxes via
There is no need to call
.Fn arc4random_stir
before using
.Fn arc4random ,
since
.Fn arc4random
automatically initializes itself.
functions family, since
they automatically initialize themselves.
.Sh EXAMPLES
The following produces a drop-in replacement for the traditional
.Fn rand

View File

@@ -1,14 +1,23 @@
/*
* Arc4 random number generator for OpenBSD.
* Copyright 1996 David Mazieres <dm@lcs.mit.edu>.
* Copyright (c) 1996, David Mazieres <dm@uun.org>
* Copyright (c) 2008, Damien Miller <djm@openbsd.org>
*
* Modification and redistribution in source and binary forms is
* permitted provided that due credit is given to the author and the
* OpenBSD project (for instance by leaving this copyright notice
* intact).
* 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.
*/
/*
* Arc4 random number generator for OpenBSD.
*
* This code is derived from section 17.1 of Applied Cryptography,
* second edition, which describes a stream cipher allegedly
* compatible with RSA Labs "RC4" cipher (the actual description of
@@ -24,7 +33,7 @@
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD: src/lib/libc/gen/arc4random.c,v 1.10 2004/03/24 14:44:57 green Exp $");
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <sys/time.h>
@@ -40,6 +49,8 @@ struct arc4_stream {
};
#define RANDOMDEV "/dev/urandom"
#define KEYSIZE 128
#ifdef __REENTRANT
static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
#define THREAD_LOCK() pthread_mutex_lock(&arc4random_mtx)
@@ -52,58 +63,63 @@ static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER;
static struct arc4_stream rs;
static int rs_initialized;
static int rs_stired;
static int arc4_count;
static inline u_int8_t arc4_getbyte(struct arc4_stream *);
static void arc4_stir(struct arc4_stream *);
static inline u_int8_t arc4_getbyte(void);
static void arc4_stir(void);
static inline void
arc4_init(struct arc4_stream *as)
arc4_init(void)
{
int n;
for (n = 0; n < 256; n++)
as->s[n] = n;
as->i = 0;
as->j = 0;
rs.s[n] = n;
rs.i = 0;
rs.j = 0;
}
static inline void
arc4_addrandom(struct arc4_stream *as, u_char *dat, int datlen)
arc4_addrandom(u_char *dat, int datlen)
{
int n;
u_int8_t si;
as->i--;
rs.i--;
for (n = 0; n < 256; n++) {
as->i = (as->i + 1);
si = as->s[as->i];
as->j = (as->j + si + dat[n % datlen]);
as->s[as->i] = as->s[as->j];
as->s[as->j] = si;
rs.i = (rs.i + 1);
si = rs.s[rs.i];
rs.j = (rs.j + si + dat[n % datlen]);
rs.s[rs.i] = rs.s[rs.j];
rs.s[rs.j] = si;
}
rs.j = rs.i;
}
static void
arc4_stir(struct arc4_stream *as)
arc4_stir(void)
{
int fd, n;
int done, fd, n;
struct {
struct timeval tv;
pid_t pid;
u_int8_t rnd[128 - sizeof(struct timeval) - sizeof(pid_t)];
} rdat;
struct timeval tv;
pid_t pid;
u_int8_t rnd[KEYSIZE];
} rdat;
gettimeofday(&rdat.tv, NULL);
rdat.pid = getpid();
fd = open(RANDOMDEV, O_RDONLY, 0);
done = 0;
if (fd >= 0) {
(void) read(fd, rdat.rnd, sizeof(rdat.rnd));
close(fd);
if (read(fd, &rdat, KEYSIZE) == KEYSIZE)
done = 1;
(void)close(fd);
}
/* fd < 0? Ah, what the heck. We'll just take whatever was on the
* stack... */
if (!done) {
(void)gettimeofday(&rdat.tv, NULL);
rdat.pid = getpid();
/* We'll just take whatever was on the stack too... */
}
arc4_addrandom(as, (void *) &rdat, sizeof(rdat));
arc4_addrandom((u_char *)&rdat, KEYSIZE);
/*
* Throw away the first N bytes of output, as suggested in the
@@ -113,33 +129,34 @@ arc4_stir(struct arc4_stream *as)
* by Ilya Mironov.
*/
for (n = 0; n < 1024; n++)
arc4_getbyte(as);
(void) arc4_getbyte();
arc4_count = 1600000;
}
static inline u_int8_t
arc4_getbyte(struct arc4_stream *as)
arc4_getbyte(void)
{
u_int8_t si, sj;
as->i = (as->i + 1);
si = as->s[as->i];
as->j = (as->j + si);
sj = as->s[as->j];
as->s[as->i] = sj;
as->s[as->j] = si;
rs.i = (rs.i + 1);
si = rs.s[rs.i];
rs.j = (rs.j + si);
sj = rs.s[rs.j];
rs.s[rs.i] = sj;
rs.s[rs.j] = si;
return (as->s[(si + sj) & 0xff]);
return (rs.s[(si + sj) & 0xff]);
}
static inline u_int32_t
arc4_getword(struct arc4_stream *as)
arc4_getword(void)
{
u_int32_t val;
val = arc4_getbyte(as) << 24;
val |= arc4_getbyte(as) << 16;
val |= arc4_getbyte(as) << 8;
val |= arc4_getbyte(as);
val = arc4_getbyte() << 24;
val |= arc4_getbyte() << 16;
val |= arc4_getbyte() << 8;
val |= arc4_getbyte();
return (val);
}
@@ -148,55 +165,115 @@ static void
arc4_check_init(void)
{
if (!rs_initialized) {
arc4_init(&rs);
arc4_init();
rs_initialized = 1;
}
}
static void
static inline void
arc4_check_stir(void)
{
if (!rs_stired) {
arc4_stir(&rs);
if (!rs_stired || arc4_count <= 0) {
arc4_stir();
rs_stired = 1;
}
}
void
arc4random_stir()
arc4random_stir(void)
{
THREAD_LOCK();
arc4_check_init();
arc4_stir(&rs);
arc4_stir();
rs_stired = 1;
THREAD_UNLOCK();
}
void
arc4random_addrandom(dat, datlen)
u_char *dat;
int datlen;
arc4random_addrandom(u_char *dat, int datlen)
{
THREAD_LOCK();
arc4_check_init();
arc4_check_stir();
arc4_addrandom(&rs, dat, datlen);
arc4_addrandom(dat, datlen);
THREAD_UNLOCK();
}
u_int32_t
arc4random()
arc4random(void)
{
u_int32_t rnd;
THREAD_LOCK();
arc4_check_init();
arc4_check_stir();
rnd = arc4_getword(&rs);
rnd = arc4_getword();
arc4_count -= 4;
THREAD_UNLOCK();
return (rnd);
}
void
arc4random_buf(void *_buf, size_t n)
{
u_char *buf = (u_char *)_buf;
THREAD_LOCK();
arc4_check_init();
while (n--) {
arc4_check_stir();
buf[n] = arc4_getbyte();
arc4_count--;
}
THREAD_UNLOCK();
}
/*
* Calculate a uniformly distributed random number less than upper_bound
* avoiding "modulo bias".
*
* Uniformity is achieved by generating new random numbers until the one
* returned is outside the range [0, 2**32 % upper_bound). This
* guarantees the selected random number will be inside
* [2**32 % upper_bound, 2**32) which maps back to [0, upper_bound)
* after reduction modulo upper_bound.
*/
u_int32_t
arc4random_uniform(u_int32_t upper_bound)
{
u_int32_t r, min;
if (upper_bound < 2)
return (0);
#if (ULONG_MAX > 0xffffffffUL)
min = 0x100000000UL % upper_bound;
#else
/* Calculate (2**32 % upper_bound) avoiding 64-bit math */
if (upper_bound > 0x80000000)
min = 1 + ~upper_bound; /* 2**32 - upper_bound */
else {
/* (2**32 - (x * 2)) % x == 2**32 % x when x <= 2**31 */
min = ((0xffffffff - (upper_bound * 2)) + 1) % upper_bound;
}
#endif
/*
* This could theoretically loop forever but each retry has
* p > 0.5 (worst case, usually far better) of selecting a
* number inside the range we need, so it should rarely need
* to re-roll.
*/
for (;;) {
r = arc4random();
if (r >= min)
break;
}
return (r % upper_bound);
}
#if 0
/*-------- Test code for i386 --------*/
#include <stdio.h>

1
src/arc4random_stir.3 Normal file
View File

@@ -0,0 +1 @@
.so man3/arc4random.3

1
src/arc4random_uniform.3 Normal file
View File

@@ -0,0 +1 @@
.so man3/arc4random.3

View File

@@ -29,13 +29,12 @@
int optreset = 0;
int
bsd_getopt (int argc, char **argv, char *shortopts)
bsd_getopt(int argc, char **argv, char *shortopts)
{
if (optreset == 1)
{
optreset = 0;
optind = 0;
}
if (optreset == 1) {
optreset = 0;
optind = 0;
}
return getopt (argc, argv, shortopts);
return getopt(argc, argv, shortopts);
}

1
src/dehumanize_number.3 Normal file
View File

@@ -0,0 +1 @@
.so man3/humanize_number.3

114
src/dehumanize_number.c Normal file
View File

@@ -0,0 +1,114 @@
/* $NetBSD: dehumanize_number.c,v 1.2 2007/12/14 17:32:47 xtraeme Exp $ */
/*
* Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Julio M. Merino Vidal, developed as part of Google's Summer of Code
* 2005 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 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>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: dehumanize_number.c,v 1.2 2007/12/14 17:32:47 xtraeme Exp $");
#endif /* LIBC_SCCS and not lint */
#include <inttypes.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
/*
* Converts the number given in 'str', which may be given in a humanized
* form (as described in humanize_number(3), but with some limitations),
* to an int64_t without units.
* In case of success, 0 is returned and *size holds the value.
* Otherwise, -1 is returned and *size is untouched.
*
* TODO: Internationalization, SI units.
*/
int
dehumanize_number(const char *str, int64_t *size)
{
char *ep, unit;
const char *delimit;
long multiplier;
long long tmp, tmp2;
size_t len;
len = strlen(str);
if (len == 0) {
errno = EINVAL;
return -1;
}
multiplier = 1;
unit = str[len - 1];
if (isalpha((unsigned char)unit)) {
switch (tolower((unsigned char)unit)) {
case 'b':
multiplier = 1;
break;
case 'k':
multiplier = 1024;
break;
case 'm':
multiplier = 1024 * 1024;
break;
case 'g':
multiplier = 1024 * 1024 * 1024;
break;
default:
errno = EINVAL;
return -1; /* Invalid suffix. */
}
delimit = &str[len - 1];
} else
delimit = NULL;
errno = 0;
tmp = strtoll(str, &ep, 10);
if (str[0] == '\0' || (ep != delimit && *ep != '\0'))
return -1; /* Not a number. */
else if (errno == ERANGE && (tmp == LLONG_MAX || tmp == LLONG_MIN))
return -1; /* Out of range. */
tmp2 = tmp * multiplier;
tmp2 = tmp2 / multiplier;
if (tmp != tmp2) {
errno = ERANGE;
return -1; /* Out of range. */
}
*size = tmp * multiplier;
return 0;
}

View File

@@ -29,44 +29,46 @@
#include <stdarg.h>
void
warnc (int code, const char *format, ...)
warnc(int code, const char *format, ...)
{
int tmp = errno;
va_list ap;
va_start (ap, format);
int tmp = errno;
va_list ap;
errno = code;
warn (format, ap);
errno = tmp;
va_start(ap, format);
va_end (ap);
errno = code;
warn(format, ap);
errno = tmp;
va_end(ap);
}
void
vwarnc (int code, const char *format, va_list ap)
vwarnc(int code, const char *format, va_list ap)
{
int tmp = errno;
int tmp = errno;
errno = code;
vwarn (format, ap);
errno = tmp;
errno = code;
vwarn(format, ap);
errno = tmp;
}
void
errc (int status, int code, const char *format, ...)
errc(int status, int code, const char *format, ...)
{
va_list ap;
va_start (ap, format);
va_list ap;
errno = code;
err (status, format, ap);
va_start(ap, format);
va_end (ap);
errno = code;
err(status, format, ap);
va_end(ap);
}
void
verrc (int status, int code, const char *format, va_list ap)
verrc(int status, int code, const char *format, va_list ap)
{
errno = code;
verr (status, format, ap);
errno = code;
verr(status, format, ap);
}

View File

@@ -35,7 +35,8 @@
.Nm fgetln
.Nd get a line from a stream
.Sh LIBRARY
.Lb libc
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In stdio.h
.Ft char *
@@ -54,7 +55,7 @@ character.
The length of the line, including the final newline,
is stored in the memory location to which
.Fa len
points.
points and is guaranteed to be greater than 0 upon successful completion.
(Note, however, that if the line is the last
in a file that does not end in a newline,
the returned text will not contain a newline.)

View File

@@ -32,13 +32,14 @@
#ifdef __GLIBC__
char *
fgetln (FILE *stream, size_t *len)
fgetln(FILE *stream, size_t *len)
{
static char *line = NULL;
static size_t line_len = 0;
ssize_t nread;
nread = getline(&line, &line_len, stream);
/* Note: the getdelim/getline API ensures nread != 0. */
if (nread == -1) {
*len = 0;
return NULL;

102
src/flopen.3 Normal file
View File

@@ -0,0 +1,102 @@
.\"-
.\" Copyright (c) 2007 Dag-Erling Co<43>dan Sm<53>rgrav
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
.\" LIABILITY, OR TORT (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 June 6, 2009
.Dt FLOPEN 3
.Os
.Sh NAME
.Nm flopen
.Nd "Reliably open and lock a file"
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In sys/fcntl.h
.In libutil.h
.Ft int
.Fn flopen "const char *path" "int flags"
.Ft int
.Fn flopen "const char *path" "int flags" "mode_t mode"
.Sh DESCRIPTION
The
.Fn flopen
function opens or creates a file and acquires an exclusive lock on it.
It is essentially equivalent with calling
.Fn open
with the same parameters followed by
.Fn flock
with an
.Va operation
argument of
.Dv LOCK_EX ,
except that
.Fn flopen
will attempt to detect and handle races that may occur between opening
/ creating the file and locking it.
Thus, it is well suited for opening lock files, PID files, spool
files, mailboxes and other kinds of files which are used for
synchronization between processes.
.Pp
If
.Va flags
includes
.Dv O_NONBLOCK
and the file is already locked,
.Fn flopen
will fail and set
.Va errno
to
.Dv EWOULDBLOCK .
.Pp
As with
.Fn open ,
the additional
.Va mode
argument is required if
.Va flags
includes
.Dv O_CREAT .
.Sh RETURN VALUES
If successful,
.Fn flopen
returns a valid file descriptor.
Otherwise, it returns -1, and sets
.Va errno
as described in
.Xr flock 2
and
.Xr open 2 .
.Sh SEE ALSO
.Xr errno 2 ,
.Xr flock 2 ,
.Xr open 2
.Sh AUTHORS
.An -nosplit
The
.Nm
function and this manual page were written by
.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org .

105
src/flopen.c Normal file
View File

@@ -0,0 +1,105 @@
/*-
* Copyright (c) 2007 Dag-Erling Coïdan Smørgrav
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer
* in this position and unchanged.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/file.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdarg.h>
#include <unistd.h>
#include <libutil.h>
int
flopen(const char *path, int flags, ...)
{
int fd, operation, serrno, trunc;
struct stat sb, fsb;
mode_t mode;
#ifdef O_EXLOCK
flags &= ~O_EXLOCK;
#endif
mode = 0;
if (flags & O_CREAT) {
va_list ap;
va_start(ap, flags);
mode = (mode_t)va_arg(ap, int); /* mode_t promoted to int */
va_end(ap);
}
operation = LOCK_EX;
if (flags & O_NONBLOCK)
operation |= LOCK_NB;
trunc = (flags & O_TRUNC);
flags &= ~O_TRUNC;
for (;;) {
if ((fd = open(path, flags, mode)) == -1)
/* non-existent or no access */
return (-1);
if (flock(fd, operation) == -1) {
/* unsupported or interrupted */
serrno = errno;
(void)close(fd);
errno = serrno;
return (-1);
}
if (stat(path, &sb) == -1) {
/* disappeared from under our feet */
(void)close(fd);
continue;
}
if (fstat(fd, &fsb) == -1) {
/* can't happen [tm] */
serrno = errno;
(void)close(fd);
errno = serrno;
return (-1);
}
if (sb.st_dev != fsb.st_dev ||
sb.st_ino != fsb.st_ino) {
/* changed under our feet */
(void)close(fd);
continue;
}
if (trunc && ftruncate(fd, 0) != 0) {
/* can't happen [tm] */
serrno = errno;
(void)close(fd);
errno = serrno;
return (-1);
}
return (fd);
}
}

View File

@@ -34,7 +34,8 @@
.Xr printf 3 Ns -style
format string
.Sh LIBRARY
.Lb libc
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In stdio.h
.Ft const char *

View File

@@ -34,6 +34,9 @@
.Nm dehumanize_number ,
.Nm humanize_number
.Nd format a number into a human readable form and viceversa
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In stdlib.h
.Ft int
@@ -163,4 +166,6 @@ first appeared in
.Pp
.Fn dehumanize_number
first appeared in
.\" FIXME: This should be in groff, but for now it avoids the warning.
.ds operating-system-NetBSD-5.0 5.0
.Nx 5.0 .

View File

@@ -23,6 +23,9 @@
.Nm MDXFileChunk ,
.Nm MDXData
.Nd calculate the RSA Data Security, Inc., ``MDX'' message digest
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.Fd #include <sys/types.h>
.Fd #include <mdX.h>

View File

@@ -35,7 +35,8 @@
.Nm nlist
.Nd retrieve symbol table name list from an executable file
.Sh LIBRARY
.Lb libc
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In nlist.h
.Ft int

254
src/pidfile.3 Normal file
View File

@@ -0,0 +1,254 @@
.\" Copyright (c) 2005 Pawel Jakub Dawidek <pjd@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 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.
.\"
.\" $FreeBSD$
.\"
.Dd October 20, 2008
.Dt PIDFILE 3
.Os
.Sh NAME
.Nm pidfile_open ,
.Nm pidfile_write ,
.Nm pidfile_close ,
.Nm pidfile_remove
.Nd "library for PID files handling"
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In libutil.h
.Ft "struct pidfh *"
.Fn pidfile_open "const char *path" "mode_t mode" "pid_t *pidptr"
.Ft int
.Fn pidfile_write "struct pidfh *pfh"
.Ft int
.Fn pidfile_close "struct pidfh *pfh"
.Ft int
.Fn pidfile_remove "struct pidfh *pfh"
.Sh DESCRIPTION
The
.Nm pidfile
family of functions allows daemons to handle PID files.
It uses
.Xr flopen 3
to lock a pidfile and detect already running daemons.
.Pp
The
.Fn pidfile_open
function opens (or creates) a file specified by the
.Fa path
argument and locks it.
If a file can not be locked, a PID of an already running daemon is returned in
the
.Fa pidptr
argument (if it is not
.Dv NULL ) .
The function does not write process' PID into the file here, so it can be
used before
.Fn fork Ns ing
and exit with a proper error message when needed.
If the
.Fa path
argument is
.Dv NULL ,
.Pa /var/run/ Ns Ao Va progname Ac Ns Pa .pid
file will be used.
.Pp
The
.Fn pidfile_write
function writes process' PID into a previously opened file.
.Pp
The
.Fn pidfile_close
function closes a pidfile.
It should be used after daemon
.Fn fork Ns s
to start a child process.
.Pp
The
.Fn pidfile_remove
function closes and removes a pidfile.
.Sh RETURN VALUES
The
.Fn pidfile_open
function returns a valid pointer to a
.Vt pidfh
structure on success, or
.Dv NULL
if an error occurs.
If an error occurs,
.Va errno
will be set.
.Pp
.Rv -std pidfile_write pidfile_close pidfile_remove
.Sh EXAMPLES
The following example shows in which order these functions should be used.
Note that it is safe to pass
.Dv NULL
to
.Fn pidfile_write ,
.Fn pidfile_remove
and
.Fn pidfile_close
functions.
.Bd -literal
struct pidfh *pfh;
pid_t otherpid, childpid;
pfh = pidfile_open("/var/run/daemon.pid", 0600, &otherpid);
if (pfh == NULL) {
if (errno == EEXIST) {
errx(EXIT_FAILURE, "Daemon already running, pid: %jd.",
(intmax_t)otherpid);
}
/* If we cannot create pidfile from other reasons, only warn. */
warn("Cannot open or create pidfile");
}
if (daemon(0, 0) == -1) {
warn("Cannot daemonize");
pidfile_remove(pfh);
exit(EXIT_FAILURE);
}
pidfile_write(pfh);
for (;;) {
/* Do work. */
childpid = fork();
switch (childpid) {
case -1:
syslog(LOG_ERR, "Cannot fork(): %s.", strerror(errno));
break;
case 0:
pidfile_close(pfh);
/* Do child work. */
break;
default:
syslog(LOG_INFO, "Child %jd started.", (intmax_t)childpid);
break;
}
}
pidfile_remove(pfh);
exit(EXIT_SUCCESS);
.Ed
.Sh ERRORS
The
.Fn pidfile_open
function will fail if:
.Bl -tag -width Er
.It Bq Er EEXIST
Some process already holds the lock on the given pidfile, meaning that a
daemon is already running.
.It Bq Er ENAMETOOLONG
Specified pidfile's name is too long.
.It Bq Er EINVAL
Some process already holds the lock on the given pidfile, but PID read
from there is invalid.
.It Bq Er EAGAIN
Some process already holds the lock on the given pidfile, but the file
is truncated.
Most likely, the existing daemon is writing new PID into
the file.
.El
.Pp
The
.Fn pidfile_open
function may also fail and set
.Va errno
for any errors specified for the
.Xr fstat 2 ,
.Xr open 2 ,
and
.Xr read 2
calls.
.Pp
The
.Fn pidfile_write
function will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
Improper function use.
Probably called before
.Fn pidfile_open .
.El
.Pp
The
.Fn pidfile_write
function may also fail and set
.Va errno
for any errors specified for the
.Xr fstat 2 ,
.Xr ftruncate 2 ,
and
.Xr write 2
calls.
.Pp
The
.Fn pidfile_close
function may fail and set
.Va errno
for any errors specified for the
.Xr close 2
and
.Xr fstat 2
calls.
.Pp
The
.Fn pidfile_remove
function will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
Improper function use.
Probably called not from the process which made
.Fn pidfile_write .
.El
.Pp
The
.Fn pidfile_remove
function may also fail and set
.Va errno
for any errors specified for the
.Xr close 2 ,
.Xr fstat 2 ,
.Xr write 2 ,
and
.Xr unlink 2
system calls and the
.Xr flopen 3
library function.
.Sh SEE ALSO
.Xr open 2 ,
.Xr daemon 3 ,
.Xr flopen 3
.Sh AUTHORS
.An -nosplit
The
.Nm pidfile
functionality is based on ideas from
.An John-Mark Gurney Aq jmg@FreeBSD.org .
.Pp
The code and manual page was written by
.An Pawel Jakub Dawidek Aq pjd@FreeBSD.org .

255
src/pidfile.c Normal file
View File

@@ -0,0 +1,255 @@
/*-
* Copyright (c) 2005 Pawel Jakub Dawidek <pjd@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 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>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <time.h>
#include <err.h>
#include <errno.h>
#include <libutil.h>
static int _pidfile_remove(struct pidfh *pfh, int freeit);
static int
pidfile_verify(struct pidfh *pfh)
{
struct stat sb;
if (pfh == NULL || pfh->pf_fd == -1)
return (EINVAL);
/*
* Check remembered descriptor.
*/
if (fstat(pfh->pf_fd, &sb) == -1)
return (errno);
if (sb.st_dev != pfh->pf_dev || sb.st_ino != pfh->pf_ino)
return (EINVAL);
return (0);
}
static int
pidfile_read(const char *path, pid_t *pidptr)
{
char buf[16], *endptr;
int error, fd, i;
fd = open(path, O_RDONLY);
if (fd == -1)
return (errno);
i = read(fd, buf, sizeof(buf) - 1);
error = errno; /* Remember errno in case close() wants to change it. */
close(fd);
if (i == -1)
return (error);
else if (i == 0)
return (EAGAIN);
buf[i] = '\0';
*pidptr = strtol(buf, &endptr, 10);
if (endptr != &buf[i])
return (EINVAL);
return (0);
}
struct pidfh *
pidfile_open(const char *path, mode_t mode, pid_t *pidptr)
{
struct pidfh *pfh;
struct stat sb;
int error, fd, len, count;
struct timespec rqtp;
pfh = malloc(sizeof(*pfh));
if (pfh == NULL)
return (NULL);
if (path == NULL) {
len = asprintf(&pfh->pf_path, "/var/run/%s.pid", getprogname());
if (len < 0) {
free(pfh);
return (NULL);
}
} else
pfh->pf_path = strdup(path);
/*
* Open the PID file and obtain exclusive lock.
* We truncate PID file here only to remove old PID immediatelly,
* PID file will be truncated again in pidfile_write(), so
* pidfile_write() can be called multiple times.
*/
fd = flopen(pfh->pf_path,
O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, mode);
if (fd == -1) {
count = 0;
rqtp.tv_sec = 0;
rqtp.tv_nsec = 5000000;
if (errno == EWOULDBLOCK && pidptr != NULL) {
again:
errno = pidfile_read(pfh->pf_path, pidptr);
if (errno == 0)
errno = EEXIST;
else if (errno == EAGAIN) {
if (++count <= 3) {
nanosleep(&rqtp, 0);
goto again;
}
}
}
free(pfh->pf_path);
free(pfh);
return (NULL);
}
/*
* Remember file information, so in pidfile_write() we are sure we write
* to the proper descriptor.
*/
if (fstat(fd, &sb) == -1) {
error = errno;
unlink(pfh->pf_path);
free(pfh->pf_path);
close(fd);
free(pfh);
errno = error;
return (NULL);
}
pfh->pf_fd = fd;
pfh->pf_dev = sb.st_dev;
pfh->pf_ino = sb.st_ino;
return (pfh);
}
int
pidfile_write(struct pidfh *pfh)
{
char pidstr[16];
int error, fd;
/*
* Check remembered descriptor, so we don't overwrite some other
* file if pidfile was closed and descriptor reused.
*/
errno = pidfile_verify(pfh);
if (errno != 0) {
/*
* Don't close descriptor, because we are not sure if it's ours.
*/
return (-1);
}
fd = pfh->pf_fd;
/*
* Truncate PID file, so multiple calls of pidfile_write() are allowed.
*/
if (ftruncate(fd, 0) == -1) {
error = errno;
_pidfile_remove(pfh, 0);
errno = error;
return (-1);
}
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
if (pwrite(fd, pidstr, strlen(pidstr), 0) != (ssize_t)strlen(pidstr)) {
error = errno;
_pidfile_remove(pfh, 0);
errno = error;
return (-1);
}
return (0);
}
int
pidfile_close(struct pidfh *pfh)
{
int error;
error = pidfile_verify(pfh);
if (error != 0) {
errno = error;
return (-1);
}
if (close(pfh->pf_fd) == -1)
error = errno;
free(pfh->pf_path);
free(pfh);
if (error != 0) {
errno = error;
return (-1);
}
return (0);
}
static int
_pidfile_remove(struct pidfh *pfh, int freeit)
{
int error;
error = pidfile_verify(pfh);
if (error != 0) {
errno = error;
return (-1);
}
if (unlink(pfh->pf_path) == -1)
error = errno;
if (close(pfh->pf_fd) == -1) {
if (error == 0)
error = errno;
}
if (freeit) {
free(pfh->pf_path);
free(pfh);
} else
pfh->pf_fd = -1;
if (error != 0) {
errno = error;
return (-1);
}
return (0);
}
int
pidfile_remove(struct pidfh *pfh)
{
return (_pidfile_remove(pfh, 1));
}

View File

@@ -33,13 +33,13 @@
static char *__progname = NULL;
char *
getprogname ()
getprogname()
{
return __progname;
return __progname;
}
void
setprogname (char *new)
setprogname(char *new)
{
__progname = new;
__progname = new;
}

168
src/readpassphrase.3 Normal file
View File

@@ -0,0 +1,168 @@
.\" $OpenBSD: readpassphrase.3,v 1.16 2005/07/22 03:16:58 jaredy Exp $
.\"
.\" Copyright (c) 2000, 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.
.\"
.Dd $Mdocdate: May 31 2007 $
.Dt READPASSPHRASE 3
.Os
.Sh NAME
.Nm readpassphrase
.Nd get a passphrase from the user
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.Fd #include <readpassphrase.h>
.Ft char *
.Fn readpassphrase "const char *prompt" "char *buf" "size_t bufsiz" "int flags"
.Sh DESCRIPTION
The
.Fn readpassphrase
function displays a prompt to, and reads in a passphrase from,
.Pa /dev/tty .
If this file is inaccessible
and the
.Dv RPP_REQUIRE_TTY
flag is not set,
.Fn readpassphrase
displays the prompt on the standard error output and reads from the standard
input.
In this case it is generally not possible to turn off echo.
.Pp
Up to
.Fa bufsiz
- 1 characters (one is for the NUL) are read into the provided buffer
.Fa buf .
Any additional
characters and the terminating newline (or return) character are discarded.
.Pp
.Fn readpassphrase
takes the following optional
.Fa flags :
.Bd -literal -offset indent
RPP_ECHO_OFF turn off echo (default behavior)
RPP_ECHO_ON leave echo on
RPP_REQUIRE_TTY fail if there is no tty
RPP_FORCELOWER force input to lower case
RPP_FORCEUPPER force input to upper case
RPP_SEVENBIT strip the high bit from input
RPP_STDIN force read of passphrase from stdin
.Ed
.Pp
The calling process should zero the passphrase as soon as possible to
avoid leaving the cleartext passphrase visible in the process's address
space.
.Sh RETURN VALUES
Upon successful completion,
.Fn readpassphrase
returns a pointer to the NUL-terminated passphrase.
If an error is encountered, the terminal state is restored and
a null pointer is returned.
.Sh FILES
.Bl -tag -width /dev/tty -compact
.It Pa /dev/tty
.El
.Sh EXAMPLES
The following code fragment will read a passphrase from
.Pa /dev/tty
into the buffer
.Fa passbuf .
.Bd -literal -offset indent
char passbuf[1024];
\&...
if (readpassphrase("Response: ", passbuf, sizeof(passbuf),
RPP_REQUIRE_TTY) == NULL)
errx(1, "unable to read passphrase");
if (compare(transform(passbuf), epass) != 0)
errx(1, "bad passphrase");
\&...
memset(passbuf, 0, sizeof(passbuf));
.Ed
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er EINTR
The
.Fn readpassphrase
function was interrupted by a signal.
.It Bq Er EINVAL
The
.Ar bufsiz
argument was zero.
.It Bq Er EIO
The process is a member of a background process attempting to read
from its controlling terminal, the process is ignoring or blocking
the
.Dv SIGTTIN
signal, or the process group is orphaned.
.It Bq Er EMFILE
The process has already reached its limit for open file descriptors.
.It Bq Er ENFILE
The system file table is full.
.It Bq Er ENOTTY
There is no controlling terminal and the
.Dv RPP_REQUIRE_TTY
flag was specified.
.El
.Sh SIGNALS
.Fn readpassphrase
will catch the following signals:
.Bd -literal -offset indent
SIGALRM SIGHUP SIGINT
SIGPIPE SIGQUIT SIGTERM
SIGTSTP SIGTTIN SIGTTOU
.Ed
.Pp
When one of the above signals is intercepted, terminal echo will
be restored if it had previously been turned off.
If a signal handler was installed for the signal when
.Fn readpassphrase
was called, that handler is then executed.
If no handler was previously installed for the signal then the
default action is taken as per
.Xr sigaction 2 .
.Pp
The
.Dv SIGTSTP ,
.Dv SIGTTIN ,
and
.Dv SIGTTOU
signals (stop signals generated from keyboard or due to terminal I/O
from a background process) are treated specially.
When the process is resumed after it has been stopped,
.Fn readpassphrase
will reprint the prompt and the user may then enter a passphrase.
.Sh SEE ALSO
.Xr sigaction 2 ,
.Xr getpass 3
.Sh STANDARDS
The
.Fn readpassphrase
function is an
.Ox
extension and should not be used if portability is desired.
.Sh HISTORY
The
.Fn readpassphrase
function first appeared in
.Ox 2.9 .

187
src/readpassphrase.c Normal file
View File

@@ -0,0 +1,187 @@
/* $OpenBSD: readpassphrase.c,v 1.20 2007/10/30 12:03:48 millert Exp $ */
/*
* Copyright (c) 2000-2002, 2007 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 <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 <bsd/readpassphrase.h>
#ifndef TCSASOFT
#define TCSASOFT 0
#endif
static volatile sig_atomic_t signo;
static void handler(int);
char *
readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags)
{
ssize_t nr;
int input, output, save_errno;
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:
signo = 0;
nr = -1;
save_errno = 0;
/*
* Read and write to /dev/tty if available. If not, read from
* stdin and write to stderr unless a tty is required.
*/
if ((flags & RPP_STDIN) ||
(input = output = open(_PATH_TTY, O_RDWR)) == -1) {
if (flags & RPP_REQUIRE_TTY) {
errno = ENOTTY;
return(NULL);
}
input = STDIN_FILENO;
output = STDERR_FILENO;
}
/*
* 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)sigaction(SIGALRM, &sa, &savealrm);
(void)sigaction(SIGHUP, &sa, &savehup);
(void)sigaction(SIGINT, &sa, &saveint);
(void)sigaction(SIGPIPE, &sa, &savepipe);
(void)sigaction(SIGQUIT, &sa, &savequit);
(void)sigaction(SIGTERM, &sa, &saveterm);
(void)sigaction(SIGTSTP, &sa, &savetstp);
(void)sigaction(SIGTTIN, &sa, &savettin);
(void)sigaction(SIGTTOU, &sa, &savettou);
/* Turn off echo if possible. */
if (input != STDIN_FILENO && tcgetattr(input, &oterm) == 0) {
memcpy(&term, &oterm, sizeof(term));
if (!(flags & RPP_ECHO_ON))
term.c_lflag &= ~(ECHO | ECHONL);
#ifdef VSTATUS
if (term.c_cc[VSTATUS] != _POSIX_VDISABLE)
term.c_cc[VSTATUS] = _POSIX_VDISABLE;
#endif
(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;
}
/* No I/O if we are already backgrounded. */
if (signo != SIGTTOU && signo != SIGTTIN) {
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(ch)) {
if ((flags & RPP_FORCELOWER))
ch = (char)tolower(ch);
if ((flags & RPP_FORCEUPPER))
ch = (char)toupper(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)
continue;
}
(void)sigaction(SIGALRM, &savealrm, NULL);
(void)sigaction(SIGHUP, &savehup, NULL);
(void)sigaction(SIGINT, &saveint, NULL);
(void)sigaction(SIGQUIT, &savequit, NULL);
(void)sigaction(SIGPIPE, &savepipe, NULL);
(void)sigaction(SIGTERM, &saveterm, NULL);
(void)sigaction(SIGTSTP, &savetstp, NULL);
(void)sigaction(SIGTTIN, &savettin, NULL);
(void)sigaction(SIGTTOU, &savettou, NULL);
if (input != STDIN_FILENO)
(void)close(input);
/*
* If we were interrupted by a signal, resend it to ourselves
* now that we have restored the signal handlers.
*/
if (signo) {
kill(getpid(), signo);
switch (signo) {
case SIGTSTP:
case SIGTTIN:
case SIGTTOU:
goto restart;
}
}
if (save_errno)
errno = save_errno;
return(nr == -1 ? NULL : buf);
}
#if 0
char *
getpass(const char *prompt)
{
static char buf[_PASSWORD_LEN + 1];
return(readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF));
}
#endif
static void handler(int s)
{
signo = s;
}

View File

@@ -36,7 +36,8 @@
.Nm setmode
.Nd modify mode bits
.Sh LIBRARY
.Lb libc
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In unistd.h
.Ft mode_t

33
src/setproctitle.c Normal file
View File

@@ -0,0 +1,33 @@
/*
* Copyright © 2010 Guillem Jover
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce 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.
*/
void
setproctitle(const char *fmt, ...)
{
/* Stub so that we can implement it later on and programs will
* automatically benefit from it, w/o needing to recompile. */
}

View File

@@ -1,37 +1,21 @@
/* $OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $ */
/* $OpenBSD: strlcat.c,v 1.12 2005/03/30 20:13:52 otto Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.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.
* 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.
*
* 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.
* 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
#include <sys/types.h>
#include <string.h>
@@ -43,10 +27,7 @@ static char *rcsid = "$OpenBSD: strlcat.c,v 1.2 1999/06/17 16:28:58 millert Exp
* If retval >= siz, truncation occurred.
*/
size_t
strlcat(dst, src, siz)
char *dst;
const char *src;
size_t siz;
strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;

View File

@@ -1,33 +1,20 @@
.\" $OpenBSD: strlcpy.3,v 1.5 1999/06/06 15:17:32 aaron Exp $
.\" $OpenBSD: strlcpy.3,v 1.18 2005/08/06 03:24:19 jaredy Exp $
.\"
.\" Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
.\" All rights reserved.
.\" Copyright (c) 1998, 2000 Todd C. Miller <Todd.Miller@courtesan.com>
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce 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.
.\" 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.
.\"
.\" 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.
.\" 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.
.\"
.\" $FreeBSD: /repoman/r/ncvs/src/lib/libc/string/strlcpy.3,v 1.13 2004/07/02 23:52:13 ru Exp $
.\"
.Dd June 22, 1998
.Dd $Mdocdate: May 31 2007 $
.Dt STRLCPY 3
.Os
.Sh NAME
@@ -35,7 +22,8 @@
.Nm strlcat
.Nd size-bounded string copying and concatenation
.Sh LIBRARY
.Lb libc
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In string.h
.Ft size_t
@@ -64,7 +52,7 @@ is larger than 0 or, in the case of
.Fn strlcat ,
as long as there is at least one byte free in
.Fa dst ) .
Note that you should include a byte for the NUL in
Note that a byte for the NUL should be included in
.Fa size .
Also note that
.Fn strlcpy
@@ -108,8 +96,7 @@ The
.Fn strlcpy
and
.Fn strlcat
functions return the total length of the string they tried to
create.
functions return the total length of the string they tried to create.
For
.Fn strlcpy
that means the length of
@@ -121,10 +108,10 @@ that means the initial length of
plus
the length of
.Fa src .
While this may seem somewhat confusing it was done to make
While this may seem somewhat confusing, it was done to make
truncation detection simple.
.Pp
Note however, that if
Note, however, that if
.Fn strlcat
traverses
.Fa size
@@ -168,8 +155,8 @@ if (strlcat(pname, file, sizeof(pname)) >= sizeof(pname))
goto toolong;
.Ed
.Pp
Since we know how many characters we copied the first time, we can
speed things up a bit by using a copy instead of an append:
Since it is known how many characters were copied the first time, things
can be sped up a bit by using a copy instead of an append:
.Bd -literal -offset indent
char *dir, *file, pname[MAXPATHLEN];
size_t n;

View File

@@ -1,37 +1,21 @@
/* $OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $ */
/* $OpenBSD: strlcpy.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
/*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.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.
* 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.
*
* 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.
* 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.
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
#include <sys/types.h>
#include <string.h>
@@ -40,21 +24,19 @@ static char *rcsid = "$OpenBSD: strlcpy.c,v 1.4 1999/05/01 18:56:41 millert Exp
* will be copied. Always NUL terminates (unless siz == 0).
* Returns strlen(src); if retval >= siz, truncation occurred.
*/
size_t strlcpy(dst, src, siz)
char *dst;
const char *src;
size_t siz;
size_t
strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
if (n != 0) {
while (--n != 0) {
if ((*d++ = *s++) == '\0')
break;
} while (--n != 0);
}
}
/* Not enough room in dst, add NUL and traverse rest of src */

View File

@@ -35,7 +35,8 @@
.Nm strmode
.Nd convert inode status information into a symbolic string
.Sh LIBRARY
.Lb libc
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In string.h
.Ft void

159
src/strtonum.3 Normal file
View File

@@ -0,0 +1,159 @@
.\" Copyright (c) 2004 Ted Unangst
.\"
.\" 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.3,v 1.12 2005/10/26 11:37:58 jmc Exp $
.\" $FreeBSD$
.\"
.Dd April 29, 2004
.Dt STRTONUM 3
.Os
.Sh NAME
.Nm strtonum
.Nd "reliably convert string value to an integer"
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In stdlib.h
.In limits.h
.Ft long long
.Fo strtonum
.Fa "const char *nptr"
.Fa "long long minval"
.Fa "long long maxval"
.Fa "const char **errstr"
.Fc
.Sh DESCRIPTION
The
.Fn strtonum
function converts the string in
.Fa nptr
to a
.Vt "long long"
value.
The
.Fn strtonum
function was designed to facilitate safe, robust programming
and overcome the shortcomings of the
.Xr atoi 3
and
.Xr strtol 3
family of interfaces.
.Pp
The string may begin with an arbitrary amount of whitespace
(as determined by
.Xr isspace 3 )
followed by a single optional
.Ql +
or
.Ql -
sign.
.Pp
The remainder of the string is converted to a
.Vt "long long"
value according to base 10.
.Pp
The value obtained is then checked against the provided
.Fa minval
and
.Fa maxval
bounds.
If
.Fa errstr
is non-null,
.Fn strtonum
stores an error string in
.Fa *errstr
indicating the failure.
.Sh RETURN VALUES
The
.Fn strtonum
function returns the result of the conversion,
unless the value would exceed the provided bounds or is invalid.
On error, 0 is returned,
.Va errno
is set, and
.Fa errstr
will point to an error message.
On success,
.Fa *errstr
will be set to
.Dv NULL ;
this fact can be used to differentiate
a successful return of 0 from an error.
.Sh EXAMPLES
Using
.Fn strtonum
correctly is meant to be simpler than the alternative functions.
.Bd -literal -offset indent
int iterations;
const char *errstr;
iterations = strtonum(optarg, 1, 64, &errstr);
if (errstr)
errx(1, "number of iterations is %s: %s", errstr, optarg);
.Ed
.Pp
The above example will guarantee that the value of iterations is between
1 and 64 (inclusive).
.Sh ERRORS
.Bl -tag -width Er
.It Bq Er ERANGE
The given string was out of range.
.It Bq Er EINVAL
The given string did not consist solely of digit characters.
.It Bq Er EINVAL
The supplied
.Fa minval
was larger than
.Fa maxval .
.El
.Pp
If an error occurs,
.Fa errstr
will be set to one of the following strings:
.Pp
.Bl -tag -width ".Li too large" -compact
.It Li "too large"
The result was larger than the provided maximum value.
.It Li "too small"
The result was smaller than the provided minimum value.
.It Li invalid
The string did not consist solely of digit characters.
.El
.Sh SEE ALSO
.Xr atof 3 ,
.Xr atoi 3 ,
.Xr atol 3 ,
.Xr atoll 3 ,
.Xr sscanf 3 ,
.Xr strtod 3 ,
.Xr strtol 3 ,
.Xr strtoul 3
.Sh STANDARDS
The
.Fn strtonum
function is a
.Bx
extension.
The existing alternatives, such as
.Xr atoi 3
and
.Xr strtol 3 ,
are either impossible or difficult to use safely.
.Sh HISTORY
The
.Fn strtonum
function first appeared in
.Ox 3.6 .

68
src/strtonum.c Normal file
View File

@@ -0,0 +1,68 @@
/*-
* 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.6 2004/08/03 19:38:01 millert Exp $
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#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;
char *ep;
int error = 0;
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);
}

198
src/unvis.3 Normal file
View File

@@ -0,0 +1,198 @@
.\" $OpenBSD: unvis.3,v 1.15 2005/07/22 03:16:58 jaredy Exp $
.\"
.\" Copyright (c) 1989, 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.
.\"
.Dd $Mdocdate: May 31 2007 $
.Dt UNVIS 3
.Os
.Sh NAME
.Nm unvis ,
.Nm strunvis ,
.Nm strnunvis
.Nd decode a visual representation of characters
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In vis.h
.Ft int
.Fn unvis "char *cp" "char c" "int *astate" "int flag"
.Ft int
.Fn strunvis "char *dst" "char *src"
.Ft ssize_t
.Fn strnunvis "char *dst" "char *src" "size_t size"
.Sh DESCRIPTION
The
.Fn unvis ,
.Fn strunvis
and
.Fn strnunvis
functions are used to decode a visual representation of characters,
as produced by the
.Xr vis 3
function, back into the original form.
.Fn unvis
is called with successive characters in
.Fa c
until a valid
sequence is recognized, at which time the decoded character is
available at the character pointed to by
.Fa cp .
.Pp
.Fn strunvis
decodes the characters pointed to by
.Fa src
into the buffer pointed to by
.Fa dst .
.Pp
.Fn strnunvis
decodes the characters pointed to by
.Fa src
into the buffer pointed to by
.Fa dst ,
writing a maximum of
.Fa size
bytes.
The
.Fn strunvis
function simply copies
.Fa src
to
.Fa dst ,
decoding any escape sequences along the way,
and returns the number of characters placed into
.Fa dst ,
or \-1 if an
invalid escape sequence was detected.
The size of
.Fa dst
should be
equal to the size of
.Fa src
(that is, no expansion takes place during decoding).
.Fn strunvis
terminates the destination string with a trailing NUL byte;
.Fn strnunvis
does so if
.Fa size
is larger than 0.
.Pp
The
.Fn unvis
function implements a state machine that can be used to decode an arbitrary
stream of bytes.
All state associated with the bytes being decoded is stored outside the
.Fn unvis
function (that is, a pointer to the state is passed in), so
calls decoding different streams can be freely intermixed.
To start decoding a stream of bytes, first initialize an integer
to zero.
Call
.Fn unvis
with each successive byte, along with a pointer
to this integer, and a pointer to a destination character.
.Sh RETURN VALUES
The
.Fn unvis
function has several return codes that must be handled properly.
They are:
.Bl -tag -width UNVIS_VALIDPUSH
.It Li \&0 (zero)
Another character is necessary; nothing has been recognized yet.
.It Dv UNVIS_VALID
A valid character has been recognized and is available at the location
pointed to by
.Fa cp .
.It Dv UNVIS_VALIDPUSH
A valid character has been recognized and is available at the location
pointed to by
.Fa cp ;
however, the character currently passed in should be passed in again.
.It Dv UNVIS_NOCHAR
A valid sequence was detected, but no character was produced.
This return code is necessary to indicate a logical break between characters.
.It Dv UNVIS_SYNBAD
An invalid escape sequence was detected, or the decoder is in an
unknown state.
The decoder is placed into the starting state.
.El
.Pp
When all bytes in the stream have been processed, call
.Fn unvis
one more time with
.Fa flag
set to
.Dv UNVIS_END
to extract any remaining character (the character passed in is ignored).
.Pp
The
.Fn strunvis
function returns the number of bytes written (not counting
the trailing NUL byte) or \-1 if an error occurred.
.Pp
The
.Fn strnunvis
function returns the number of bytes (not counting the trailing NUL byte)
that would be needed to fully convert the input string, or \-1 if an
error occurred.
.Sh EXAMPLES
The following code fragment illustrates a proper use of
.Fn unvis .
.Bd -literal -offset indent
int state = 0;
char out;
while ((ch = getchar()) != EOF) {
again:
switch(unvis(&out, ch, &state, 0)) {
case 0:
case UNVIS_NOCHAR:
break;
case UNVIS_VALID:
(void) putchar(out);
break;
case UNVIS_VALIDPUSH:
(void) putchar(out);
goto again;
case UNVIS_SYNBAD:
(void)fprintf(stderr, "bad sequence!\en");
exit(1);
}
}
if (unvis(&out, (char)0, &state, UNVIS_END) == UNVIS_VALID)
(void) putchar(out);
.Ed
.Sh SEE ALSO
.Xr unvis 1 ,
.Xr vis 1 ,
.Xr vis 3
.Sh HISTORY
The
.Fn unvis
function first appeared in
.Bx 4.4 .

View File

@@ -235,7 +235,7 @@ strunvis(char *dst, const char *src)
char *start = dst;
int state = 0;
while ( (c = *src++) ) {
while ((c = *src++)) {
again:
switch (unvis(dst, c, &state, 0)) {
case UNVIS_VALID:
@@ -248,6 +248,7 @@ strunvis(char *dst, const char *src)
case UNVIS_NOCHAR:
break;
default:
*dst = '\0';
return (-1);
}
}
@@ -257,14 +258,55 @@ strunvis(char *dst, const char *src)
return (dst - start);
}
ssize_t
strnunvis(char *dst, const char *src, size_t sz)
{
char c, p;
char *start = dst, *end = dst + sz - 1;
int state = 0;
if (sz > 0)
*end = '\0';
while ((c = *src++)) {
again:
switch (unvis(&p, c, &state, 0)) {
case UNVIS_VALID:
if (dst < end)
*dst = p;
dst++;
break;
case UNVIS_VALIDPUSH:
if (dst < end)
*dst = p;
dst++;
goto again;
case 0:
case UNVIS_NOCHAR:
break;
default:
if (dst <= end)
*dst = '\0';
return (-1);
}
}
if (unvis(&p, c, &state, UNVIS_END) == UNVIS_VALID) {
if (dst < end)
*dst = p;
dst++;
}
if (dst <= end)
*dst = '\0';
return (dst - start);
}
int
strunvisx(char *dst, const char *src, int flag)
{
char c;
char *start = dst;
int state = 0;
while ( (c = *src++) ) {
while ((c = *src++)) {
again:
switch (unvis(dst, c, &state, flag)) {
case UNVIS_VALID:

321
src/vis.3 Normal file
View File

@@ -0,0 +1,321 @@
.\" $OpenBSD: vis.3,v 1.23 2005/08/28 19:51:27 millert Exp $
.\"
.\" Copyright (c) 1989, 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.
.\"
.Dd $Mdocdate: May 31 2007 $
.Dt VIS 3
.Os
.Sh NAME
.Nm vis ,
.Nm strvis ,
.Nm strnvis ,
.Nm strvisx
.Nd visually encode characters
.Sh LIBRARY
.ds str-Lb-libbsd Utility functions from BSD systems (libbsd, \-lbsd)
.Lb libbsd
.Sh SYNOPSIS
.In stdlib.h
.In vis.h
.Ft char *
.Fn vis "char *dst" "int c" "int flag" "int nextc"
.Ft int
.Fn strvis "char *dst" "const char *src" "int flag"
.Ft int
.Fn strnvis "char *dst" "const char *src" "size_t size" "int flag"
.Ft int
.Fn strvisx "char *dst" "const char *src" "size_t len" "int flag"
.Sh DESCRIPTION
The
.Fn vis
function copies into
.Fa dst
a string which represents the character
.Fa c .
If
.Fa c
needs no encoding, it is copied in unaltered.
The string is NUL terminated and a pointer to the end of the string is
returned.
The maximum length of any encoding is four
characters (not including the trailing NUL);
thus, when
encoding a set of characters into a buffer, the size of the buffer should
be four times the number of characters encoded, plus one for the trailing
NUL.
The
.Fa flag
parameter is used for altering the default range of
characters considered for encoding and for altering the visual
representation.
The additional character,
.Fa nextc ,
is only used when selecting the
.Dv VIS_CSTYLE
encoding format (explained below).
.Pp
The
.Fn strvis ,
.Fn strnvis
and
.Fn strvisx
functions copy into
.Fa dst
a visual representation of
the string
.Fa src .
The
.Fn strvis
function encodes characters from
.Fa src
up to the first NUL.
The
.Fn strnvis
function encodes characters from
.Fa src
up to the first NUL or the end of
.Fa dst ,
as indicated by
.Fa size .
The
.Fn strvisx
function encodes exactly
.Fa len
characters from
.Fa src
(this
is useful for encoding a block of data that may contain NULs).
All three forms NUL terminate
.Fa dst ,
except for
.Fn strnvis
when
.Fa size
is zero, in which case
.Fa dst
is not touched.
For
.Fn strvis
and
.Fn strvisx ,
the size of
.Fa dst
must be four times the number
of characters encoded from
.Fa src
(plus one for the NUL).
.Fn strvis
and
.Fn strvisx
return the number of characters in
.Fa dst
(not including the trailing NUL).
.Fn strnvis
returns the length that
.Fa dst
would become if it were of unlimited size (similar to
.Xr snprintf 3
or
.Xr strlcpy 3 ) .
This can be used to detect truncation but it also means that
the return value of
.Fn strnvis
must not be used without checking it against
.Fa size .
.Pp
The encoding is a unique, invertible representation composed entirely of
graphic characters; it can be decoded back into the original form using
the
.Xr unvis 3
or
.Xr strunvis 3
functions.
.Pp
There are two parameters that can be controlled: the range of
characters that are encoded, and the type
of representation used.
By default, all non-graphic characters
except space, tab, and newline are encoded
(see
.Xr isgraph 3 ) .
The following flags
alter this:
.Bl -tag -width VIS_WHITEX
.It Dv VIS_GLOB
Also encode magic characters recognized by
.Xr glob 3
.Pf ( Ql * ,
.Ql \&? ,
.Ql \&[ )
and
.Ql # .
.It Dv VIS_SP
Also encode space.
.It Dv VIS_TAB
Also encode tab.
.It Dv VIS_NL
Also encode newline.
.It Dv VIS_WHITE
Synonym for
.Dv VIS_SP
\&|
.Dv VIS_TAB
\&|
.Dv VIS_NL .
.It Dv VIS_SAFE
Only encode
.Dq unsafe
characters.
These are control characters which may cause common terminals to perform
unexpected functions.
Currently this form allows space,
tab, newline, backspace, bell, and return -- in addition
to all graphic characters -- unencoded.
.El
.Pp
There are three forms of encoding.
All forms use the backslash
.Ql \e
character to introduce a special
sequence; two backslashes are used to represent a real backslash.
These are the visual formats:
.Bl -tag -width VIS_CSTYLE
.It (default)
Use an
.Ql M
to represent meta characters (characters with the 8th
bit set), and use a caret
.Ql ^
to represent control characters (see
.Xr iscntrl 3 ) .
The following formats are used:
.Bl -tag -width xxxxx
.It Dv \e^C
Represents the control character
.Ql C .
Spans characters
.Ql \e000
through
.Ql \e037 ,
and
.Ql \e177
(as
.Ql \e^? ) .
.It Dv \eM-C
Represents character
.Ql C
with the 8th bit set.
Spans characters
.Ql \e241
through
.Ql \e376 .
.It Dv \eM^C
Represents control character
.Ql C
with the 8th bit set.
Spans characters
.Ql \e200
through
.Ql \e237 ,
and
.Ql \e377
(as
.Ql \eM^? ) .
.It Dv \e040
Represents
.Tn ASCII
space.
.It Dv \e240
Represents Meta-space.
.El
.Pp
.It Dv VIS_CSTYLE
Use C-style backslash sequences to represent standard non-printable
characters.
The following sequences are used to represent the indicated characters:
.Bd -unfilled -offset indent
.Li \ea Tn - BEL No (007)
.Li \eb Tn - BS No (010)
.Li \ef Tn - NP No (014)
.Li \en Tn - NL No (012)
.Li \er Tn - CR No (015)
.Li \es Tn - SP No (040)
.Li \et Tn - HT No (011)
.Li \ev Tn - VT No (013)
.Li \e0 Tn - NUL No (000)
.Ed
.Pp
When using this format, the
.Fa nextc
parameter is looked at to determine
if a NUL character can be encoded as
.Ql \e0
instead of
.Ql \e000 .
If
.Fa nextc
is an octal digit, the latter representation is used to
avoid ambiguity.
.It Dv VIS_OCTAL
Use a three digit octal sequence.
The form is
.Ql \eddd
where
.Ar d
represents an octal digit.
.El
.Pp
There is one additional flag,
.Dv VIS_NOSLASH ,
which inhibits the
doubling of backslashes and the backslash before the default
format (that is, control characters are represented by
.Ql ^C
and
meta characters as
.Ql M-C ) .
With this flag set, the encoding is
ambiguous and non-invertible.
.Sh SEE ALSO
.Xr unvis 1 ,
.Xr vis 1 ,
.Xr snprintf 3 ,
.Xr strlcpy 3 ,
.Xr unvis 3
.Sh HISTORY
The
.Fn vis ,
.Fn strvis
and
.Fn strvisx
functions first appeared in
.Bx 4.4 .
The
.Fn strnvis
function first appeared in
.Ox 2.9 .

View File

@@ -1,3 +1,4 @@
/* $OpenBSD: vis.c,v 1.18 2005/08/29 18:38:41 otto Exp $ */
/*-
* Copyright (c) 1989, 1993
* The Regents of the University of California. All rights reserved.
@@ -30,19 +31,26 @@
#include <sys/types.h>
#include <limits.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <vis.h>
#define isoctal(c) (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
#define isvisible(c) \
(((u_int)(c) <= UCHAR_MAX && isascii((u_char)(c)) && \
(((c) != '*' && (c) != '?' && (c) != '[' && (c) != '#') || \
(flag & VIS_GLOB) == 0) && isgraph((u_char)(c))) || \
((flag & VIS_SP) == 0 && (c) == ' ') || \
((flag & VIS_TAB) == 0 && (c) == '\t') || \
((flag & VIS_NL) == 0 && (c) == '\n') || \
((flag & VIS_SAFE) && ((c) == '\b' || \
(c) == '\007' || (c) == '\r' || \
isgraph((u_char)(c)))))
/*
* vis - visually encode characters
*/
char *
vis(dst, c, flag, nextc)
char *dst;
int c, nextc;
int flag;
vis(char *dst, int c, int flag, int nextc)
{
c = (unsigned char)c;
@@ -149,20 +157,20 @@ done:
}
/*
* strvis, strvisx - visually encode characters from src into dst
* strvis, strnvis, strvisx - visually encode characters from src into dst
*
* Dst must be 4 times the size of src to account for possible
* expansion. The length of dst, not including the trailing NUL,
* is returned.
*
* Strnvis will write no more than siz-1 bytes (and will NULL terminate).
* The number of bytes needed to fully encode the string is returned.
*
* Strvisx encodes exactly len bytes from src into dst.
* This is useful for encoding a block of data.
*/
int
strvis(dst, src, flag)
char *dst;
const char *src;
int flag;
strvis(char *dst, const char *src, int flag)
{
char c;
char *start;
@@ -174,11 +182,51 @@ strvis(dst, src, flag)
}
int
strvisx(dst, src, len, flag)
char *dst;
const char *src;
size_t len;
int flag;
strnvis(char *dst, const char *src, size_t siz, int flag)
{
char *start, *end;
char tbuf[5];
int c, i;
i = 0;
for (start = dst, end = start + siz - 1; (c = *src) && dst < end; ) {
if (isvisible(c)) {
i = 1;
*dst++ = c;
if (c == '\\' && (flag & VIS_NOSLASH) == 0) {
/* need space for the extra '\\' */
if (dst < end)
*dst++ = '\\';
else {
dst--;
i = 2;
break;
}
}
src++;
} else {
i = vis(tbuf, c, flag, *++src) - tbuf;
if (dst + i <= end) {
memcpy(dst, tbuf, i);
dst += i;
} else {
src--;
break;
}
}
}
if (siz > 0)
*dst = '\0';
if (dst + i > end) {
/* adjust return value for truncation */
while ((c = *src))
dst += vis(tbuf, c, flag, *++src) - tbuf;
}
return (dst - start);
}
int
strvisx(char *dst, const char *src, size_t len, int flag)
{
int c;
char *start;