summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJennifer Averett <jennifer.averett@oarcorp.com>2012-10-23 14:16:33 -0500
committerJennifer Averett <jennifer.averett@oarcorp.com>2012-10-23 14:16:33 -0500
commitd422d0df649bd601aa1b841cb25cac4188091aa5 (patch)
tree6ddc4ac88432fd954d544b7de0bee5c12705c860
parentnetstat: Added exit funtionality. (diff)
parentroute: Add macros to assist use of getopt_r() (diff)
downloadrtems-libbsd-d422d0df649bd601aa1b841cb25cac4188091aa5.tar.bz2
Merge branch 'master' of ssh://git.rtems.org/data/git/rtems-libbsd
-rw-r--r--.gitignore1
-rw-r--r--freebsd-userspace/Makefile105
-rw-r--r--freebsd-userspace/commands/sbin/route/route.c4
-rw-r--r--freebsd-userspace/lib/libc/net/gethostbydns.c6
-rw-r--r--freebsd-userspace/lib/libc/net/gethostbyht.c13
-rw-r--r--freebsd-userspace/lib/libc/net/gethostnamadr.c4
-rw-r--r--freebsd-userspace/lib/libc/stdlib/strtonum.3155
-rw-r--r--freebsd-userspace/lib/libc/stdlib/strtonum.c68
8 files changed, 319 insertions, 37 deletions
diff --git a/.gitignore b/.gitignore
index ec291bc1..f4295e39 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,5 @@
*.d
+*.rel
o-optimize
copied
libbsd.html
diff --git a/freebsd-userspace/Makefile b/freebsd-userspace/Makefile
index c763bc8b..554ca649 100644
--- a/freebsd-userspace/Makefile
+++ b/freebsd-userspace/Makefile
@@ -82,7 +82,10 @@ C_FILES += lib/libc/net/if_indextoname.c
C_FILES += lib/libc/net/if_nameindex.c
C_FILES += lib/libc/net/if_nametoindex.c
C_FILES += lib/libc/net/linkaddr.c
+ifneq ($(DISABLE_IPV6),yes)
C_FILES += lib/libc/net/map_v4v6.c
+endif
+# This file is not IPV6 specific
C_FILES += lib/libc/net/name6.c
C_FILES += lib/libc/net/rcmd.c
C_FILES += lib/libc/net/recv.c
@@ -102,6 +105,7 @@ C_FILES += lib/libc/resolv/res_state.c
C_FILES += lib/libc/resolv/res_update.c
C_FILES += lib/libc/resolv/mtctxres.c
C_FILES += lib/libc/string/strsep.c
+C_FILES += lib/libc/stdlib/strtonum.c
C_FILES += lib/libc/isc/ev_streams.c
C_FILES += lib/libc/isc/ev_timers.c
@@ -168,7 +172,9 @@ C_FILES += rtems/rtems-shell.c
# ping command sources
C_FILES += commands/sbin/ping/ping.c
+ifneq ($(DISABLE_IPV6),yes)
C_FILES += commands/sbin/ping6/ping6.c
+endif
# route command sources
C_FILES += commands/sbin/route/route.c
@@ -192,24 +198,26 @@ C_FILES += commands/sbin/dhclient/tables.c
C_FILES += commands/sbin/dhclient/tree.c
# ifconfig command sources
-C_FILES += commands/sbin/ifconfig/af_atalk.c
-C_FILES += commands/sbin/ifconfig/af_inet.c
-C_FILES += commands/sbin/ifconfig/af_link.c
-C_FILES += commands/sbin/ifconfig/ifbridge.c
-C_FILES += commands/sbin/ifconfig/ifclone.c
-C_FILES += commands/sbin/ifconfig/ifgif.c
-C_FILES += commands/sbin/ifconfig/ifgroup.c
-C_FILES += commands/sbin/ifconfig/iflagg.c
-C_FILES += commands/sbin/ifconfig/ifmedia.c
-C_FILES += commands/sbin/ifconfig/ifvlan.c
-C_FILES += commands/sbin/ifconfig/af_inet6.c
-C_FILES += commands/sbin/ifconfig/af_nd6.c
-C_FILES += commands/sbin/ifconfig/ifcarp.c
-C_FILES += commands/sbin/ifconfig/ifconfig.c
-C_FILES += commands/sbin/ifconfig/ifgre.c
-C_FILES += commands/sbin/ifconfig/ifieee80211.c
-C_FILES += commands/sbin/ifconfig/ifmac.c
-C_FILES += commands/sbin/ifconfig/ifpfsync.c
+# UNUSED IFCONFIG_C_FILES += commands/sbin/ifconfig/af_atalk.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/af_inet.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/af_link.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifbridge.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifclone.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifgif.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifgroup.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/iflagg.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifmedia.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifvlan.c
+ifneq ($(DISABLE_IPV6),yes)
+IFCONFIG_C_FILES += commands/sbin/ifconfig/af_inet6.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/af_nd6.c
+endif
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifcarp.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifconfig.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifgre.c
+# UNUSED IFCONFIG_C_FILES += commands/sbin/ifconfig/ifieee80211.c
+# UNUSED IFCONFIG_C_FILES += commands/sbin/ifconfig/ifmac.c
+IFCONFIG_C_FILES += commands/sbin/ifconfig/ifpfsync.c
# The following two files were left out to avoid
# porting issues. regdomain uses an xml parser
@@ -222,31 +230,46 @@ C_FILES += commands/sbin/ifconfig/ifpfsync.c
# netstat command sources
# no need to support AppleTalk yet
-# C_FILES += commands/usr.bin/netstat/atalk.c
-C_FILES += commands/usr.bin/netstat/bpf.c
-C_FILES += commands/usr.bin/netstat/if.c
-C_FILES += commands/usr.bin/netstat/inet6.c
-C_FILES += commands/usr.bin/netstat/inet.c
-C_FILES += commands/usr.bin/netstat/ipsec.c
+# NETSTAT_C_FILES += commands/usr.bin/netstat/atalk.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/bpf.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/if.c
+ifneq ($(DISABLE_IPV6),yes)
+NETSTAT_C_FILES += commands/usr.bin/netstat/inet6.c
+endif
+NETSTAT_C_FILES += commands/usr.bin/netstat/inet.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/ipsec.c
# no need to support IPX yet
-# C_FILES += commands/usr.bin/netstat/ipx.c
-C_FILES += commands/usr.bin/netstat/main.c
+# NETSTAT_C_FILES += commands/usr.bin/netstat/ipx.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/main.c
# XXX does not compile yet
-C_FILES += commands/usr.bin/netstat/mbuf.c
-C_FILES += commands/usr.bin/netstat/mroute6.c
-C_FILES += commands/usr.bin/netstat/mroute.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/mbuf.c
+ifneq ($(DISABLE_IPV6),yes)
+NETSTAT_C_FILES += commands/usr.bin/netstat/mroute6.c
+endif
+NETSTAT_C_FILES += commands/usr.bin/netstat/mroute.c
# Disable netgraph support - this is a long thread to pull
-# C_FILES += commands/usr.bin/netstat/netgraph.c
-C_FILES += commands/usr.bin/netstat/pfkey.c
+# NETSTAT_C_FILES += commands/usr.bin/netstat/netgraph.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/pfkey.c
# Actually just route.c in FreeBSD
-C_FILES += commands/usr.bin/netstat/netstat_route.c
-C_FILES += commands/usr.bin/netstat/sctp.c
-C_FILES += commands/usr.bin/netstat/unix.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/netstat_route.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/sctp.c
+NETSTAT_C_FILES += commands/usr.bin/netstat/unix.c
C_O_FILES = $(C_FILES:%.c=%.o)
C_D_FILES = $(C_FILES:%.c=%.d)
+IFCONFIG_C_O_FILES = $(IFCONFIG_C_FILES:%.c=%.o)
+IFCONFIG_C_D_FILES = $(IFCONFIG_C_FILES:%.c=%.d)
+
+NETSTAT_C_O_FILES = $(NETSTAT_C_FILES:%.c=%.o)
+NETSTAT_C_D_FILES = $(NETSTAT_C_FILES:%.c=%.d)
+
LIB = libbsdc.a
+IFCONFIG = commands/sbin/ifconfig/ifconfig.rel
+NETSTAT = commands/usr.bin/netstat/netstat.rel
+
+COMMAND_RELS = $(NETSTAT) $(IFCONFIG)
+
GEN_FILES = include/rpc/rpcb_prot.h
GEN_FILES += commands/sbin/route/keywords.h
# lib/libc/net
@@ -261,11 +284,17 @@ GEN_FILES += lib/libipsec/policy_parse.c
EXTRA_CLEAN += lib/libipsec/policy_parse.i
EXTRA_CLEAN += lib/libipsec/y.tab.h
-all: $(LIB)
+all: $(LIB)
-$(LIB): $(GEN_FILES) $(C_O_FILES)
+$(LIB): $(GEN_FILES) $(C_O_FILES) $(COMMAND_RELS)
$(AR) rcu $@ $^
+$(IFCONFIG): $(IFCONFIG_C_O_FILES)
+ $(LD) -r -o $@ $^
+
+$(NETSTAT): $(NETSTAT_C_O_FILES)
+ $(LD) -r -o $@ $^
+
include/rpc/rpcb_prot.h: include/rpc/rpcb_prot.x
rm -f include/rpc/rpcb_prot.h
rpcgen -h -o include/rpc/rpcb_prot.h include/rpc/rpcb_prot.x
@@ -307,7 +336,9 @@ install: $(LIB)
install -c -m 644 $(LIB) $(INSTALL_BASE)
clean:
- rm -f $(LIB) $(C_O_FILES) $(C_D_FILES) $(GEN_FILES) $(CLEAN_FILES)
+ rm -f $(LIB) $(GEN_FILES) $(CLEAN_FILES)
+ rm -f $(C_O_FILES) $(IFCONFIG_C_O_FILES) $(NETSTAT_C_O_FILES)
+ rm -f $(C_D_FILES) $(IFCONFIG_C_D_FILES) $(NETSTAT_C_D_FILES)
-include $(C_D_FILES)
diff --git a/freebsd-userspace/commands/sbin/route/route.c b/freebsd-userspace/commands/sbin/route/route.c
index 8099d4c4..c0f2d50a 100644
--- a/freebsd-userspace/commands/sbin/route/route.c
+++ b/freebsd-userspace/commands/sbin/route/route.c
@@ -167,6 +167,10 @@ main(argc, argv)
int ch;
#ifdef __rtems__
struct getopt_data getopt_reent;
+#define optind getopt_reent.optind
+#define optarg getopt_reent.optarg
+#define opterr getopt_reent.opterr
+#define optopt getopt_reent.optopt
#endif
if (argc < 2)
diff --git a/freebsd-userspace/lib/libc/net/gethostbydns.c b/freebsd-userspace/lib/libc/net/gethostbydns.c
index fa22fedd..2993a678 100644
--- a/freebsd-userspace/lib/libc/net/gethostbydns.c
+++ b/freebsd-userspace/lib/libc/net/gethostbydns.c
@@ -340,6 +340,7 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
break;
#else
he->h_name = bp;
+#ifdef INET6
if (statp->options & RES_USE_INET6) {
n = strlen(bp) + 1; /* for the \0 */
if (n >= MAXHOSTNAMELEN) {
@@ -349,6 +350,7 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
bp += n;
_map_v4v6_hostent(he, &bp, ep);
}
+#endif
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
return (0);
#endif
@@ -424,8 +426,10 @@ gethostanswer(const querybuf *answer, int anslen, const char *qname, int qtype,
he->h_name = bp;
bp += n;
}
+#ifdef INET6
if (statp->options & RES_USE_INET6)
_map_v4v6_hostent(he, &bp, ep);
+#endif
RES_SET_H_ERRNO(statp, NETDB_SUCCESS);
return (0);
}
@@ -699,11 +703,13 @@ _dns_gethostbyaddr(void *rval, void *cb_data, va_list ap)
memcpy(hed->host_addr, uaddr, len);
hed->h_addr_ptrs[0] = (char *)hed->host_addr;
hed->h_addr_ptrs[1] = NULL;
+#ifdef INET6
if (af == AF_INET && (statp->options & RES_USE_INET6)) {
_map_v4v6_address((char*)hed->host_addr, (char*)hed->host_addr);
he.h_addrtype = AF_INET6;
he.h_length = NS_IN6ADDRSZ;
}
+#endif
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
*errnop = errno;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
diff --git a/freebsd-userspace/lib/libc/net/gethostbyht.c b/freebsd-userspace/lib/libc/net/gethostbyht.c
index cb88cf9d..eb995b96 100644
--- a/freebsd-userspace/lib/libc/net/gethostbyht.c
+++ b/freebsd-userspace/lib/libc/net/gethostbyht.c
@@ -115,6 +115,7 @@ gethostent_p(struct hostent *he, struct hostent_data *hed, int mapped,
if (!(cp = strpbrk(p, " \t")))
goto again;
*cp++ = '\0';
+#ifdef INET6
if (inet_pton(AF_INET6, p, hed->host_addr) > 0) {
af = AF_INET6;
len = IN6ADDRSZ;
@@ -131,6 +132,12 @@ gethostent_p(struct hostent *he, struct hostent_data *hed, int mapped,
} else {
goto again;
}
+#else
+ if (inet_pton(AF_INET, p, hed->host_addr) > 0) {
+ af = AF_INET;
+ len = INADDRSZ;
+ }
+#endif
hed->h_addr_ptrs[0] = (char *)hed->host_addr;
hed->h_addr_ptrs[1] = NULL;
he->h_addr_list = hed->h_addr_ptrs;
@@ -193,8 +200,10 @@ gethostent_r(struct hostent *hptr, char *buffer, size_t buflen,
*h_errnop = statp->res_h_errno;
return (-1);
}
+#ifdef INET6
if (gethostent_p(&he, hed, statp->options & RES_USE_INET6, statp) != 0)
return (-1);
+#endif
if (__copy_hostent(&he, hptr, buffer, buflen) != 0) {
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
*h_errnop = statp->res_h_errno;
@@ -254,12 +263,14 @@ _ht_gethostbyname(void *rval, void *cb_data, va_list ap)
while ((error = gethostent_p(&he, hed, 0, statp)) == 0) {
if (he.h_addrtype != af)
continue;
+#ifdef INET6
if (he.h_addrtype == AF_INET &&
statp->options & RES_USE_INET6) {
_map_v4v6_address(he.h_addr, he.h_addr);
he.h_length = IN6ADDRSZ;
he.h_addrtype = AF_INET6;
}
+#endif
if (strcasecmp(he.h_name, name) == 0)
break;
for (cp = he.h_aliases; *cp != 0; cp++)
@@ -317,6 +328,7 @@ _ht_gethostbyaddr(void *rval, void *cb_data, va_list ap)
_sethosthtent(0, hed);
while ((error = gethostent_p(&he, hed, 0, statp)) == 0)
+#ifdef INET6
if (he.h_addrtype == af && !bcmp(he.h_addr, addr, len)) {
if (he.h_addrtype == AF_INET &&
statp->options & RES_USE_INET6) {
@@ -326,6 +338,7 @@ _ht_gethostbyaddr(void *rval, void *cb_data, va_list ap)
}
break;
}
+#endif
_endhosthtent(hed);
if (error != 0)
diff --git a/freebsd-userspace/lib/libc/net/gethostnamadr.c b/freebsd-userspace/lib/libc/net/gethostnamadr.c
index d5aaa38b..d663e286 100644
--- a/freebsd-userspace/lib/libc/net/gethostnamadr.c
+++ b/freebsd-userspace/lib/libc/net/gethostnamadr.c
@@ -458,19 +458,23 @@ fakeaddr(const char *name, int af, struct hostent *hp, char *buf,
}
strncpy(hed->hostbuf, name, MAXDNAME);
hed->hostbuf[MAXDNAME] = '\0';
+#ifdef INET6
if (af == AF_INET && (statp->options & RES_USE_INET6) != 0U) {
_map_v4v6_address((char *)hed->host_addr,
(char *)hed->host_addr);
af = AF_INET6;
}
+#endif
he.h_addrtype = af;
switch(af) {
case AF_INET:
he.h_length = NS_INADDRSZ;
break;
+#ifdef INET6
case AF_INET6:
he.h_length = NS_IN6ADDRSZ;
break;
+#endif
default:
errno = EAFNOSUPPORT;
RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
diff --git a/freebsd-userspace/lib/libc/stdlib/strtonum.3 b/freebsd-userspace/lib/libc/stdlib/strtonum.3
new file mode 100644
index 00000000..b83aadda
--- /dev/null
+++ b/freebsd-userspace/lib/libc/stdlib/strtonum.3
@@ -0,0 +1,155 @@
+.\" 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.13 2006/04/25 05:15:42 tedu Exp $
+.\" $FreeBSD$
+.\"
+.Dd April 29, 2004
+.Dt STRTONUM 3
+.Os
+.Sh NAME
+.Nm strtonum
+.Nd "reliably convert string value to an integer"
+.Sh SYNOPSIS
+.In stdlib.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 .
diff --git a/freebsd-userspace/lib/libc/stdlib/strtonum.c b/freebsd-userspace/lib/libc/stdlib/strtonum.c
new file mode 100644
index 00000000..6dccd973
--- /dev/null
+++ b/freebsd-userspace/lib/libc/stdlib/strtonum.c
@@ -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);
+}