summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile15
-rw-r--r--lib/atf/Makefile.inc23
-rw-r--r--lib/atf/common.mk2
-rw-r--r--lib/atf/libatf-c++/Makefile9
-rw-r--r--lib/atf/libatf-c++/tests/Makefile3
-rw-r--r--lib/atf/libatf-c++/tests/detail/Makefile3
-rw-r--r--lib/atf/libatf-c/Makefile17
-rw-r--r--lib/atf/libatf-c/tests/Makefile2
-rw-r--r--lib/atf/libatf-c/tests/detail/Makefile1
-rw-r--r--lib/clang/clang.build.mk9
-rw-r--r--lib/clang/include/clang/Config/config.h2
-rw-r--r--lib/clang/include/llvm/Config/config.h2
-rw-r--r--lib/csu/amd64/Makefile1
-rw-r--r--lib/csu/i386-elf/Makefile20
-rw-r--r--lib/libarchive/Makefile6
-rw-r--r--lib/libarchive/libarchive.pc12
-rw-r--r--lib/libc++/Makefile14
-rw-r--r--lib/libc/Makefile8
-rw-r--r--lib/libc/Makefile.amd646
-rw-r--r--lib/libc/Makefile.i3866
-rw-r--r--lib/libc/arm/Makefile.inc7
-rw-r--r--lib/libc/arm/Symbol_oabi.map16
-rw-r--r--lib/libc/arm/Symbol_vfp.map10
-rw-r--r--lib/libc/arm/aeabi/Makefile.inc6
-rw-r--r--lib/libc/arm/aeabi/Symbol.map8
-rw-r--r--lib/libc/arm/aeabi/aeabi_asm_double.S117
-rw-r--r--lib/libc/arm/aeabi/aeabi_asm_float.S108
-rw-r--r--lib/libc/arm/aeabi/aeabi_double.c25
-rw-r--r--lib/libc/arm/aeabi/aeabi_float.c25
-rw-r--r--lib/libc/arm/aeabi/aeabi_vfp.h6
-rw-r--r--lib/libc/arm/aeabi/aeabi_vfp_double.S27
-rw-r--r--lib/libc/arm/aeabi/aeabi_vfp_float.S24
-rw-r--r--lib/libc/arm/gen/Makefile.inc4
-rw-r--r--lib/libc/arm/gen/__aeabi_read_tp.S1
-rw-r--r--lib/libc/arm/gen/_ctx_start.S1
-rw-r--r--lib/libc/arm/gen/_setjmp.S2
-rw-r--r--lib/libc/arm/gen/alloca.S1
-rw-r--r--lib/libc/arm/gen/divsi3.S4
-rw-r--r--lib/libc/arm/gen/setjmp.S3
-rw-r--r--lib/libc/arm/gen/sigsetjmp.S2
-rw-r--r--lib/libc/arm/string/ffs.S1
-rw-r--r--lib/libc/arm/string/memcmp.S1
-rw-r--r--lib/libc/arm/string/memcpy_arm.S1
-rw-r--r--lib/libc/arm/string/memcpy_xscale.S1
-rw-r--r--lib/libc/arm/string/memmove.S5
-rw-r--r--lib/libc/arm/string/memset.S5
-rw-r--r--lib/libc/arm/string/strcmp.S1
-rw-r--r--lib/libc/arm/string/strlen.S1
-rw-r--r--lib/libc/arm/string/strncmp.S1
-rw-r--r--lib/libc/arm/sys/Ovfork.S1
-rw-r--r--lib/libc/arm/sys/brk.S1
-rw-r--r--lib/libc/arm/sys/cerror.S1
-rw-r--r--lib/libc/arm/sys/pipe.S1
-rw-r--r--lib/libc/arm/sys/ptrace.S1
-rw-r--r--lib/libc/arm/sys/sbrk.S1
-rw-r--r--lib/libc/gen/dl_iterate_phdr.34
-rw-r--r--lib/libc/gen/getgrouplist.312
-rw-r--r--lib/libc/gen/initgroups.313
-rw-r--r--lib/libc/gen/nlist.c4
-rw-r--r--lib/libc/gen/posix_spawnattr_init.32
-rw-r--r--lib/libc/gen/rewinddir.c2
-rw-r--r--lib/libc/gen/sem_destroy.33
-rw-r--r--lib/libc/gen/sem_getvalue.33
-rw-r--r--lib/libc/gen/sem_init.33
-rw-r--r--lib/libc/gen/sem_new.c27
-rw-r--r--lib/libc/gen/sem_open.33
-rw-r--r--lib/libc/gen/sem_post.33
-rw-r--r--lib/libc/gen/sem_timedwait.33
-rw-r--r--lib/libc/gen/sem_wait.33
-rw-r--r--lib/libc/iconv/iconv.38
-rw-r--r--lib/libc/include/isc/eventlib.h22
-rw-r--r--lib/libc/include/isc/list.h3
-rw-r--r--lib/libc/include/port_before.h1
-rw-r--r--lib/libc/inet/inet_addr.c2
-rw-r--r--lib/libc/inet/inet_cidr_ntop.c4
-rw-r--r--lib/libc/inet/inet_cidr_pton.c2
-rw-r--r--lib/libc/inet/inet_net_ntop.c2
-rw-r--r--lib/libc/inet/inet_net_pton.c22
-rw-r--r--lib/libc/inet/inet_neta.c2
-rw-r--r--lib/libc/inet/inet_ntoa.c2
-rw-r--r--lib/libc/inet/inet_ntop.c2
-rw-r--r--lib/libc/inet/inet_pton.c2
-rw-r--r--lib/libc/inet/nsap_addr.c2
-rw-r--r--lib/libc/isc/ev_streams.c2
-rw-r--r--lib/libc/isc/ev_timers.c2
-rw-r--r--lib/libc/isc/eventlib_p.h2
-rw-r--r--lib/libc/locale/lmonetary.c2
-rw-r--r--lib/libc/md/Makefile.inc5
-rw-r--r--lib/libc/nameser/Symbol.map21
-rw-r--r--lib/libc/nameser/ns_name.c255
-rw-r--r--lib/libc/nameser/ns_netint.c4
-rw-r--r--lib/libc/nameser/ns_parse.c70
-rw-r--r--lib/libc/nameser/ns_print.c356
-rw-r--r--lib/libc/nameser/ns_samedomain.c2
-rw-r--r--lib/libc/nameser/ns_ttl.c4
-rw-r--r--lib/libc/net/getaddrinfo.c52
-rw-r--r--lib/libc/net/getnameinfo.c1
-rw-r--r--lib/libc/net/linkaddr.c2
-rw-r--r--lib/libc/net/nsdispatch.c13
-rw-r--r--lib/libc/net/sctp_sys_calls.c28
-rw-r--r--lib/libc/posix1e/acl.314
-rw-r--r--lib/libc/posix1e/acl_add_flag_np.34
-rw-r--r--lib/libc/posix1e/acl_clear_flags_np.34
-rw-r--r--lib/libc/posix1e/acl_delete_flag_np.34
-rw-r--r--lib/libc/posix1e/acl_get_flag_np.34
-rw-r--r--lib/libc/posix1e/acl_get_flagset_np.34
-rw-r--r--lib/libc/posix1e/acl_set_entry_type_np.34
-rw-r--r--lib/libc/posix1e/acl_set_flagset_np.34
-rw-r--r--lib/libc/powerpc/gen/_ctx_start.S1
-rw-r--r--lib/libc/powerpc/gen/_setjmp.S2
-rw-r--r--lib/libc/powerpc/gen/eabi.S1
-rw-r--r--lib/libc/powerpc/gen/fabs.S1
-rw-r--r--lib/libc/powerpc/gen/setjmp.S2
-rw-r--r--lib/libc/powerpc/gen/sigsetjmp.S2
-rw-r--r--lib/libc/powerpc/sys/brk.S1
-rw-r--r--lib/libc/powerpc/sys/exect.S1
-rw-r--r--lib/libc/powerpc/sys/pipe.S1
-rw-r--r--lib/libc/powerpc/sys/ptrace.S1
-rw-r--r--lib/libc/powerpc/sys/sbrk.S1
-rw-r--r--lib/libc/powerpc64/gen/_ctx_start.S1
-rw-r--r--lib/libc/powerpc64/gen/_setjmp.S2
-rw-r--r--lib/libc/powerpc64/gen/fabs.S1
-rw-r--r--lib/libc/powerpc64/gen/setjmp.S2
-rw-r--r--lib/libc/powerpc64/gen/sigsetjmp.S2
-rw-r--r--lib/libc/powerpc64/sys/brk.S1
-rw-r--r--lib/libc/powerpc64/sys/exect.S1
-rw-r--r--lib/libc/powerpc64/sys/pipe.S1
-rw-r--r--lib/libc/powerpc64/sys/ptrace.S1
-rw-r--r--lib/libc/powerpc64/sys/sbrk.S1
-rw-r--r--lib/libc/quad/Makefile.inc2
-rw-r--r--lib/libc/resolv/Makefile.inc2
-rw-r--r--lib/libc/resolv/Symbol.map5
-rw-r--r--lib/libc/resolv/herror.c2
-rw-r--r--lib/libc/resolv/res_comp.c2
-rw-r--r--lib/libc/resolv/res_data.c19
-rw-r--r--lib/libc/resolv/res_debug.c77
-rw-r--r--lib/libc/resolv/res_findzonecut.c2
-rw-r--r--lib/libc/resolv/res_init.c69
-rw-r--r--lib/libc/resolv/res_mkquery.c47
-rw-r--r--lib/libc/resolv/res_mkupdate.c5
-rw-r--r--lib/libc/resolv/res_query.c44
-rw-r--r--lib/libc/resolv/res_send.c52
-rw-r--r--lib/libc/resolv/res_update.c2
-rw-r--r--lib/libc/rpc/clnt_vc.c1
-rw-r--r--lib/libc/stdio/getline.31
-rw-r--r--lib/libc/stdio/open_memstream.36
-rw-r--r--lib/libc/stdlib/Symbol.map1
-rw-r--r--lib/libc/stdlib/lsearch.c6
-rw-r--r--lib/libc/stdlib/strtonum.c14
-rw-r--r--lib/libc/stdtime/strptime.315
-rw-r--r--lib/libc/stdtime/strptime.c141
-rw-r--r--lib/libc/string/Makefile.inc5
-rw-r--r--lib/libc/string/Symbol.map4
-rw-r--r--lib/libc/string/bzero.320
-rw-r--r--lib/libc/sys/Makefile.inc1
-rw-r--r--lib/libc/sys/Symbol.map6
-rw-r--r--lib/libc/sys/accept.24
-rw-r--r--lib/libc/sys/access.212
-rw-r--r--lib/libc/sys/connect.24
-rw-r--r--lib/libc/sys/kqueue.21
-rw-r--r--lib/libc/sys/mmap.238
-rw-r--r--lib/libc/sys/mq_open.210
-rw-r--r--lib/libc/sys/poll.265
-rw-r--r--lib/libc/sys/recv.26
-rw-r--r--lib/libc/sys/utrace.23
-rw-r--r--lib/libc/tests/Makefile32
-rw-r--r--lib/libc/tests/Makefile.netbsd-tests7
-rw-r--r--lib/libc/tests/c063/Makefile24
-rw-r--r--lib/libc/tests/db/Makefile17
-rw-r--r--lib/libc/tests/gen/Makefile61
-rw-r--r--lib/libc/tests/gen/arc4random_test.c92
-rw-r--r--lib/libc/tests/gen/execve/Makefile15
-rw-r--r--lib/libc/tests/gen/fpclassify2_test.c72
-rw-r--r--lib/libc/tests/gen/posix_spawn/Makefile34
-rw-r--r--lib/libc/tests/hash/Makefile31
-rw-r--r--lib/libc/tests/inet/Makefile11
-rw-r--r--lib/libc/tests/locale/Makefile22
-rw-r--r--lib/libc/tests/net/Makefile39
-rw-r--r--lib/libc/tests/net/getaddrinfo/Makefile31
-rw-r--r--lib/libc/tests/regex/Makefile59
-rw-r--r--lib/libc/tests/rpc/Makefile27
-rw-r--r--lib/libc/tests/setjmp/Makefile13
-rw-r--r--lib/libc/tests/ssp/Makefile45
-rw-r--r--lib/libc/tests/stdio/Makefile19
-rw-r--r--lib/libc/tests/stdio/fmemopen2_test.c300
-rw-r--r--lib/libc/tests/stdlib/Makefile44
-rw-r--r--lib/libc/tests/string/Makefile33
-rw-r--r--lib/libc/tests/sys/Makefile85
-rw-r--r--lib/libc/tests/termios/Makefile11
-rw-r--r--lib/libc/tests/time/Makefile12
-rw-r--r--lib/libc/tests/tls/Makefile35
-rw-r--r--lib/libc/tests/tls/dso/Makefile18
-rw-r--r--lib/libc/tests/tls_dso/Makefile20
-rw-r--r--lib/libc/tests/ttyio/Makefile15
-rw-r--r--lib/libcompiler_rt/Makefile9
-rw-r--r--lib/libcrypt/crypt.c17
-rw-r--r--lib/libcrypt/tests/Makefile3
-rw-r--r--lib/libcuse/Makefile1
-rw-r--r--lib/libcuse/cuse_lib.c98
-rw-r--r--lib/libcxxrt/Version.map9
-rw-r--r--lib/libdpv/Makefile18
-rw-r--r--lib/libdpv/dialog_util.c633
-rw-r--r--lib/libdpv/dialog_util.h73
-rw-r--r--lib/libdpv/dialogrc.c359
-rw-r--r--lib/libdpv/dialogrc.h (renamed from lib/libproc/test/t3-name2sym/t3-name2sym.c)97
-rw-r--r--lib/libdpv/dprompt.c770
-rw-r--r--lib/libdpv/dprompt.h59
-rw-r--r--lib/libdpv/dpv.3510
-rw-r--r--lib/libdpv/dpv.c721
-rw-r--r--lib/libdpv/dpv.h161
-rw-r--r--lib/libdpv/dpv_private.h66
-rw-r--r--lib/libdpv/status.c111
-rw-r--r--lib/libdpv/status.h43
-rw-r--r--lib/libdpv/util.c107
-rw-r--r--lib/libdpv/util.h (renamed from lib/libproc/test/t2-name2map/t2-name2map.c)84
-rw-r--r--lib/libevent/Makefile31
-rw-r--r--lib/libexpat/Makefile10
-rw-r--r--lib/libfetch/common.c10
-rw-r--r--lib/libfetch/fetch.328
-rw-r--r--lib/libfigpar/Makefile21
-rw-r--r--lib/libfigpar/figpar.3251
-rw-r--r--lib/libfigpar/figpar.c469
-rw-r--r--lib/libfigpar/figpar.h99
-rw-r--r--lib/libfigpar/string_m.c309
-rw-r--r--lib/libfigpar/string_m.h43
-rw-r--r--lib/libgeom/geom_getxml.c41
-rw-r--r--lib/libgeom/geom_stats.c4
-rw-r--r--lib/libkvm/kvm_arm.c40
-rw-r--r--lib/libkvm/kvm_proc.c18
-rw-r--r--lib/libmp/Makefile6
-rw-r--r--lib/libmp/tests/Makefile10
-rw-r--r--lib/libmp/tests/legacy_test.c211
-rw-r--r--lib/libnetbsd/netinet/in.h72
-rw-r--r--lib/libnetbsd/sys/cdefs.h22
-rw-r--r--lib/libnetbsd/sys/time.h65
-rw-r--r--lib/libnv/Makefile11
-rw-r--r--lib/libnv/msgio.c113
-rw-r--r--lib/libnv/nv.38
-rw-r--r--lib/libnv/nv.h2
-rw-r--r--lib/libnv/nv_impl.h4
-rw-r--r--lib/libnv/nvlist.c255
-rw-r--r--lib/libnv/nvlist_impl.h4
-rw-r--r--lib/libnv/nvpair.c217
-rw-r--r--lib/libnv/nvpair_impl.h44
-rw-r--r--lib/libnv/tests/Makefile17
-rw-r--r--lib/libnv/tests/nvlist_add_test.c196
-rw-r--r--lib/libnv/tests/nvlist_exists_test.c321
-rw-r--r--lib/libnv/tests/nvlist_free_test.c221
-rw-r--r--lib/libnv/tests/nvlist_get_test.c182
-rw-r--r--lib/libnv/tests/nvlist_move_test.c161
-rw-r--r--lib/libnv/tests/nvlist_send_recv_test.c325
-rw-r--r--lib/libohash/Makefile9
-rw-r--r--lib/libohash/ohash.c330
-rw-r--r--lib/libohash/ohash.h75
-rw-r--r--lib/libohash/ohash_init.3273
-rw-r--r--lib/libohash/ohash_interval.395
-rw-r--r--lib/libopie/Makefile2
-rw-r--r--lib/libpam/libpam/Makefile5
-rw-r--r--lib/libpam/libpam/tests/Makefile19
-rw-r--r--lib/libpam/modules/pam_login_access/pam_login_access.c21
-rw-r--r--lib/libpam/modules/pam_opie/pam_opie.c2
-rw-r--r--lib/libpam/modules/pam_ssh/Makefile2
-rw-r--r--lib/libpcap/Makefile1
-rw-r--r--lib/libpcap/config.h3
-rw-r--r--lib/libpcap/pcap-netmap.c283
-rw-r--r--lib/libproc/Makefile17
-rw-r--r--lib/libproc/libproc.h13
-rw-r--r--lib/libproc/proc_sym.c319
-rw-r--r--lib/libproc/test/Makefile5
-rw-r--r--lib/libproc/test/t1-bkpt/Makefile12
-rw-r--r--lib/libproc/test/t2-name2map/Makefile12
-rw-r--r--lib/libproc/test/t3-name2sym/Makefile12
-rw-r--r--lib/libproc/tests/Makefile21
-rw-r--r--lib/libproc/tests/proc_test.c349
-rw-r--r--lib/libproc/tests/target_prog.c (renamed from lib/libproc/test/t1-bkpt/t1-bkpt.c)102
-rw-r--r--lib/librt/Makefile4
-rw-r--r--lib/librt/Makefile.amd646
-rw-r--r--lib/librt/Makefile.i3866
-rw-r--r--lib/librt/tests/Makefile17
-rw-r--r--lib/librtld_db/rtld_db.c4
-rw-r--r--lib/libstand/Makefile5
-rw-r--r--lib/libstand/open.c32
-rw-r--r--lib/libstand/pkgfs.c791
-rw-r--r--lib/libstand/stand.h2
-rw-r--r--lib/libstdthreads/threads.h27
-rw-r--r--lib/libthr/Makefile2
-rw-r--r--lib/libthr/Makefile.amd646
-rw-r--r--lib/libthr/Makefile.i3866
-rw-r--r--lib/libthr/libthr.3223
-rw-r--r--lib/libthr/tests/Makefile58
-rw-r--r--lib/libthr/tests/dlopen/Makefile30
-rw-r--r--lib/libthr/tests/dlopen/dso/Makefile19
-rw-r--r--lib/libthr/thread/thr_cond.c2
-rw-r--r--lib/libthr/thread/thr_init.c11
-rw-r--r--lib/libthr/thread/thr_stack.c7
-rw-r--r--lib/libunbound/Makefile2
-rw-r--r--lib/libusb/Makefile2
-rw-r--r--lib/libusb/libusb.h8
-rw-r--r--lib/libutil/Makefile4
-rw-r--r--lib/libutil/gr_util.c17
-rw-r--r--lib/libutil/login_class.c10
-rw-r--r--lib/libutil/tests/Makefile15
-rw-r--r--lib/libutil/tests/flopen_test.c210
-rw-r--r--lib/libutil/tests/grp_test.c117
-rw-r--r--lib/libutil/tests/humanize_number_test.c598
-rw-r--r--lib/libutil/tests/pidfile_test.c280
-rw-r--r--lib/libutil/tests/trimdomain-nodomain_test.c91
-rw-r--r--lib/libutil/tests/trimdomain_test.c91
-rw-r--r--lib/libxo/Makefile36
-rw-r--r--lib/libz/Makefile2
-rw-r--r--lib/msun/Makefile8
-rw-r--r--lib/msun/Makefile.amd646
-rw-r--r--lib/msun/Makefile.i3866
-rw-r--r--lib/msun/Symbol.map7
-rw-r--r--lib/msun/arm/fenv.c4
-rw-r--r--lib/msun/ld128/e_lgammal_r.c330
-rw-r--r--lib/msun/ld80/e_lgammal_r.c358
-rw-r--r--lib/msun/man/lgamma.337
-rw-r--r--lib/msun/src/e_lgamma.c6
-rw-r--r--lib/msun/src/e_lgamma_r.c150
-rw-r--r--lib/msun/src/e_lgammaf_r.c261
-rw-r--r--lib/msun/src/e_lgammal.c25
-rw-r--r--lib/msun/src/imprecise.c1
-rw-r--r--lib/msun/src/math.h29
-rw-r--r--lib/msun/src/s_tanh.c3
-rw-r--r--lib/msun/src/s_tanhf.c4
-rw-r--r--lib/msun/tests/Makefile63
327 files changed, 15898 insertions, 1463 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 05fab01..8ca673a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -42,11 +42,14 @@ SUBDIR= ${SUBDIR_ORDERED} \
libcrypt \
libdevinfo \
libdevstat \
+ libdpv \
libdwarf \
libedit \
+ ${_libevent} \
libexecinfo \
libexpat \
libfetch \
+ libfigpar \
libgeom \
${_libgpib} \
${_libgssapi} \
@@ -69,6 +72,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
${_libnetgraph} \
${_libngatm} \
libnv \
+ libohash \
libopie \
libpam \
libpcap \
@@ -104,6 +108,7 @@ SUBDIR= ${SUBDIR_ORDERED} \
${_libvgl} \
${_libvmmapi} \
libwrap \
+ libxo \
liby \
${_libypclnt} \
libz \
@@ -126,7 +131,7 @@ SUBDIR_DEPEND_libcam= libsbuf
SUBDIR_DEPEND_libcapsicum= libnv
SUBDIR_DEPEND_libcasper= libcapsicum libnv libpjdlog
SUBDIR_DEPEND_libdevstat= libkvm
-SUBDIR_DEPEND_libdiaglog= ncurses
+SUBDIR_DEPEND_libdpv= libfigpar ncurses libutil
SUBDIR_DEPEND_libedit= ncurses
SUBDIR_DEPEND_libg++= msun
SUBDIR_DEPEND_libgeom= libexpat libsbuf
@@ -225,6 +230,10 @@ _libnetgraph= libnetgraph
_libypclnt= libypclnt
.endif
+.if ${MK_PF} != "no"
+_libevent= libevent
+.endif
+
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
_libsmb= libsmb
_libvgl= libvgl
@@ -270,8 +279,10 @@ _libsmutil= libsmutil
_libtelnet= libtelnet
.endif
-.if ${MK_TESTS} != "no"
+.if ${MK_TESTS_SUPPORT} != "no"
_atf= atf
+.endif
+.if ${MK_TESTS} != "no"
_tests= tests
.endif
diff --git a/lib/atf/Makefile.inc b/lib/atf/Makefile.inc
index 40da946..392bbb2 100644
--- a/lib/atf/Makefile.inc
+++ b/lib/atf/Makefile.inc
@@ -25,29 +25,6 @@
#
# $FreeBSD$
-_CFLAGS:= ${CFLAGS}
-_CPPFLAGS:= ${CPPFLAGS}
-_CXXFLAGS:= ${CXXFLAGS}
-
CFLAGS+= -DHAVE_CONFIG_H
-CFLAGS+= -DATF_ARCH='"${MACHINE}"'
-CFLAGS+= -DATF_BUILD_CC='"${CC}"'
-CFLAGS+= -DATF_BUILD_CFLAGS='"${_CFLAGS}"'
-CFLAGS+= -DATF_BUILD_CPP='"${CPP}"'
-CFLAGS+= -DATF_BUILD_CPPFLAGS='"${_CPPFLAGS}"'
-CFLAGS+= -DATF_BUILD_CXX='"${CXX}"'
-CFLAGS+= -DATF_BUILD_CXXFLAGS='"${_CXXFLAGS}"'
-CFLAGS+= -DATF_CONFDIR='"${CONFDIR}/atf"'
-CFLAGS+= -DATF_C_TESTS_BASE='"${TESTSBASE}/lib/atf/libatf-c"'
-CFLAGS+= -DATF_INCLUDEDIR='"${INCLUDEDIR}"'
-CFLAGS+= -DATF_LIBDIR='"${LIBDIR}"'
-CFLAGS+= -DATF_LIBEXECDIR='"${LIBEXECDIR}"'
-CFLAGS+= -DATF_MACHINE='"${MACHINE_ARCH}"'
-CFLAGS+= -DATF_M4='"/usr/bin/m4"'
-CFLAGS+= -DATF_PKGDATADIR='"${SHAREDIR}/atf"'
-CFLAGS+= -DATF_SHELL='"/bin/sh"'
-CFLAGS+= -DATF_WORKDIR='"/tmp"'
WARNS?= 3
-
-# vim: syntax=make
diff --git a/lib/atf/common.mk b/lib/atf/common.mk
index 6338207..581befb 100644
--- a/lib/atf/common.mk
+++ b/lib/atf/common.mk
@@ -14,6 +14,6 @@ atf-version: atf-version-real
@cmp -s atf-version atf-version-real \
|| cp atf-version-real atf-version
atf-version-real: .PHONY
- @grep 'define VERSION' ${ATF}/bconfig.h \
+ @grep 'define VERSION' ${ATF}/config.h \
| cut -d '"' -f 2 >atf-version-real
CLEANFILES+= atf-version atf-version-real
diff --git a/lib/atf/libatf-c++/Makefile b/lib/atf/libatf-c++/Makefile
index 163f7fb..352a8f4 100644
--- a/lib/atf/libatf-c++/Makefile
+++ b/lib/atf/libatf-c++/Makefile
@@ -30,10 +30,10 @@
LIB= atf-c++
PRIVATELIB= true
-SHLIB_MAJOR= 1
+SHLIB_MAJOR= 2
# libatf-c++ depends on the C version of the ATF library to build.
-DPADD= ${LIBATFC}
+DPADD= ${LIBATF_C}
LDADD= -latf-c
LDFLAGS+= -L${.OBJDIR}/../libatf-c
@@ -52,7 +52,6 @@ CFLAGS+= -DHAVE_CONFIG_H
SRCS= application.cpp \
build.cpp \
check.cpp \
- config.cpp \
env.cpp \
exceptions.cpp \
fs.cpp \
@@ -63,7 +62,6 @@ SRCS= application.cpp \
INCS= build.hpp \
check.hpp \
- config.hpp \
macros.hpp \
tests.hpp \
utils.hpp
@@ -72,7 +70,8 @@ INCSDIR= ${INCLUDEDIR}/atf-c++
INCS+= atf-c++.hpp
INCSDIR_atf-c++.hpp= ${INCLUDEDIR}
-MAN= atf-c++-api.3
+MAN= atf-c++.3
+MLINKS+= atf-c++.3 atf-c-api++.3 # Backwards compatibility.
.if ${MK_TESTS} != "no"
SUBDIR= tests
diff --git a/lib/atf/libatf-c++/tests/Makefile b/lib/atf/libatf-c++/tests/Makefile
index 56355f2..5f5a575 100644
--- a/lib/atf/libatf-c++/tests/Makefile
+++ b/lib/atf/libatf-c++/tests/Makefile
@@ -9,6 +9,8 @@ ATF= ${.CURDIR:H:H:H:H}/contrib/atf
.PATH: ${ATF}/atf-c++
.PATH: ${ATF}/atf-c++/detail
+CFLAGS+= -DATF_C_TESTS_BASE='"${TESTSBASE}/lib/atf/libatf-c"'
+CFLAGS+= -DATF_INCLUDEDIR='"${INCLUDEDIR}"'
CFLAGS+= -I${ATF}
FILESDIR= ${TESTSDIR}
@@ -18,7 +20,6 @@ FILES+= unused_test.cpp
.for _T in atf_c++_test \
build_test \
check_test \
- config_test \
macros_test \
tests_test \
utils_test
diff --git a/lib/atf/libatf-c++/tests/detail/Makefile b/lib/atf/libatf-c++/tests/detail/Makefile
index b3fd4dc..69c3e7b 100644
--- a/lib/atf/libatf-c++/tests/detail/Makefile
+++ b/lib/atf/libatf-c++/tests/detail/Makefile
@@ -7,6 +7,8 @@ TESTSDIR= ${TESTSBASE}/lib/atf/libatf-c++/detail
ATF= ${.CURDIR:H:H:H:H:H}/contrib/atf
.PATH: ${ATF}/atf-c++/detail
+CFLAGS+= -DATF_C_TESTS_BASE='"${TESTSBASE}/lib/atf/libatf-c"'
+CFLAGS+= -DATF_INCLUDEDIR='"${INCLUDEDIR}"'
CFLAGS+= -I${ATF}
.for _T in application_test \
@@ -14,7 +16,6 @@ CFLAGS+= -I${ATF}
exceptions_test \
fs_test \
process_test \
- sanity_test \
text_test
ATF_TESTS_CXX+= ${_T}
SRCS.${_T}= ${_T}.cpp test_helpers.cpp
diff --git a/lib/atf/libatf-c/Makefile b/lib/atf/libatf-c/Makefile
index 4920eb5..0fbb4ca 100644
--- a/lib/atf/libatf-c/Makefile
+++ b/lib/atf/libatf-c/Makefile
@@ -28,22 +28,31 @@
.include <src.opts.mk>
.include <bsd.init.mk>
+_CFLAGS:= ${CFLAGS}
+_CPPFLAGS:= ${CPPFLAGS}
+_CXXFLAGS:= ${CXXFLAGS}
+
LIB= atf-c
PRIVATELIB= true
-SHLIB_MAJOR= 0
+SHLIB_MAJOR= 1
ATF= ${.CURDIR:H:H:H}/contrib/atf
.PATH: ${ATF}
.PATH: ${ATF}/atf-c
.PATH: ${ATF}/atf-c/detail
+CFLAGS+= -DATF_BUILD_CC='"${CC}"'
+CFLAGS+= -DATF_BUILD_CFLAGS='"${_CFLAGS}"'
+CFLAGS+= -DATF_BUILD_CPP='"${CPP}"'
+CFLAGS+= -DATF_BUILD_CPPFLAGS='"${_CPPFLAGS}"'
+CFLAGS+= -DATF_BUILD_CXX='"${CXX}"'
+CFLAGS+= -DATF_BUILD_CXXFLAGS='"${_CXXFLAGS}"'
CFLAGS+= -I${ATF}
CFLAGS+= -I${.CURDIR}
CFLAGS+= -I.
SRCS= build.c \
check.c \
- config.c \
dynstr.c \
env.c \
error.c \
@@ -61,7 +70,6 @@ SRCS= build.c \
INCS= build.h \
check.h \
- config.h \
defs.h \
error.h \
error_fwd.h \
@@ -74,7 +82,8 @@ INCSDIR= ${INCLUDEDIR}/atf-c
INCS+= atf-c.h
INCSDIR_atf-c.h= ${INCLUDEDIR}
-MAN= atf-c-api.3
+MAN= atf-c.3
+MLINKS+= atf-c.3 atf-c-api.3 # Backwards compatibility.
.if ${MK_TESTS} != "no"
SUBDIR= tests
diff --git a/lib/atf/libatf-c/tests/Makefile b/lib/atf/libatf-c/tests/Makefile
index 70ba1a5..d5b6dc0 100644
--- a/lib/atf/libatf-c/tests/Makefile
+++ b/lib/atf/libatf-c/tests/Makefile
@@ -9,6 +9,7 @@ ATF= ${.CURDIR:H:H:H:H}/contrib/atf
.PATH: ${ATF}/atf-c
.PATH: ${ATF}/atf-c/detail
+CFLAGS+= -DATF_INCLUDEDIR='"${INCLUDEDIR}"'
CFLAGS+= -I${ATF}
# macros_test.c contains a double 'const const' which will be gone with
@@ -23,7 +24,6 @@ FILES+= unused_test.c
.for _T in atf_c_test \
build_test \
check_test \
- config_test \
error_test \
macros_test \
tc_test \
diff --git a/lib/atf/libatf-c/tests/detail/Makefile b/lib/atf/libatf-c/tests/detail/Makefile
index aa85aa3..02c1f2b 100644
--- a/lib/atf/libatf-c/tests/detail/Makefile
+++ b/lib/atf/libatf-c/tests/detail/Makefile
@@ -7,6 +7,7 @@ TESTSDIR= ${TESTSBASE}/lib/atf/libatf-c/detail
ATF= ${.CURDIR:H:H:H:H:H}/contrib/atf
.PATH: ${ATF}/atf-c/detail
+CFLAGS+= -DATF_INCLUDEDIR='"${INCLUDEDIR}"'
CFLAGS+= -I${ATF}
.for _T in dynstr_test \
diff --git a/lib/clang/clang.build.mk b/lib/clang/clang.build.mk
index ec8f451..0f68178 100644
--- a/lib/clang/clang.build.mk
+++ b/lib/clang/clang.build.mk
@@ -22,11 +22,10 @@ CFLAGS+= -fno-strict-aliasing
TARGET_ARCH?= ${MACHINE_ARCH}
BUILD_ARCH?= ${MACHINE_ARCH}
-.if (${TARGET_ARCH} == "arm" || ${TARGET_ARCH} == "armv6") && \
- ${MK_ARM_EABI} != "no"
-TARGET_ABI= gnueabi
-.elif ${TARGET_ARCH} == "armv6hf"
+.if ${TARGET_ARCH:Marm*hf*} != ""
TARGET_ABI= gnueabihf
+.elif ${TARGET_ARCH:Marm*} != ""
+TARGET_ABI= gnueabi
.else
TARGET_ABI= unknown
.endif
@@ -250,7 +249,7 @@ Checkers.inc.h: ${CLANG_SRCS}/lib/StaticAnalyzer/Checkers/Checkers.td
.endfor
SRCS+= ${TGHDRS:C/$/.inc.h/}
-DPADD+= ${TGHDRS:C/$/.inc.h/}
+DPSRCS+= ${TGHDRS:C/$/.inc.h/}
CLEANFILES+= ${TGHDRS:C/$/.inc.h/} ${TGHDRS:C/$/.inc.d/}
# if we are not doing explicit 'make depend', there is
diff --git a/lib/clang/include/clang/Config/config.h b/lib/clang/include/clang/Config/config.h
index 8a7936b..5c35829 100644
--- a/lib/clang/include/clang/Config/config.h
+++ b/lib/clang/include/clang/Config/config.h
@@ -6,7 +6,7 @@
#define CONFIG_H
/* Bug report URL. */
-#define BUG_REPORT_URL "http://llvm.org/bugs/"
+#define BUG_REPORT_URL "https://bugs.freebsd.org/submit/"
/* Relative directory for resource files */
#define CLANG_RESOURCE_DIR ""
diff --git a/lib/clang/include/llvm/Config/config.h b/lib/clang/include/llvm/Config/config.h
index cbbb4fb..ce32c50 100644
--- a/lib/clang/include/llvm/Config/config.h
+++ b/lib/clang/include/llvm/Config/config.h
@@ -9,7 +9,7 @@
#include <osreldate.h>
/* Bug report URL. */
-#define BUG_REPORT_URL "http://llvm.org/bugs/"
+#define BUG_REPORT_URL "https://bugs.freebsd.org/submit/"
/* Define if we have libxml2 */
/* #undef CLANG_HAVE_LIBXML */
diff --git a/lib/csu/amd64/Makefile b/lib/csu/amd64/Makefile
index 7b888fa..5ddbab6 100644
--- a/lib/csu/amd64/Makefile
+++ b/lib/csu/amd64/Makefile
@@ -14,7 +14,6 @@ FILESOWN= ${LIBOWN}
FILESGRP= ${LIBGRP}
FILESMODE= ${LIBMODE}
FILESDIR= ${LIBDIR}
-NO_PIE= yes
all: ${OBJS}
diff --git a/lib/csu/i386-elf/Makefile b/lib/csu/i386-elf/Makefile
index 8a685dc..57f4f05 100644
--- a/lib/csu/i386-elf/Makefile
+++ b/lib/csu/i386-elf/Makefile
@@ -3,17 +3,15 @@
.PATH: ${.CURDIR}/../common
SRCS= crti.S crtn.S
-FILES= ${SRCS:N*.h:R:S/$/.o/g} gcrt1.o crt1.o Scrt1.o
-FILESOWN= ${LIBOWN}
-FILESGRP= ${LIBGRP}
-FILESMODE= ${LIBMODE}
-FILESDIR= ${LIBDIR}
+OBJS= ${SRCS:N*.h:R:S/$/.o/g}
+OBJS+= gcrt1.o crt1.o Scrt1.o
CFLAGS+= -I${.CURDIR}/../common \
-I${.CURDIR}/../../libc/include
-CLEANFILES= ${FILES} crt1_c.o crt1_s.o gcrt1_c.o Scrt1_c.o
-CLEANFILES+= crt1_c.s gcrt1_c.s Scrt1_c.s
-NO_PIE= yes
+all: ${OBJS}
+
+CLEANFILES= ${OBJS} crt1_c.o crt1_s.o gcrt1_c.o Scrt1_c.o
+CLEANFILES+= crt1_c.s gcrt1_c.s Scrt1_c.s
# See the comment in lib/csu/common/crtbrand.c for the reason crt1_c.c is not
# directly compiled to .o files.
@@ -50,4 +48,8 @@ Scrt1.o: Scrt1_c.o crt1_s.o
${LD} ${_LDFLAGS} -o Scrt1.o -r crt1_s.o Scrt1_c.o
objcopy --localize-symbol _start1 Scrt1.o
-.include <bsd.prog.mk>
+realinstall:
+ ${INSTALL} -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${OBJS} ${DESTDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index 1460329..b7e9d7f 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -49,6 +49,12 @@ CFLAGS+= -DPPMD_32BIT
.endif
NO_WCAST_ALIGN.clang=
+.ifndef COMPAT_32BIT
+beforeinstall:
+ ${INSTALL} -C -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
+ ${.CURDIR}/libarchive.pc ${DESTDIR}${LIBDATADIR}/pkgconfig
+.endif
+
.PATH: ${LIBARCHIVEDIR}/libarchive
# Headers to be installed in /usr/include
diff --git a/lib/libarchive/libarchive.pc b/lib/libarchive/libarchive.pc
new file mode 100644
index 0000000..3aa1d04
--- /dev/null
+++ b/lib/libarchive/libarchive.pc
@@ -0,0 +1,12 @@
+# $FreeBSD$
+prefix=/usr
+exec_prefix=${prefix}
+libdir=${exec_prefix}/lib
+includedir=${prefix}/include
+
+Name: libarchive
+Description: library that can create and read several streaming archive formats
+Version: 3.1.2
+Cflags: -I${includedir}
+Libs: -L${libdir} -larchive
+Libs.private: -lz -lbz2 -llzma -lbsdxml -lcrypto
diff --git a/lib/libc++/Makefile b/lib/libc++/Makefile
index 1e7dfaf..e55cf55 100644
--- a/lib/libc++/Makefile
+++ b/lib/libc++/Makefile
@@ -1,5 +1,7 @@
# $FreeBSD$
+.include <src.opts.mk>
+
LIBCXXRTDIR= ${.CURDIR}/../../contrib/libcxxrt
HDRDIR= ${.CURDIR}/../../contrib/libc++/include
SRCDIR= ${.CURDIR}/../../contrib/libc++/src
@@ -57,7 +59,7 @@ cxxrt_${_S}:
WARNS= 0
CFLAGS+= -I${HDRDIR} -I${LIBCXXRTDIR} -nostdlib -DLIBCXXRT
.if empty(CXXFLAGS:M-std=*)
-CXXFLAGS+= -std=c++0x
+CXXFLAGS+= -std=c++11
.endif
DPADD= ${LIBCXXRT}
@@ -192,4 +194,14 @@ EXT+= ${HDRDIR}/ext/${hdr}
.endfor
EXTDIR= ${CXXINCLUDEDIR}/ext
+.if ${MK_GNUCXX} == "no" && ${COMPILER_TYPE} == "gcc"
+CLEANFILES+= libstdc++.so libstdc++.a
+
+afterinstall:
+ ln -sf ${DESTDIR}${LIBDIR}/lib${LIB}.so \
+ ${.OBJDIR}/libstdc++.so
+ ln -sf ${DESTDIR}${LIBDIR}/lib${LIB}.a \
+ ${.OBJDIR}/libstdc++.a
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libc/Makefile b/lib/libc/Makefile
index 9951857..5653220 100644
--- a/lib/libc/Makefile
+++ b/lib/libc/Makefile
@@ -49,6 +49,7 @@ LDFLAGS+= -nodefaultlibs
LDADD+= -lcompiler_rt
.if ${MK_SSP} != "no"
+DPADD+= ${LIBSSP_NONSHARED}
LDADD+= -lssp_nonshared
.endif
@@ -75,6 +76,7 @@ NOASM=
.include "${LIBC_SRCTOP}/inet/Makefile.inc"
.include "${LIBC_SRCTOP}/isc/Makefile.inc"
.include "${LIBC_SRCTOP}/locale/Makefile.inc"
+.include "${LIBC_SRCTOP}/md/Makefile.inc"
.include "${LIBC_SRCTOP}/nameser/Makefile.inc"
.include "${LIBC_SRCTOP}/net/Makefile.inc"
.include "${LIBC_SRCTOP}/nls/Makefile.inc"
@@ -149,13 +151,15 @@ KSRCS= bcmp.c ffs.c ffsl.c fls.c flsl.c mcount.c strcat.c strchr.c \
libkern: libkern.gen libkern.${LIBC_ARCH}
libkern.gen: ${KQSRCS} ${KSRCS}
- cp -p ${LIBC_SRCTOP}/quad/quad.h ${.ALLSRC} ${DESTDIR}/sys/libkern
+ cp -fp ${LIBC_SRCTOP}/quad/quad.h ${.ALLSRC} ${DESTDIR}/sys/libkern
libkern.${LIBC_ARCH}:: ${KMSRCS}
.if defined(KMSRCS) && !empty(KMSRCS)
- cp -p ${.ALLSRC} ${DESTDIR}/sys/libkern/${LIBC_ARCH}
+ cp -fp ${.ALLSRC} ${DESTDIR}/sys/libkern/${LIBC_ARCH}
.endif
+.include <bsd.arch.inc.mk>
+
.include <bsd.lib.mk>
.if !defined(_SKIP_BUILD)
diff --git a/lib/libc/Makefile.amd64 b/lib/libc/Makefile.amd64
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/libc/Makefile.amd64
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/libc/Makefile.i386 b/lib/libc/Makefile.i386
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/libc/Makefile.i386
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/libc/arm/Makefile.inc b/lib/libc/arm/Makefile.inc
index 6e61dcd..418f54d 100644
--- a/lib/libc/arm/Makefile.inc
+++ b/lib/libc/arm/Makefile.inc
@@ -9,10 +9,9 @@ SOFTFLOAT_BITS=32
MDSRCS+=machdep_ldisd.c
SYM_MAPS+=${LIBC_SRCTOP}/arm/Symbol.map
-.if ${MK_ARM_EABI} == "no"
-# This contains the symbols that were removed when moving to the ARM EABI
-SYM_MAPS+=${LIBC_SRCTOP}/arm/Symbol_oabi.map
-.else
.include "${LIBC_SRCTOP}/arm/aeabi/Makefile.inc"
+
+.if ${MACHINE_ARCH:Marm*hf*} != ""
+SYM_MAPS+=${LIBC_SRCTOP}/arm/Symbol_vfp.map
.endif
diff --git a/lib/libc/arm/Symbol_oabi.map b/lib/libc/arm/Symbol_oabi.map
deleted file mode 100644
index 0c22e4a..0000000
--- a/lib/libc/arm/Symbol_oabi.map
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * $FreeBSD$
- */
-
-/*
- * This only needs to contain symbols that are not listed in
- * symbol maps from other parts of libc (i.e., not found in
- * stdlib/Symbol.map, string/Symbol.map, sys/Symbol.map, ...)
- * and are not used in the ARM EABI.
- */
-FBSDprivate_1.0 {
- __umodsi3;
- __modsi3;
- __udivsi3;
- __divsi3;
-};
diff --git a/lib/libc/arm/Symbol_vfp.map b/lib/libc/arm/Symbol_vfp.map
new file mode 100644
index 0000000..82cfcfb
--- /dev/null
+++ b/lib/libc/arm/Symbol_vfp.map
@@ -0,0 +1,10 @@
+/*
+ * $FreeBSD$
+ */
+
+FBSD_1.0 {
+ fpgetmask;
+ fpgetround;
+ fpsetmask;
+ fpsetround;
+};
diff --git a/lib/libc/arm/aeabi/Makefile.inc b/lib/libc/arm/aeabi/Makefile.inc
index 0957c92..b204a53 100644
--- a/lib/libc/arm/aeabi/Makefile.inc
+++ b/lib/libc/arm/aeabi/Makefile.inc
@@ -5,8 +5,10 @@
SRCS+= aeabi_atexit.c \
aeabi_unwind_cpp.c \
aeabi_unwind_exidx.c
-.if ${MACHINE_ARCH} != "armv6hf"
-SRCS+= aeabi_double.c \
+.if ${MACHINE_ARCH:Marm*hf*} == ""
+SRCS+= aeabi_asm_double.S \
+ aeabi_asm_float.S \
+ aeabi_double.c \
aeabi_float.c
.endif
.if ${MACHINE_ARCH:Marmv6*}
diff --git a/lib/libc/arm/aeabi/Symbol.map b/lib/libc/arm/aeabi/Symbol.map
index 9493427..164d3e7 100644
--- a/lib/libc/arm/aeabi/Symbol.map
+++ b/lib/libc/arm/aeabi/Symbol.map
@@ -17,6 +17,10 @@ FBSDprivate_1.0 {
__aeabi_dcmpgt;
__aeabi_dcmpun;
+ __aeabi_cdcmpeq;
+ __aeabi_cdcmple;
+ __aeabi_cdrcmple;
+
__aeabi_d2iz;
__aeabi_d2f;
@@ -33,6 +37,10 @@ FBSDprivate_1.0 {
__aeabi_fcmpgt;
__aeabi_fcmpun;
+ __aeabi_cfcmpeq;
+ __aeabi_cfcmple;
+ __aeabi_cfrcmple;
+
__aeabi_f2iz;
__aeabi_f2d;
diff --git a/lib/libc/arm/aeabi/aeabi_asm_double.S b/lib/libc/arm/aeabi/aeabi_asm_double.S
new file mode 100644
index 0000000..ab44362
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_asm_double.S
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define PCR_Z (1 << 30)
+#define PCR_C (1 << 29)
+
+/*
+ * These functions return the result in the CPSR register.
+ *
+ * For __aeabi_cdcmple:
+ * Z C
+ * LT 0 0
+ * EQ 1 1
+ * else 0 1
+ *
+ * __aeabi_cdrcmple is the same as __aeabi_cdcmple, however the arguments
+ * have been swapped.
+ */
+ENTRY(__aeabi_cdcmple)
+ push {r4, r5, r6, r7, ip, lr}
+
+ /* Backup the input registers */
+ mov r4, r0
+ mov r5, r1
+ mov r6, r2
+ mov r7, r3
+ /* Is it less than? */
+ bl __aeabi_dcmplt
+ cmp r0, #1
+ bne 1f
+ /* Yes, clear Z and C */
+ msr cpsr_c, #(0)
+ b 99f
+
+1:
+ /* Restore the input regsters for the next function call */
+ mov r0, r4
+ mov r1, r5
+ mov r2, r6
+ mov r3, r7
+ /* Is it equal? */
+ bl __aeabi_dcmpeq
+ cmp r0, #1
+ bne 2f
+ /* Yes, set Z and C */
+ msr cpsr_c, #(PCR_Z | PCR_C)
+ b 99f
+
+2:
+ /* Not less than or equal, set C and clear Z */
+ msr cpsr_c, #(PCR_C)
+
+99:
+ pop {r4, r5, r6, r7, ip, pc}
+END(__aeabi_cdcmple)
+
+ENTRY(__aeabi_cdrcmple)
+ /* Swap the first half of the arguments */
+ mov ip, r0
+ mov r0, r2
+ mov r2, ip
+
+ /* And the second half */
+ mov ip, r1
+ mov r1, r3
+ mov r3, ip
+
+ b __aeabi_cdcmple
+END(__aeabi_cdrcmple)
+
+/*
+ * This is just like __aeabi_cdcmple except it will not throw an exception
+ * in the presence of a quiet NaN. If either argument is a signalling NaN we
+ * will still signal.
+ */
+ENTRY(__aeabi_cdcmpeq)
+ /* Check if we can call __aeabi_cfcmple safely */
+ push {r0, r1, r2, r3, r4, lr}
+ bl __aeabi_cdcmpeq_helper
+ cmp r0, #1
+ pop {r0, r1, r2, r3, r4, lr}
+ beq 1f
+
+ bl __aeabi_cdcmple
+ RET
+
+1:
+ msr cpsr_c, #(PCR_C)
+ RET
+END(__aeabi_cdcmpeq)
diff --git a/lib/libc/arm/aeabi/aeabi_asm_float.S b/lib/libc/arm/aeabi/aeabi_asm_float.S
new file mode 100644
index 0000000..bf32af7
--- /dev/null
+++ b/lib/libc/arm/aeabi/aeabi_asm_float.S
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2014 Andrew Turner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <machine/asm.h>
+__FBSDID("$FreeBSD$");
+
+#define PCR_Z (1 << 30)
+#define PCR_C (1 << 29)
+
+/*
+ * These functions return the result in the CPSR register.
+ *
+ * For __aeabi_cfcmple:
+ * Z C
+ * LT 0 0
+ * EQ 1 1
+ * else 0 1
+ *
+ * __aeabi_cfrcmple is the same as __aeabi_cfcmple, however the arguments
+ * have been swapped.
+ */
+ENTRY(__aeabi_cfcmple)
+ push {r4, r5, ip, lr}
+
+ /* Backup the input registers */
+ mov r4, r0
+ mov r5, r1
+ /* Is it less than? */
+ bl __aeabi_fcmplt
+ cmp r0, #1
+ bne 1f
+ /* Yes, clear Z and C */
+ msr cpsr_c, #(0)
+ b 99f
+
+1:
+ /* Restore the input regsters for the next function call */
+ mov r0, r4
+ mov r1, r5
+ /* Is it equal? */
+ bl __aeabi_fcmpeq
+ cmp r0, #1
+ bne 2f
+ /* Yes, set Z and C */
+ msr cpsr_c, #(PCR_Z | PCR_C)
+ b 99f
+
+2:
+ /* Not less than or equal, set C and clear Z */
+ msr cpsr_c, #(PCR_C)
+
+99:
+ pop {r4, r5, ip, pc}
+END(__aeabi_cfcmple)
+
+ENTRY(__aeabi_cfrcmple)
+ /* Swap the arguments */
+ mov ip, r0
+ mov r0, r1
+ mov r1, ip
+
+ b __aeabi_cfcmple
+END(__aeabi_cfrcmple)
+
+/*
+ * This is just like __aeabi_cfcmple except it will not throw an exception
+ * in the presence of a quiet NaN. If either argument is a signalling NaN we
+ * will still signal.
+ */
+ENTRY(__aeabi_cfcmpeq)
+ /* Check if we can call __aeabi_cfcmple safely */
+ push {r0, r1, r2, lr}
+ bl __aeabi_cfcmpeq_helper
+ cmp r0, #1
+ pop {r0, r1, r2, lr}
+ beq 1f
+
+ bl __aeabi_cfcmple
+ RET
+
+1:
+ msreq cpsr_c, #(PCR_C)
+ RET
+END(__aeabi_cfcmpeq)
diff --git a/lib/libc/arm/aeabi/aeabi_double.c b/lib/libc/arm/aeabi/aeabi_double.c
index 274279d..a69e8a7 100644
--- a/lib/libc/arm/aeabi/aeabi_double.c
+++ b/lib/libc/arm/aeabi/aeabi_double.c
@@ -74,3 +74,28 @@ float64 AEABI_FUNC2(ddiv, float64, float64_div)
float64 AEABI_FUNC2(dmul, float64, float64_mul)
float64 AEABI_FUNC2(dsub, float64, float64_sub)
+int
+__aeabi_cdcmpeq_helper(float64 a, float64 b)
+{
+ int quiet = 0;
+
+ /* Check if a is a NaN */
+ if ((a << 1) > 0xffe0000000000000ull) {
+ /* If it's a signalling NaN we will always signal */
+ if ((a & 0x0008000000000000ull) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ /* Check if b is a NaN */
+ if ((b << 1) > 0xffe0000000000000ull) {
+ /* If it's a signalling NaN we will always signal */
+ if ((b & 0x0008000000000000ull) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ return (quiet);
+}
diff --git a/lib/libc/arm/aeabi/aeabi_float.c b/lib/libc/arm/aeabi/aeabi_float.c
index be7a6d6..2e93594 100644
--- a/lib/libc/arm/aeabi/aeabi_float.c
+++ b/lib/libc/arm/aeabi/aeabi_float.c
@@ -74,3 +74,28 @@ float32 AEABI_FUNC2(fdiv, float32, float32_div)
float32 AEABI_FUNC2(fmul, float32, float32_mul)
float32 AEABI_FUNC2(fsub, float32, float32_sub)
+int
+__aeabi_cfcmpeq_helper(float32 a, float32 b)
+{
+ int quiet = 0;
+
+ /* Check if a is a NaN */
+ if ((a << 1) > 0xff000000u) {
+ /* If it's a signalling NaN we will always signal */
+ if ((a & 0x00400000u) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ /* Check if b is a NaN */
+ if ((b << 1) > 0xff000000u) {
+ /* If it's a signalling NaN we will always signal */
+ if ((b & 0x00400000u) == 0)
+ return (0);
+
+ quiet = 1;
+ }
+
+ return (quiet);
+}
diff --git a/lib/libc/arm/aeabi/aeabi_vfp.h b/lib/libc/arm/aeabi/aeabi_vfp.h
index 76c2ff0..927652f 100644
--- a/lib/libc/arm/aeabi/aeabi_vfp.h
+++ b/lib/libc/arm/aeabi/aeabi_vfp.h
@@ -30,6 +30,8 @@
#ifndef AEABI_VFP_H
#define AEABI_VFP_H
+#include <machine/acle-compat.h>
+
/*
* ASM helper macros. These allow the functions to be changed depending on
* the endian-ness we are building for.
@@ -49,7 +51,7 @@
* point falue. They will load the data from an ARM to a VFP register(s),
* or from a VFP to an ARM register
*/
-#ifdef __ARMEB__
+#ifdef __ARM_BIG_ENDIAN
#define LOAD_DREG(vreg, reg0, reg1) vmov vreg, reg1, reg0
#define UNLOAD_DREG(reg0, reg1, vreg) vmov reg1, reg0, vreg
#else
@@ -65,7 +67,7 @@
* C Helper macros
*/
-#if defined(__FreeBSD_ARCH_armv6__) || (defined(__ARM_ARCH) && __ARM_ARCH >= 6)
+#if __ARM_ARCH >= 6
/*
* Generate a function that will either call into the VFP implementation,
* or the soft float version for a given __aeabi_* helper. The function
diff --git a/lib/libc/arm/aeabi/aeabi_vfp_double.S b/lib/libc/arm/aeabi/aeabi_vfp_double.S
index 842412b..62100d2 100644
--- a/lib/libc/arm/aeabi/aeabi_vfp_double.S
+++ b/lib/libc/arm/aeabi/aeabi_vfp_double.S
@@ -33,6 +33,33 @@ __FBSDID("$FreeBSD$");
.fpu vfp
.syntax unified
+/* void __aeabi_cdcmpeq(double, double) */
+AEABI_ENTRY(cdcmpeq)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmp.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ RET
+AEABI_END(cdcmpeq)
+
+/* void __aeabi_cdcmple(double, double) */
+AEABI_ENTRY(cdcmple)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmpe.f64 d0, d1
+ vmrs APSR_nzcv, fpscr
+ RET
+AEABI_END(cdcmple)
+
+/* void __aeabi_cdrcmple(double, double) */
+AEABI_ENTRY(cdrcmple)
+ LOAD_DREG(d0, r0, r1)
+ LOAD_DREG(d1, r2, r3)
+ vcmpe.f64 d1, d0
+ vmrs APSR_nzcv, fpscr
+ RET
+AEABI_END(cdrcmple)
+
/* int __aeabi_dcmpeq(double, double) */
AEABI_ENTRY(dcmpeq)
LOAD_DREG(d0, r0, r1)
diff --git a/lib/libc/arm/aeabi/aeabi_vfp_float.S b/lib/libc/arm/aeabi/aeabi_vfp_float.S
index d81b2b2..c9a9a7e 100644
--- a/lib/libc/arm/aeabi/aeabi_vfp_float.S
+++ b/lib/libc/arm/aeabi/aeabi_vfp_float.S
@@ -33,6 +33,30 @@ __FBSDID("$FreeBSD$");
.fpu vfp
.syntax unified
+/* void __aeabi_cfcmpeq(float, float) */
+AEABI_ENTRY(cfcmpeq)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmp.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ RET
+AEABI_END(cfcmpeq)
+
+/* void __aeabi_cfcmple(float, float) */
+AEABI_ENTRY(cfcmple)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmpe.f32 s0, s1
+ vmrs APSR_nzcv, fpscr
+ RET
+AEABI_END(cfcmple)
+
+/* void __aeabi_cfrcmple(float, float) */
+AEABI_ENTRY(cfrcmple)
+ LOAD_SREGS(s0, s1, r0, r1)
+ vcmpe.f32 s1, s0
+ vmrs APSR_nzcv, fpscr
+ RET
+AEABI_END(cfrcmple)
+
/* int __aeabi_fcmpeq(float, float) */
AEABI_ENTRY(fcmpeq)
LOAD_SREGS(s0, s1, r0, r1)
diff --git a/lib/libc/arm/gen/Makefile.inc b/lib/libc/arm/gen/Makefile.inc
index 5fd52c2..8efde09 100644
--- a/lib/libc/arm/gen/Makefile.inc
+++ b/lib/libc/arm/gen/Makefile.inc
@@ -6,10 +6,6 @@ SRCS+= _ctx_start.S _setjmp.S _set_tp.c alloca.S fabs.c \
__aeabi_read_tp.S setjmp.S signalcontext.c sigsetjmp.S flt_rounds.c \
arm_initfini.c
-.if ${MK_ARM_EABI} == "no"
-SRCS+= divsi3.S
-.endif
-
.if ${MACHINE_ARCH} == "armv6hf"
SRCS+= fpgetmask_vfp.c fpgetround_vfp.c fpgetsticky_vfp.c fpsetmask_vfp.c \
fpsetround_vfp.c fpsetsticky_vfp.c
diff --git a/lib/libc/arm/gen/__aeabi_read_tp.S b/lib/libc/arm/gen/__aeabi_read_tp.S
index c3ea99d..670d0b8 100644
--- a/lib/libc/arm/gen/__aeabi_read_tp.S
+++ b/lib/libc/arm/gen/__aeabi_read_tp.S
@@ -38,6 +38,7 @@ ENTRY(__aeabi_read_tp)
mrc p15, 0, r0, c13, c0, 3
#endif
RET
+END(__aeabi_read_tp)
#ifdef ARM_TP_ADDRESS
.Larm_tp_address:
diff --git a/lib/libc/arm/gen/_ctx_start.S b/lib/libc/arm/gen/_ctx_start.S
index fbde357..41bfff9 100644
--- a/lib/libc/arm/gen/_ctx_start.S
+++ b/lib/libc/arm/gen/_ctx_start.S
@@ -7,3 +7,4 @@ ENTRY(_ctx_start)
mov r0, r5
bl _C_LABEL(ctx_done)
bl _C_LABEL(abort)
+END(_ctx_start)
diff --git a/lib/libc/arm/gen/_setjmp.S b/lib/libc/arm/gen/_setjmp.S
index b475f1e..387f8a9 100644
--- a/lib/libc/arm/gen/_setjmp.S
+++ b/lib/libc/arm/gen/_setjmp.S
@@ -89,6 +89,7 @@ ENTRY(_setjmp)
mov r0, #0x00000000
RET
+END(_setjmp)
.L_setjmp_magic:
.word _JB_MAGIC__SETJMP
@@ -140,3 +141,4 @@ botch:
#else
b .
#endif
+END(_longjmp)
diff --git a/lib/libc/arm/gen/alloca.S b/lib/libc/arm/gen/alloca.S
index 9569d86..e4a73d4 100644
--- a/lib/libc/arm/gen/alloca.S
+++ b/lib/libc/arm/gen/alloca.S
@@ -43,3 +43,4 @@ ENTRY(alloca)
sub sp, sp, r0 /* Adjust the stack pointer */
mov r0, sp /* r0 = base of new space */
RET
+END(alloca)
diff --git a/lib/libc/arm/gen/divsi3.S b/lib/libc/arm/gen/divsi3.S
index 104a958..82de5de 100644
--- a/lib/libc/arm/gen/divsi3.S
+++ b/lib/libc/arm/gen/divsi3.S
@@ -29,6 +29,7 @@ ENTRY(__umodsi3)
add sp, sp, #4 /* unalign stack */
mov r0, r1
ldmfd sp!, {pc}
+END(__umodsi3)
ENTRY(__modsi3)
stmfd sp!, {lr}
@@ -48,6 +49,7 @@ ENTRY(__modsi3)
mvn r0, #0
#endif
RET
+END(__modsi3)
ENTRY(__udivsi3)
.L_udivide: /* r0 = r0 / r1; r1 = r0 % r1 */
@@ -70,6 +72,7 @@ ENTRY(__udivsi3)
mov r0, r1
mov r1, #0
RET
+END(__udivsi3)
ENTRY(__divsi3)
.L_divide: /* r0 = r0 / r1; r1 = r0 % r1 */
@@ -385,3 +388,4 @@ ENTRY(__divsi3)
addhs r3, r3, r2
mov r0, r3
RET
+END(__divsi3)
diff --git a/lib/libc/arm/gen/setjmp.S b/lib/libc/arm/gen/setjmp.S
index b7af33b..ad4ba38 100644
--- a/lib/libc/arm/gen/setjmp.S
+++ b/lib/libc/arm/gen/setjmp.S
@@ -101,7 +101,7 @@ ENTRY(setjmp)
.Lfpu_present:
.word PIC_SYM(_libc_arm_fpu_present, GOTOFF)
#endif /* __ARM_EABI__ */
-
+END(setjmp)
.weak _C_LABEL(longjmp)
.set _C_LABEL(longjmp), _C_LABEL(__longjmp)
@@ -150,3 +150,4 @@ ENTRY(__longjmp)
bl PIC_SYM(_C_LABEL(longjmperror), PLT)
bl PIC_SYM(_C_LABEL(abort), PLT)
b . - 8 /* Cannot get here */
+END(__longjmp)
diff --git a/lib/libc/arm/gen/sigsetjmp.S b/lib/libc/arm/gen/sigsetjmp.S
index 79f1f9d..3743e89 100644
--- a/lib/libc/arm/gen/sigsetjmp.S
+++ b/lib/libc/arm/gen/sigsetjmp.S
@@ -51,6 +51,7 @@ ENTRY(sigsetjmp)
teq r1, #0
beq PIC_SYM(_C_LABEL(_setjmp), PLT)
b PIC_SYM(_C_LABEL(setjmp), PLT)
+END(sigsetjmp)
.L_setjmp_magic:
.word _JB_MAGIC__SETJMP
@@ -64,3 +65,4 @@ ENTRY(siglongjmp)
teq r2, r3 /* magic correct? */
beq PIC_SYM(_C_LABEL(_longjmp), PLT)
b PIC_SYM(_C_LABEL(longjmp), PLT)
+END(siglongjmp)
diff --git a/lib/libc/arm/string/ffs.S b/lib/libc/arm/string/ffs.S
index af4e118..d3684ed 100644
--- a/lib/libc/arm/string/ffs.S
+++ b/lib/libc/arm/string/ffs.S
@@ -80,3 +80,4 @@ ENTRY(ffs)
rsbne r0, r0, #32
RET
#endif
+END(ffs)
diff --git a/lib/libc/arm/string/memcmp.S b/lib/libc/arm/string/memcmp.S
index a81c960..63a00ef 100644
--- a/lib/libc/arm/string/memcmp.S
+++ b/lib/libc/arm/string/memcmp.S
@@ -178,3 +178,4 @@ ENTRY(memcmp)
sub r0, r3, r2 /* r0 = b1#5 - b2#5 */
RET
#endif
+END(memcmp)
diff --git a/lib/libc/arm/string/memcpy_arm.S b/lib/libc/arm/string/memcpy_arm.S
index b84a32e..eff1eb0 100644
--- a/lib/libc/arm/string/memcpy_arm.S
+++ b/lib/libc/arm/string/memcpy_arm.S
@@ -330,3 +330,4 @@ ENTRY(memcpy)
.Lmemcpy_srcul3l4:
sub r1, r1, #1
b .Lmemcpy_l4
+END(memcpy)
diff --git a/lib/libc/arm/string/memcpy_xscale.S b/lib/libc/arm/string/memcpy_xscale.S
index 02cca5e..1f48cd9 100644
--- a/lib/libc/arm/string/memcpy_xscale.S
+++ b/lib/libc/arm/string/memcpy_xscale.S
@@ -1781,3 +1781,4 @@ ENTRY(memcpy)
strb r1, [r0, #0x0b]
bx lr
#endif /* !_STANDALONE */
+END(memcpy)
diff --git a/lib/libc/arm/string/memmove.S b/lib/libc/arm/string/memmove.S
index 8b8baaf..75a2744 100644
--- a/lib/libc/arm/string/memmove.S
+++ b/lib/libc/arm/string/memmove.S
@@ -580,3 +580,8 @@ ENTRY(bcopy)
.Lmemmove_bsrcul1l4:
add r1, r1, #1
b .Lmemmove_bl4
+#ifndef _BCOPY
+END(memmove)
+#else
+END(bcopy)
+#endif
diff --git a/lib/libc/arm/string/memset.S b/lib/libc/arm/string/memset.S
index 5387aab..458f8f7 100644
--- a/lib/libc/arm/string/memset.S
+++ b/lib/libc/arm/string/memset.S
@@ -234,3 +234,8 @@ ENTRY(memset)
strgeb r3, [ip], #0x01 /* Set another byte */
strgtb r3, [ip] /* and a third */
RET /* Exit */
+#ifdef _BZERO
+END(bzero)
+#else
+END(memset)
+#endif
diff --git a/lib/libc/arm/string/strcmp.S b/lib/libc/arm/string/strcmp.S
index e5cba7d..3dd7453 100644
--- a/lib/libc/arm/string/strcmp.S
+++ b/lib/libc/arm/string/strcmp.S
@@ -41,3 +41,4 @@ ENTRY(strcmp)
beq 1b
sub r0, r2, r3
RET
+END(strcmp)
diff --git a/lib/libc/arm/string/strlen.S b/lib/libc/arm/string/strlen.S
index 378257d..3d7726f 100644
--- a/lib/libc/arm/string/strlen.S
+++ b/lib/libc/arm/string/strlen.S
@@ -76,3 +76,4 @@ ENTRY(strlen)
.Lexit:
mov r0, r1
RET
+END(strlen)
diff --git a/lib/libc/arm/string/strncmp.S b/lib/libc/arm/string/strncmp.S
index fce0159..ac59deb 100644
--- a/lib/libc/arm/string/strncmp.S
+++ b/lib/libc/arm/string/strncmp.S
@@ -52,3 +52,4 @@ ENTRY(strncmp)
beq 1b
sub r0, r2, r3
RET
+END(strncmp)
diff --git a/lib/libc/arm/sys/Ovfork.S b/lib/libc/arm/sys/Ovfork.S
index 286347e..4520e02 100644
--- a/lib/libc/arm/sys/Ovfork.S
+++ b/lib/libc/arm/sys/Ovfork.S
@@ -52,3 +52,4 @@ ENTRY(vfork)
sub r1, r1, #1 /* r1 == 0xffffffff if parent, 0 if child */
and r0, r0, r1 /* r0 == 0 if child, else unchanged */
mov r15, r2
+END(vfork)
diff --git a/lib/libc/arm/sys/brk.S b/lib/libc/arm/sys/brk.S
index 5fdf90c..f3d8d87 100644
--- a/lib/libc/arm/sys/brk.S
+++ b/lib/libc/arm/sys/brk.S
@@ -98,3 +98,4 @@ ENTRY(_brk)
.word PIC_SYM(_C_LABEL(minbrk), GOT)
.Lcurbrk:
.word PIC_SYM(CURBRK, GOT)
+END(_brk)
diff --git a/lib/libc/arm/sys/cerror.S b/lib/libc/arm/sys/cerror.S
index e807285..26f5211 100644
--- a/lib/libc/arm/sys/cerror.S
+++ b/lib/libc/arm/sys/cerror.S
@@ -46,3 +46,4 @@ ASENTRY(CERROR)
mvn r0, #0x00000000
mvn r1, #0x00000000
ldmfd sp!, {r4, pc}
+END(CERROR)
diff --git a/lib/libc/arm/sys/pipe.S b/lib/libc/arm/sys/pipe.S
index 83518fc2..77ce0fc 100644
--- a/lib/libc/arm/sys/pipe.S
+++ b/lib/libc/arm/sys/pipe.S
@@ -48,3 +48,4 @@ ENTRY(_pipe)
str r1, [r2, #0x0004]
mov r0, #0x00000000
RET
+END(_pipe)
diff --git a/lib/libc/arm/sys/ptrace.S b/lib/libc/arm/sys/ptrace.S
index 3cc13f3..876da32 100644
--- a/lib/libc/arm/sys/ptrace.S
+++ b/lib/libc/arm/sys/ptrace.S
@@ -46,3 +46,4 @@ ENTRY(ptrace)
SYSTRAP(ptrace)
bcs PIC_SYM(CERROR, PLT)
RET
+END(ptrace)
diff --git a/lib/libc/arm/sys/sbrk.S b/lib/libc/arm/sys/sbrk.S
index d76e85a..7d22aa7 100644
--- a/lib/libc/arm/sys/sbrk.S
+++ b/lib/libc/arm/sys/sbrk.S
@@ -86,3 +86,4 @@ ENTRY(_sbrk)
#endif
.Lcurbrk:
.word PIC_SYM(CURBRK, GOT)
+END(_sbrk)
diff --git a/lib/libc/gen/dl_iterate_phdr.3 b/lib/libc/gen/dl_iterate_phdr.3
index 5b8afc6..6e952dc 100644
--- a/lib/libc/gen/dl_iterate_phdr.3
+++ b/lib/libc/gen/dl_iterate_phdr.3
@@ -15,7 +15,7 @@
.\"
.\" $OpenBSD: dl_iterate_phdr.3,v 1.3 2007/05/31 19:19:48 jmc Exp $
.\" $FreeBSD$
-.Dd February 15, 2012
+.Dd October 9, 2014
.Dt DL_ITERATE_PHDR 3
.Os
.Sh NAME
@@ -68,7 +68,7 @@ have the following meaning:
The base address at which the object is mapped into the address
space of the calling process.
.It Fa dlpi_name
-The name of the ELF object.
+The pathname of the ELF object.
.It Fa dlpi_phdr
A pointer to the object's program headers.
.It Fa dlpi_phnum
diff --git a/lib/libc/gen/getgrouplist.3 b/lib/libc/gen/getgrouplist.3
index 44d95f5..b0e116f 100644
--- a/lib/libc/gen/getgrouplist.3
+++ b/lib/libc/gen/getgrouplist.3
@@ -28,7 +28,7 @@
.\" @(#)getgrouplist.3 8.1 (Berkeley) 6/9/93
.\" $FreeBSD$
.\"
-.Dd February 20, 2012
+.Dd October 26, 2014
.Dt GETGROUPLIST 3
.Os
.Sh NAME
@@ -80,13 +80,3 @@ The
.Fn getgrouplist
function first appeared in
.Bx 4.4 .
-.Sh BUGS
-The
-.Fn getgrouplist
-function
-uses the routines based on
-.Xr getgrent 3 .
-If the invoking program uses any of these routines,
-the group structure will
-be overwritten in the call to
-.Fn getgrouplist .
diff --git a/lib/libc/gen/initgroups.3 b/lib/libc/gen/initgroups.3
index 3ed3ca7..b0b68f2 100644
--- a/lib/libc/gen/initgroups.3
+++ b/lib/libc/gen/initgroups.3
@@ -28,7 +28,7 @@
.\" @(#)initgroups.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd June 4, 1993
+.Dd October 26, 2014
.Dt INITGROUPS 3
.Os
.Sh NAME
@@ -80,14 +80,3 @@ The
.Fn initgroups
function appeared in
.Bx 4.2 .
-.Sh BUGS
-The
-.Fn getgrouplist
-function called by
-.Fn initgroups
-uses the routines based on
-.Xr getgrent 3 .
-If the invoking program uses any of these routines,
-the group structure will
-be overwritten in the call to
-.Fn initgroups .
diff --git a/lib/libc/gen/nlist.c b/lib/libc/gen/nlist.c
index 159731c..bdadd55 100644
--- a/lib/libc/gen/nlist.c
+++ b/lib/libc/gen/nlist.c
@@ -268,7 +268,7 @@ __elf_fdnlist(fd, list)
}
/* mmap section header table */
- base = mmap(NULL, (size_t)shdr_size, PROT_READ, 0, fd,
+ base = mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_PRIVATE, fd,
(off_t)ehdr.e_shoff);
if (base == MAP_FAILED)
return (-1);
@@ -301,7 +301,7 @@ __elf_fdnlist(fd, list)
* making the memory allocation permanent as with malloc/free
* (i.e., munmap will return it to the system).
*/
- base = mmap(NULL, (size_t)symstrsize, PROT_READ, 0, fd,
+ base = mmap(NULL, (size_t)symstrsize, PROT_READ, MAP_PRIVATE, fd,
(off_t)symstroff);
if (base == MAP_FAILED)
goto done;
diff --git a/lib/libc/gen/posix_spawnattr_init.3 b/lib/libc/gen/posix_spawnattr_init.3
index 19d29a6..388fe5a 100644
--- a/lib/libc/gen/posix_spawnattr_init.3
+++ b/lib/libc/gen/posix_spawnattr_init.3
@@ -100,7 +100,7 @@ The
function will fail if:
.Bl -tag -width Er
.It Bq Er ENOMEM
-Insufficient memory exists to initialize the spawn file actions object.
+Insufficient memory exists to initialize the spawn attributes object.
.El
.Sh SEE ALSO
.Xr posix_spawn 3 ,
diff --git a/lib/libc/gen/rewinddir.c b/lib/libc/gen/rewinddir.c
index 89e717c..193f4b0 100644
--- a/lib/libc/gen/rewinddir.c
+++ b/lib/libc/gen/rewinddir.c
@@ -53,7 +53,7 @@ rewinddir(dirp)
_pthread_mutex_lock(&dirp->dd_lock);
if (dirp->dd_flags & __DTF_READALL)
_filldir(dirp, false);
- else if (dirp->dd_seek != 0) {
+ else {
(void) lseek(dirp->dd_fd, 0, SEEK_SET);
dirp->dd_seek = 0;
}
diff --git a/lib/libc/gen/sem_destroy.3 b/lib/libc/gen/sem_destroy.3
index f488b4e..b437420 100644
--- a/lib/libc/gen/sem_destroy.3
+++ b/lib/libc/gen/sem_destroy.3
@@ -67,8 +67,7 @@ There are currently threads blocked on the semaphore that
points to.
.El
.Sh SEE ALSO
-.Xr sem_init 3 ,
-.Xr sem 4
+.Xr sem_init 3
.Sh STANDARDS
The
.Fn sem_destroy
diff --git a/lib/libc/gen/sem_getvalue.3 b/lib/libc/gen/sem_getvalue.3
index a8dd177..d81c2b1 100644
--- a/lib/libc/gen/sem_getvalue.3
+++ b/lib/libc/gen/sem_getvalue.3
@@ -65,8 +65,7 @@ points to an invalid semaphore.
.Sh SEE ALSO
.Xr sem_post 3 ,
.Xr sem_trywait 3 ,
-.Xr sem_wait 3 ,
-.Xr sem 4
+.Xr sem_wait 3
.Sh STANDARDS
The
.Fn sem_getvalue
diff --git a/lib/libc/gen/sem_init.3 b/lib/libc/gen/sem_init.3
index 52bcb75..a96749b 100644
--- a/lib/libc/gen/sem_init.3
+++ b/lib/libc/gen/sem_init.3
@@ -93,8 +93,7 @@ Memory allocation error.
.Xr sem_getvalue 3 ,
.Xr sem_post 3 ,
.Xr sem_trywait 3 ,
-.Xr sem_wait 3 ,
-.Xr sem 4
+.Xr sem_wait 3
.Sh STANDARDS
The
.Fn sem_init
diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c
index ec1a2fd..3ee0272 100644
--- a/lib/libc/gen/sem_new.c
+++ b/lib/libc/gen/sem_new.c
@@ -61,7 +61,9 @@ __weak_reference(_sem_unlink, sem_unlink);
__weak_reference(_sem_wait, sem_wait);
#define SEM_PREFIX "/tmp/SEMD"
-#define SEM_MAGIC ((u_int32_t)0x73656d31)
+#define SEM_MAGIC ((u_int32_t)0x73656d32)
+
+_Static_assert(SEM_VALUE_MAX <= USEM_MAX_COUNT, "SEM_VALUE_MAX too large");
struct sem_nameinfo {
int open_count;
@@ -131,7 +133,6 @@ _sem_init(sem_t *sem, int pshared, unsigned int value)
bzero(sem, sizeof(sem_t));
sem->_magic = SEM_MAGIC;
sem->_kern._count = (u_int32_t)value;
- sem->_kern._has_waiters = 0;
sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0;
return (0);
}
@@ -212,7 +213,6 @@ _sem_open(const char *name, int flags, ...)
sem_t tmp;
tmp._magic = SEM_MAGIC;
- tmp._kern._has_waiters = 0;
tmp._kern._count = value;
tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED;
if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp))
@@ -332,18 +332,18 @@ _sem_getvalue(sem_t * __restrict sem, int * __restrict sval)
if (sem_check_validity(sem) != 0)
return (-1);
- *sval = (int)sem->_kern._count;
+ *sval = (int)USEM_COUNT(sem->_kern._count);
return (0);
}
static __inline int
-usem_wake(struct _usem *sem)
+usem_wake(struct _usem2 *sem)
{
- return _umtx_op(sem, UMTX_OP_SEM_WAKE, 0, NULL, NULL);
+ return _umtx_op(sem, UMTX_OP_SEM2_WAKE, 0, NULL, NULL);
}
static __inline int
-usem_wait(struct _usem *sem, const struct timespec *abstime)
+usem_wait(struct _usem2 *sem, const struct timespec *abstime)
{
struct _umtx_time *tm_p, timeout;
size_t tm_size;
@@ -358,7 +358,7 @@ usem_wait(struct _usem *sem, const struct timespec *abstime)
tm_p = &timeout;
tm_size = sizeof(timeout);
}
- return _umtx_op(sem, UMTX_OP_SEM_WAIT, 0,
+ return _umtx_op(sem, UMTX_OP_SEM2_WAIT, 0,
(void *)tm_size, __DECONST(void*, tm_p));
}
@@ -370,7 +370,7 @@ _sem_trywait(sem_t *sem)
if (sem_check_validity(sem) != 0)
return (-1);
- while ((val = sem->_kern._count) > 0) {
+ while (USEM_COUNT(val = sem->_kern._count) > 0) {
if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
return (0);
}
@@ -390,7 +390,7 @@ _sem_timedwait(sem_t * __restrict sem,
retval = 0;
_pthread_testcancel();
for (;;) {
- while ((val = sem->_kern._count) > 0) {
+ while (USEM_COUNT(val = sem->_kern._count) > 0) {
if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1))
return (0);
}
@@ -439,9 +439,10 @@ _sem_post(sem_t *sem)
do {
count = sem->_kern._count;
- if (count + 1 > SEM_VALUE_MAX)
+ if (USEM_COUNT(count) + 1 > SEM_VALUE_MAX)
return (EOVERFLOW);
- } while(!atomic_cmpset_rel_int(&sem->_kern._count, count, count+1));
- (void)usem_wake(&sem->_kern);
+ } while (!atomic_cmpset_rel_int(&sem->_kern._count, count, count + 1));
+ if (count & USEM_HAS_WAITERS)
+ usem_wake(&sem->_kern);
return (0);
}
diff --git a/lib/libc/gen/sem_open.3 b/lib/libc/gen/sem_open.3
index 3527605..2fdc019 100644
--- a/lib/libc/gen/sem_open.3
+++ b/lib/libc/gen/sem_open.3
@@ -210,8 +210,7 @@ The named semaphore does not exist.
.Xr sem_getvalue 3 ,
.Xr sem_post 3 ,
.Xr sem_trywait 3 ,
-.Xr sem_wait 3 ,
-.Xr sem 4
+.Xr sem_wait 3
.Sh STANDARDS
The
.Fn sem_open ,
diff --git a/lib/libc/gen/sem_post.3 b/lib/libc/gen/sem_post.3
index 67559cc..485d2fc 100644
--- a/lib/libc/gen/sem_post.3
+++ b/lib/libc/gen/sem_post.3
@@ -69,8 +69,7 @@ points to an invalid semaphore.
.Sh SEE ALSO
.Xr sem_getvalue 3 ,
.Xr sem_trywait 3 ,
-.Xr sem_wait 3 ,
-.Xr sem 4
+.Xr sem_wait 3
.Sh STANDARDS
The
.Fn sem_post
diff --git a/lib/libc/gen/sem_timedwait.3 b/lib/libc/gen/sem_timedwait.3
index 3a58d41..254af60 100644
--- a/lib/libc/gen/sem_timedwait.3
+++ b/lib/libc/gen/sem_timedwait.3
@@ -108,8 +108,7 @@ A signal interrupted this function.
.Sh SEE ALSO
.Xr sem_post 3 ,
.Xr sem_trywait 3 ,
-.Xr sem_wait 3 ,
-.Xr sem 4
+.Xr sem_wait 3
.Sh STANDARDS
The
.Fn sem_timedwait
diff --git a/lib/libc/gen/sem_wait.3 b/lib/libc/gen/sem_wait.3
index 9de8ba8..cb5a2f6 100644
--- a/lib/libc/gen/sem_wait.3
+++ b/lib/libc/gen/sem_wait.3
@@ -92,8 +92,7 @@ The semaphore value was zero, and thus could not be decremented.
.Sh SEE ALSO
.Xr sem_getvalue 3 ,
.Xr sem_post 3 ,
-.Xr sem_timedwait 3 ,
-.Xr sem 4
+.Xr sem_timedwait 3
.Sh STANDARDS
The
.Fn sem_wait
diff --git a/lib/libc/iconv/iconv.3 b/lib/libc/iconv/iconv.3
index 939d442..6692c47 100644
--- a/lib/libc/iconv/iconv.3
+++ b/lib/libc/iconv/iconv.3
@@ -26,7 +26,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd June 16, 2010
+.Dd August 4, 2014
.Dt ICONV 3
.Os
.Sh NAME
@@ -285,7 +285,11 @@ terminates with an incomplete character or shift sequence.
.Sh SEE ALSO
.Xr iconv 1 ,
.Xr mkcsmapper 1 ,
-.Xr mkesdb 1
+.Xr mkesdb 1 ,
+.Xr __iconv_get_list 3 ,
+.Xr iconv_canonicalize 3 ,
+.Xr iconvctl 3 ,
+.Xr iconvlist 3
.Sh STANDARDS
The
.Fn iconv_open ,
diff --git a/lib/libc/include/isc/eventlib.h b/lib/libc/include/isc/eventlib.h
index 5003823..a4cfdf9 100644
--- a/lib/libc/include/isc/eventlib.h
+++ b/lib/libc/include/isc/eventlib.h
@@ -1,24 +1,24 @@
/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Copyright (c) 1995-1999 by Internet Software Consortium
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1995-1999, 2001, 2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
*/
/* eventlib.h - exported interfaces for eventlib
* vix 09sep95 [initial]
*
- * $Id: eventlib.h,v 1.3.18.3 2008/01/23 02:12:01 marka Exp $
+ * $Id: eventlib.h,v 1.7 2008/11/14 02:36:51 marka Exp $
*/
#ifndef _EVENTLIB_H
diff --git a/lib/libc/include/isc/list.h b/lib/libc/include/isc/list.h
index fef631b..ffd0c51 100644
--- a/lib/libc/include/isc/list.h
+++ b/lib/libc/include/isc/list.h
@@ -38,7 +38,8 @@
} while (0)
#define INIT_LINK(elt, link) \
INIT_LINK_TYPE(elt, link, void)
-#define LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1))
+#define LINKED(elt, link) ((void *)((elt)->link.prev) != (void *)(-1) && \
+ (void *)((elt)->link.next) != (void *)(-1))
#define HEAD(list) ((list).head)
#define TAIL(list) ((list).tail)
diff --git a/lib/libc/include/port_before.h b/lib/libc/include/port_before.h
index 9e7525b..430d233 100644
--- a/lib/libc/include/port_before.h
+++ b/lib/libc/include/port_before.h
@@ -6,6 +6,7 @@
#define _LIBC 1
#define DO_PTHREADS 1
#define USE_POLL 1
+#define HAVE_MD5 1
#define ISC_SOCKLEN_T socklen_t
#define ISC_FORMAT_PRINTF(fmt, args) \
diff --git a/lib/libc/inet/inet_addr.c b/lib/libc/inet/inet_addr.c
index e606d34..9744fb6 100644
--- a/lib/libc/inet/inet_addr.c
+++ b/lib/libc/inet/inet_addr.c
@@ -66,7 +66,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93";
-static const char rcsid[] = "$Id: inet_addr.c,v 1.4.18.1 2005/04/27 05:00:52 sra Exp $";
+static const char rcsid[] = "$Id: inet_addr.c,v 1.5 2005/04/27 04:56:19 sra Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/inet_cidr_ntop.c b/lib/libc/inet/inet_cidr_ntop.c
index 645b3cd..33d8ea1 100644
--- a/lib/libc/inet/inet_cidr_ntop.c
+++ b/lib/libc/inet/inet_cidr_ntop.c
@@ -16,8 +16,10 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.4.18.3 2006/10/11 02:32:47 marka Exp $";
+static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
diff --git a/lib/libc/inet/inet_cidr_pton.c b/lib/libc/inet/inet_cidr_pton.c
index b0586ff..a6a5c7d 100644
--- a/lib/libc/inet/inet_cidr_pton.c
+++ b/lib/libc/inet/inet_cidr_pton.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.5.18.1 2005/04/27 05:00:53 sra Exp $";
+static const char rcsid[] = "$Id: inet_cidr_pton.c,v 1.6 2005/04/27 04:56:19 sra Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/inet_net_ntop.c b/lib/libc/inet/inet_net_ntop.c
index 867f441..da7af33 100644
--- a/lib/libc/inet/inet_net_ntop.c
+++ b/lib/libc/inet/inet_net_ntop.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.3.18.2 2006/06/20 02:51:32 marka Exp $";
+static const char rcsid[] = "$Id: inet_net_ntop.c,v 1.5 2006/06/20 02:50:14 marka Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/inet_net_pton.c b/lib/libc/inet/inet_net_pton.c
index 74df38b9..fa18759 100644
--- a/lib/libc/inet/inet_net_pton.c
+++ b/lib/libc/inet/inet_net_pton.c
@@ -1,22 +1,22 @@
/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Copyright (c) 1996,1999 by Internet Software Consortium.
+ * Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Copyright (C) 1996, 1998, 1999, 2001, 2003 Internet Software Consortium.
*
- * Permission to use, copy, modify, and distribute this software for any
+ * Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_net_pton.c,v 1.7.18.2 2008/08/26 04:42:43 marka Exp $";
+static const char rcsid[] = "$Id: inet_net_pton.c,v 1.10 2008/11/14 02:36:51 marka Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/inet_neta.c b/lib/libc/inet/inet_neta.c
index 72ac549..01ad3be 100644
--- a/lib/libc/inet/inet_neta.c
+++ b/lib/libc/inet/inet_neta.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_neta.c,v 1.2.18.1 2005/04/27 05:00:53 sra Exp $";
+static const char rcsid[] = "$Id: inet_neta.c,v 1.3 2005/04/27 04:56:20 sra Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/inet_ntoa.c b/lib/libc/inet/inet_ntoa.c
index f5d69fa..d8afd0d 100644
--- a/lib/libc/inet/inet_ntoa.c
+++ b/lib/libc/inet/inet_ntoa.c
@@ -29,7 +29,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)inet_ntoa.c 8.1 (Berkeley) 6/4/93";
-static const char rcsid[] = "$Id: inet_ntoa.c,v 1.1.352.1 2005/04/27 05:00:54 sra Exp $";
+static const char rcsid[] = "$Id: inet_ntoa.c,v 1.2 2005/04/27 04:56:21 sra Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/inet_ntop.c b/lib/libc/inet/inet_ntop.c
index d57e6ab..ac5ebc4 100644
--- a/lib/libc/inet/inet_ntop.c
+++ b/lib/libc/inet/inet_ntop.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_ntop.c,v 1.3.18.2 2005/11/03 23:02:22 marka Exp $";
+static const char rcsid[] = "$Id: inet_ntop.c,v 1.5 2005/11/03 22:59:52 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/inet_pton.c b/lib/libc/inet/inet_pton.c
index ae65099..04b515f 100644
--- a/lib/libc/inet/inet_pton.c
+++ b/lib/libc/inet/inet_pton.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: inet_pton.c,v 1.3.18.2 2005/07/28 07:38:07 marka Exp $";
+static const char rcsid[] = "$Id: inet_pton.c,v 1.5 2005/07/28 06:51:47 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/inet/nsap_addr.c b/lib/libc/inet/nsap_addr.c
index 2947472..af0180f 100644
--- a/lib/libc/inet/nsap_addr.c
+++ b/lib/libc/inet/nsap_addr.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: nsap_addr.c,v 1.3.18.2 2005/07/28 07:38:08 marka Exp $";
+static const char rcsid[] = "$Id: nsap_addr.c,v 1.5 2005/07/28 06:51:48 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/isc/ev_streams.c b/lib/libc/isc/ev_streams.c
index 06bdfad..1854350 100644
--- a/lib/libc/isc/ev_streams.c
+++ b/lib/libc/isc/ev_streams.c
@@ -20,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: ev_streams.c,v 1.4.18.1 2005/04/27 05:01:06 sra Exp $";
+static const char rcsid[] = "$Id: ev_streams.c,v 1.5 2005/04/27 04:56:36 sra Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/isc/ev_timers.c b/lib/libc/isc/ev_timers.c
index 66fc186..7c25c67 100644
--- a/lib/libc/isc/ev_timers.c
+++ b/lib/libc/isc/ev_timers.c
@@ -20,7 +20,7 @@
*/
#if !defined(LINT) && !defined(CODECENTER)
-static const char rcsid[] = "$Id: ev_timers.c,v 1.5.18.1 2005/04/27 05:01:06 sra Exp $";
+static const char rcsid[] = "$Id: ev_timers.c,v 1.6 2005/04/27 04:56:36 sra Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/isc/eventlib_p.h b/lib/libc/isc/eventlib_p.h
index 951af00..8620aeb 100644
--- a/lib/libc/isc/eventlib_p.h
+++ b/lib/libc/isc/eventlib_p.h
@@ -19,7 +19,7 @@
* \brief private interfaces for eventlib
* \author vix 09sep95 [initial]
*
- * $Id: eventlib_p.h,v 1.5.18.4 2006/03/10 00:20:08 marka Exp $
+ * $Id: eventlib_p.h,v 1.9 2006/03/09 23:57:56 marka Exp $
* $FreeBSD$
*/
diff --git a/lib/libc/locale/lmonetary.c b/lib/libc/locale/lmonetary.c
index a9d67d3..84eccdb 100644
--- a/lib/libc/locale/lmonetary.c
+++ b/lib/libc/locale/lmonetary.c
@@ -192,7 +192,7 @@ printf( "int_curr_symbol = %s\n"
"n_cs_precedes = %d\n"
"n_sep_by_space = %d\n"
"p_sign_posn = %d\n"
- "n_sign_posn = %d\n",
+ "n_sign_posn = %d\n"
"int_p_cs_precedes = %d\n"
"int_p_sep_by_space = %d\n"
"int_n_cs_precedes = %d\n"
diff --git a/lib/libc/md/Makefile.inc b/lib/libc/md/Makefile.inc
new file mode 100644
index 0000000..338f64d
--- /dev/null
+++ b/lib/libc/md/Makefile.inc
@@ -0,0 +1,5 @@
+# $FreeBSD$
+
+.PATH: ${LIBC_SRCTOP}/../libmd
+
+SRCS+= md5c.c
diff --git a/lib/libc/nameser/Symbol.map b/lib/libc/nameser/Symbol.map
index 190a59f..2c4b76e 100644
--- a/lib/libc/nameser/Symbol.map
+++ b/lib/libc/nameser/Symbol.map
@@ -29,3 +29,24 @@ FBSD_1.0 {
__ns_format_ttl;
__ns_parse_ttl;
};
+
+FBSD_1.4 {
+ __ns_parserr2;
+ __ns_name_pton2;
+ __ns_name_unpack2;
+ __ns_name_length;
+ __ns_name_eq;
+ __ns_name_owned;
+ __ns_name_map;
+ __ns_name_labels;
+ __ns_newmsg_init;
+ __ns_newmsg_copy;
+ __ns_newmsg_id;
+ __ns_newmsg_flag;
+ __ns_newmsg_q;
+ __ns_newmsg_rr;
+ __ns_newmsg_done;
+ __ns_rdata_unpack;
+ __ns_rdata_equal;
+ __ns_rdata_refers;
+};
diff --git a/lib/libc/nameser/ns_name.c b/lib/libc/nameser/ns_name.c
index 31dee36..5b8a8cb 100644
--- a/lib/libc/nameser/ns_name.c
+++ b/lib/libc/nameser/ns_name.c
@@ -16,8 +16,10 @@
*/
#ifndef lint
-static const char rcsid[] = "$Id: ns_name.c,v 1.8.18.2 2005/04/27 05:01:08 sra Exp $";
+static const char rcsid[] = "$Id: ns_name.c,v 1.11 2009/01/23 19:59:16 each Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
#include "port_before.h"
@@ -121,7 +123,7 @@ ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
}
if ((l = labellen(cp - 1)) < 0) {
errno = EMSGSIZE; /*%< XXX */
- return(-1);
+ return (-1);
}
if (dn + l >= eom) {
errno = EMSGSIZE;
@@ -133,12 +135,12 @@ ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
if (n != DNS_LABELTYPE_BITSTRING) {
/* XXX: labellen should reject this case */
errno = EINVAL;
- return(-1);
+ return (-1);
}
if ((m = decode_bitstring(&cp, dn, eom)) < 0)
{
errno = EMSGSIZE;
- return(-1);
+ return (-1);
}
dn += m;
continue;
@@ -197,10 +199,25 @@ ns_name_ntop(const u_char *src, char *dst, size_t dstsiz)
* notes:
*\li Enforces label and domain length limits.
*/
+int
+ns_name_pton(const char *src, u_char *dst, size_t dstsiz) {
+ return (ns_name_pton2(src, dst, dstsiz, NULL));
+}
+/*
+ * ns_name_pton2(src, dst, dstsiz, *dstlen)
+ * Convert a ascii string into an encoded domain name as per RFC1035.
+ * return:
+ * -1 if it fails
+ * 1 if string was fully qualified
+ * 0 is string was not fully qualified
+ * side effects:
+ * fills in *dstlen (if non-NULL)
+ * notes:
+ * Enforces label and domain length limits.
+ */
int
-ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
-{
+ns_name_pton2(const char *src, u_char *dst, size_t dstsiz, size_t *dstlen) {
u_char *label, *bp, *eom;
int c, n, escaped, e = 0;
char *cp;
@@ -215,13 +232,13 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
if (c == '[') { /*%< start a bit string label */
if ((cp = strchr(src, ']')) == NULL) {
errno = EINVAL; /*%< ??? */
- return(-1);
+ return (-1);
}
if ((e = encode_bitsring(&src, cp + 2,
&label, &bp, eom))
!= 0) {
errno = e;
- return(-1);
+ return (-1);
}
escaped = 0;
label = bp++;
@@ -229,7 +246,7 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
goto done;
else if (c != '.') {
errno = EINVAL;
- return(-1);
+ return (-1);
}
continue;
}
@@ -281,6 +298,8 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
errno = EMSGSIZE;
return (-1);
}
+ if (dstlen != NULL)
+ *dstlen = (bp - dst);
return (1);
}
if (c == 0 || *src == '.') {
@@ -318,6 +337,8 @@ ns_name_pton(const char *src, u_char *dst, size_t dstsiz)
errno = EMSGSIZE;
return (-1);
}
+ if (dstlen != NULL)
+ *dstlen = (bp - dst);
return (0);
}
@@ -365,7 +386,7 @@ ns_name_ntol(const u_char *src, u_char *dst, size_t dstsiz)
}
for ((void)NULL; l > 0; l--) {
c = *cp++;
- if (isupper(c))
+ if (isascii(c) && isupper(c))
*dn++ = tolower(c);
else
*dn++ = c;
@@ -385,6 +406,21 @@ int
ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
u_char *dst, size_t dstsiz)
{
+ return (ns_name_unpack2(msg, eom, src, dst, dstsiz, NULL));
+}
+
+/*
+ * ns_name_unpack2(msg, eom, src, dst, dstsiz, *dstlen)
+ * Unpack a domain name from a message, source may be compressed.
+ * return:
+ * -1 if it fails, or consumed octets if it succeeds.
+ * side effect:
+ * fills in *dstlen (if non-NULL).
+ */
+int
+ns_name_unpack2(const u_char *msg, const u_char *eom, const u_char *src,
+ u_char *dst, size_t dstsiz, size_t *dstlen)
+{
const u_char *srcp, *dstlim;
u_char *dstp;
int n, len, checked, l;
@@ -407,7 +443,7 @@ ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
/* Limit checks. */
if ((l = labellen(srcp - 1)) < 0) {
errno = EMSGSIZE;
- return(-1);
+ return (-1);
}
if (dstp + l + 1 >= dstlim || srcp + l >= eom) {
errno = EMSGSIZE;
@@ -427,11 +463,12 @@ ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
}
if (len < 0)
len = srcp - src + 1;
- srcp = msg + (((n & 0x3f) << 8) | (*srcp & 0xff));
- if (srcp < msg || srcp >= eom) { /*%< Out of range. */
+ l = ((n & 0x3f) << 8) | (*srcp & 0xff);
+ if (l >= eom - msg) { /*%< Out of range. */
errno = EMSGSIZE;
return (-1);
}
+ srcp = msg + l;
checked += 2;
/*
* Check for loops in the compressed name;
@@ -449,7 +486,9 @@ ns_name_unpack(const u_char *msg, const u_char *eom, const u_char *src,
return (-1); /*%< flag error */
}
}
- *dstp = '\0';
+ *dstp++ = 0;
+ if (dstlen != NULL)
+ *dstlen = dstp - dst;
if (len < 0)
len = srcp - src;
return (len);
@@ -508,7 +547,7 @@ ns_name_pack(const u_char *src, u_char *dst, int dstsiz,
}
if ((l0 = labellen(srcp)) < 0) {
errno = EINVAL;
- return(-1);
+ return (-1);
}
l += l0 + 1;
if (l > MAXCDNAME) {
@@ -655,7 +694,7 @@ ns_name_skip(const u_char **ptrptr, const u_char *eom)
case NS_TYPE_ELT: /*%< EDNS0 extended label */
if ((l = labellen(cp - 1)) < 0) {
errno = EMSGSIZE; /*%< XXX */
- return(-1);
+ return (-1);
}
cp += l;
continue;
@@ -676,6 +715,150 @@ ns_name_skip(const u_char **ptrptr, const u_char *eom)
return (0);
}
+/* Find the number of octets an nname takes up, including the root label.
+ * (This is basically ns_name_skip() without compression-pointer support.)
+ * ((NOTE: can only return zero if passed-in namesiz argument is zero.))
+ */
+ssize_t
+ns_name_length(ns_nname_ct nname, size_t namesiz) {
+ ns_nname_ct orig = nname;
+ u_int n;
+
+ while (namesiz-- > 0 && (n = *nname++) != 0) {
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (n > namesiz) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ nname += n;
+ namesiz -= n;
+ }
+ return (nname - orig);
+}
+
+/* Compare two nname's for equality. Return -1 on error (setting errno).
+ */
+int
+ns_name_eq(ns_nname_ct a, size_t as, ns_nname_ct b, size_t bs) {
+ ns_nname_ct ae = a + as, be = b + bs;
+ int ac, bc;
+
+ while (ac = *a, bc = *b, ac != 0 && bc != 0) {
+ if ((ac & NS_CMPRSFLGS) != 0 || (bc & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (a + ac >= ae || b + bc >= be) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ if (ac != bc || strncasecmp((const char *) ++a,
+ (const char *) ++b, ac) != 0)
+ return (0);
+ a += ac, b += bc;
+ }
+ return (ac == 0 && bc == 0);
+}
+
+/* Is domain "A" owned by (at or below) domain "B"?
+ */
+int
+ns_name_owned(ns_namemap_ct a, int an, ns_namemap_ct b, int bn) {
+ /* If A is shorter, it cannot be owned by B. */
+ if (an < bn)
+ return (0);
+
+ /* If they are unequal before the length of the shorter, A cannot... */
+ while (bn > 0) {
+ if (a->len != b->len ||
+ strncasecmp((const char *) a->base,
+ (const char *) b->base, a->len) != 0)
+ return (0);
+ a++, an--;
+ b++, bn--;
+ }
+
+ /* A might be longer or not, but either way, B owns it. */
+ return (1);
+}
+
+/* Build an array of <base,len> tuples from an nname, top-down order.
+ * Return the number of tuples (labels) thus discovered.
+ */
+int
+ns_name_map(ns_nname_ct nname, size_t namelen, ns_namemap_t map, int mapsize) {
+ u_int n;
+ int l;
+
+ n = *nname++;
+ namelen--;
+
+ /* Root zone? */
+ if (n == 0) {
+ /* Extra data follows name? */
+ if (namelen > 0) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ return (0);
+ }
+
+ /* Compression pointer? */
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+
+ /* Label too long? */
+ if (n > namelen) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+
+ /* Recurse to get rest of name done first. */
+ l = ns_name_map(nname + n, namelen - n, map, mapsize);
+ if (l < 0)
+ return (-1);
+
+ /* Too many labels? */
+ if (l >= mapsize) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+
+ /* We're on our way back up-stack, store current map data. */
+ map[l].base = nname;
+ map[l].len = n;
+ return (l + 1);
+}
+
+/* Count the labels in a domain name. Root counts, so COM. has two. This
+ * is to make the result comparable to the result of ns_name_map().
+ */
+int
+ns_name_labels(ns_nname_ct nname, size_t namesiz) {
+ int ret = 0;
+ u_int n;
+
+ while (namesiz-- > 0 && (n = *nname++) != 0) {
+ if ((n & NS_CMPRSFLGS) != 0) {
+ errno = EISDIR;
+ return (-1);
+ }
+ if (n > namesiz) {
+ errno = EMSGSIZE;
+ return (-1);
+ }
+ nname += n;
+ namesiz -= n;
+ ret++;
+ }
+ return (ret + 1);
+}
+
/* Private. */
/*%
@@ -806,7 +989,7 @@ decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
plen = (blen + 3) / 4;
plen += sizeof("\\[x/]") + (blen > 99 ? 3 : (blen > 9) ? 2 : 1);
if (dn + plen >= eom)
- return(-1);
+ return (-1);
cp++;
i = SPRINTF((dn, "\\[x"));
@@ -839,12 +1022,12 @@ decode_bitstring(const unsigned char **cpp, char *dn, const char *eom)
dn += i;
*cpp = cp;
- return(dn - beg);
+ return (dn - beg);
}
static int
encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
- unsigned char ** dst, unsigned const char *eom)
+ unsigned char ** dst, unsigned const char *eom)
{
int afterslash = 0;
const char *cp = *bp;
@@ -858,23 +1041,23 @@ encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
/* a bitstring must contain at least 2 characters */
if (end - cp < 2)
- return(EINVAL);
+ return (EINVAL);
/* XXX: currently, only hex strings are supported */
if (*cp++ != 'x')
- return(EINVAL);
+ return (EINVAL);
if (!isxdigit((*cp) & 0xff)) /*%< reject '\[x/BLEN]' */
- return(EINVAL);
+ return (EINVAL);
for (tp = *dst + 1; cp < end && tp < eom; cp++) {
switch((c = *cp)) {
case ']': /*%< end of the bitstring */
if (afterslash) {
if (beg_blen == NULL)
- return(EINVAL);
+ return (EINVAL);
blen = (int)strtol(beg_blen, &end_blen, 10);
if (*end_blen != ']')
- return(EINVAL);
+ return (EINVAL);
}
if (count)
*tp++ = ((value << 4) & 0xff);
@@ -886,24 +1069,24 @@ encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
default:
if (afterslash) {
if (!isdigit(c&0xff))
- return(EINVAL);
+ return (EINVAL);
if (beg_blen == NULL) {
if (c == '0') {
/* blen never begings with 0 */
- return(EINVAL);
+ return (EINVAL);
}
beg_blen = cp;
}
} else {
if (!isxdigit(c&0xff))
- return(EINVAL);
+ return (EINVAL);
value <<= 4;
value += digitvalue[(int)c];
count += 4;
tbcount += 4;
if (tbcount > 256)
- return(EINVAL);
+ return (EINVAL);
if (count == 8) {
*tp++ = value;
count = 0;
@@ -914,7 +1097,7 @@ encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
}
done:
if (cp >= end || tp >= eom)
- return(EMSGSIZE);
+ return (EMSGSIZE);
/*
* bit length validation:
@@ -928,10 +1111,10 @@ encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
int traillen;
if (((blen + 3) & ~3) != tbcount)
- return(EINVAL);
+ return (EINVAL);
traillen = tbcount - blen; /*%< between 0 and 3 */
if (((value << (8 - traillen)) & 0xff) != 0)
- return(EINVAL);
+ return (EINVAL);
}
else
blen = tbcount;
@@ -945,7 +1128,7 @@ encode_bitsring(const char **bp, const char *end, unsigned char **labelp,
*bp = cp;
*dst = tp;
- return(0);
+ return (0);
}
static int
@@ -956,18 +1139,18 @@ labellen(const u_char *lp)
if ((l & NS_CMPRSFLGS) == NS_CMPRSFLGS) {
/* should be avoided by the caller */
- return(-1);
+ return (-1);
}
if ((l & NS_CMPRSFLGS) == NS_TYPE_ELT) {
if (l == DNS_LABELTYPE_BITSTRING) {
if ((bitlen = *(lp + 1)) == 0)
bitlen = 256;
- return((bitlen + 7 ) / 8 + 1);
+ return ((bitlen + 7 ) / 8 + 1);
}
- return(-1); /*%< unknwon ELT */
+ return (-1); /*%< unknwon ELT */
}
- return(l);
+ return (l);
}
/*! \file */
diff --git a/lib/libc/nameser/ns_netint.c b/lib/libc/nameser/ns_netint.c
index b08c58b..5ddd5bc 100644
--- a/lib/libc/nameser/ns_netint.c
+++ b/lib/libc/nameser/ns_netint.c
@@ -16,8 +16,10 @@
*/
#ifndef lint
-static const char rcsid[] = "$Id: ns_netint.c,v 1.2.18.1 2005/04/27 05:01:08 sra Exp $";
+static const char rcsid[] = "$Id: ns_netint.c,v 1.3 2005/04/27 04:56:40 sra Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
/* Import. */
diff --git a/lib/libc/nameser/ns_parse.c b/lib/libc/nameser/ns_parse.c
index c4658d8..7294c92 100644
--- a/lib/libc/nameser/ns_parse.c
+++ b/lib/libc/nameser/ns_parse.c
@@ -16,8 +16,10 @@
*/
#ifndef lint
-static const char rcsid[] = "$Id: ns_parse.c,v 1.5.18.4 2007/08/27 03:34:24 marka Exp $";
+static const char rcsid[] = "$Id: ns_parse.c,v 1.10 2009/01/23 19:59:16 each Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
/* Import. */
@@ -47,6 +49,9 @@ static void setsection(ns_msg *msg, ns_sect sect);
do { errno = (err); if (errno == errno) return (-1); } while (0)
#endif
+#define PARSE_FMT_PRESO 0 /* Parse using presentation-format names */
+#define PARSE_FMT_WIRE 1 /* Parse using network-format names */
+
/* Public. */
/* These need to be in the same order as the nres.h:ns_flag enum. */
@@ -102,7 +107,6 @@ ns_initparse(const u_char *msg, int msglen, ns_msg *handle) {
const u_char *eom = msg + msglen;
int i;
- memset(handle, 0x5e, sizeof *handle);
handle->_msg = msg;
handle->_eom = eom;
if (msg + NS_INT16SZ > eom)
@@ -194,6 +198,68 @@ ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr) {
return (0);
}
+/*
+ * This is identical to the above but uses network-format (uncompressed) names.
+ */
+int
+ns_parserr2(ns_msg *handle, ns_sect section, int rrnum, ns_rr2 *rr) {
+ int b;
+ int tmp;
+
+ /* Make section right. */
+ if ((tmp = section) < 0 || section >= ns_s_max)
+ RETERR(ENODEV);
+ if (section != handle->_sect)
+ setsection(handle, section);
+
+ /* Make rrnum right. */
+ if (rrnum == -1)
+ rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[(int)section])
+ RETERR(ENODEV);
+ if (rrnum < handle->_rrnum)
+ setsection(handle, section);
+ if (rrnum > handle->_rrnum) {
+ b = ns_skiprr(handle->_msg_ptr, handle->_eom, section,
+ rrnum - handle->_rrnum);
+
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ handle->_rrnum = rrnum;
+ }
+
+ /* Do the parse. */
+ b = ns_name_unpack2(handle->_msg, handle->_eom, handle->_msg_ptr,
+ rr->nname, NS_MAXNNAME, &rr->nnamel);
+ if (b < 0)
+ return (-1);
+ handle->_msg_ptr += b;
+ if (handle->_msg_ptr + NS_INT16SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section == ns_s_qd) {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ } else {
+ if (handle->_msg_ptr + NS_INT32SZ + NS_INT16SZ > handle->_eom)
+ RETERR(EMSGSIZE);
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (handle->_msg_ptr + rr->rdlength > handle->_eom)
+ RETERR(EMSGSIZE);
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ }
+ if (++handle->_rrnum > handle->_counts[(int)section])
+ setsection(handle, (ns_sect)((int)section + 1));
+
+ /* All done. */
+ return (0);
+}
+
/* Private. */
static void
diff --git a/lib/libc/nameser/ns_print.c b/lib/libc/nameser/ns_print.c
index 2a46379..27d6538 100644
--- a/lib/libc/nameser/ns_print.c
+++ b/lib/libc/nameser/ns_print.c
@@ -16,7 +16,7 @@
*/
#ifndef lint
-static const char rcsid[] = "$Id: ns_print.c,v 1.6.18.4 2005/04/27 05:01:09 sra Exp $";
+static const char rcsid[] = "$Id: ns_print.c,v 1.12 2009/03/03 05:29:58 each Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -74,6 +74,9 @@ static int addtab(size_t len, size_t target, int spaced,
return (-1); \
} while (0)
+static const char base32hex[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUV=0123456789abcdefghijklmnopqrstuv";
+
/* Public. */
/*%
@@ -257,7 +260,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
case ns_t_mx:
case ns_t_afsdb:
- case ns_t_rt: {
+ case ns_t_rt:
+ case ns_t_kx: {
u_int t;
if (rdlen < (size_t)NS_INT16SZ)
@@ -305,6 +309,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
break;
case ns_t_txt:
+ case ns_t_spf:
while (rdata < edata) {
T(len = charstr(rdata, edata, &buf, &buflen));
if (len == 0)
@@ -451,7 +456,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
break;
}
- case ns_t_key: {
+ case ns_t_key:
+ case ns_t_dnskey: {
char base64_key[NS_MD5RSA_MAX_BASE64];
u_int keyflags, protocol, algorithm, key_id;
const char *leader;
@@ -497,7 +503,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
break;
}
- case ns_t_sig: {
+ case ns_t_sig:
+ case ns_t_rrsig: {
char base64_key[NS_MD5RSA_MAX_BASE64];
u_int type, algorithm, labels, footprint;
const char *leader;
@@ -508,7 +515,7 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
goto formerr;
/* Type covered, Algorithm, Label count, Original TTL. */
- type = ns_get16(rdata); rdata += NS_INT16SZ;
+ type = ns_get16(rdata); rdata += NS_INT16SZ;
algorithm = *rdata++;
labels = *rdata++;
t = ns_get32(rdata); rdata += NS_INT32SZ;
@@ -702,6 +709,345 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
break;
}
+ case ns_t_ds:
+ case ns_t_dlv:
+ case ns_t_sshfp: {
+ u_int t;
+
+ if (type == ns_t_ds || type == ns_t_dlv) {
+ if (rdlen < 4U) goto formerr;
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+ } else
+ if (rdlen < 2U) goto formerr;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ while (rdata < edata) {
+ len = SPRINTF((tmp, "%02X", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ break;
+ }
+
+ case ns_t_nsec3:
+ case ns_t_nsec3param: {
+ u_int t, w, l, j, k, c;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ t = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+ len = SPRINTF((tmp, "%u ", t));
+ T(addstr(tmp, len, &buf, &buflen));
+
+ t = *rdata++;
+ if (t == 0) {
+ T(addstr("-", 1, &buf, &buflen));
+ } else {
+ while (t-- > 0) {
+ len = SPRINTF((tmp, "%02X", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ }
+ if (type == ns_t_nsec3param)
+ break;
+ T(addstr(" ", 1, &buf, &buflen));
+
+ t = *rdata++;
+ while (t > 0) {
+ switch (t) {
+ case 1:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)];
+ tmp[2] = tmp[3] = tmp[4] = '=';
+ tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 2:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)];
+ tmp[4] = tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 3:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)];
+ tmp[5] = tmp[6] = tmp[7] = '=';
+ break;
+ case 4:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
+ ((rdata[3]>>7)&0x01)];
+ tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
+ tmp[6] = base32hex[(rdata[3]<<3)&0x18];
+ tmp[7] = '=';
+ break;
+ default:
+ tmp[0] = base32hex[((rdata[0]>>3)&0x1f)];
+ tmp[1] = base32hex[((rdata[0]<<2)&0x1c)|
+ ((rdata[1]>>6)&0x03)];
+ tmp[2] = base32hex[((rdata[1]>>1)&0x1f)];
+ tmp[3] = base32hex[((rdata[1]<<4)&0x10)|
+ ((rdata[2]>>4)&0x0f)];
+ tmp[4] = base32hex[((rdata[2]<<1)&0x1e)|
+ ((rdata[3]>>7)&0x01)];
+ tmp[5] = base32hex[((rdata[3]>>2)&0x1f)];
+ tmp[6] = base32hex[((rdata[3]<<3)&0x18)|
+ ((rdata[4]>>5)&0x07)];
+ tmp[7] = base32hex[(rdata[4]&0x1f)];
+ break;
+ }
+ T(addstr(tmp, 8, &buf, &buflen));
+ if (t >= 5) {
+ rdata += 5;
+ t -= 5;
+ } else {
+ rdata += t;
+ t -= t;
+ }
+ }
+
+ while (rdata < edata) {
+ w = *rdata++;
+ l = *rdata++;
+ for (j = 0; j < l; j++) {
+ if (rdata[j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((rdata[j] & (0x80 >> k)) == 0)
+ continue;
+ c = w * 256 + j * 8 + k;
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ }
+ rdata += l;
+ }
+ break;
+ }
+
+ case ns_t_nsec: {
+ u_int w, l, j, k, c;
+
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+
+ while (rdata < edata) {
+ w = *rdata++;
+ l = *rdata++;
+ for (j = 0; j < l; j++) {
+ if (rdata[j] == 0)
+ continue;
+ for (k = 0; k < 8; k++) {
+ if ((rdata[j] & (0x80 >> k)) == 0)
+ continue;
+ c = w * 256 + j * 8 + k;
+ len = SPRINTF((tmp, " %s", p_type(c)));
+ T(addstr(tmp, len, &buf, &buflen));
+ }
+ }
+ rdata += l;
+ }
+ break;
+ }
+
+ case ns_t_dhcid: {
+ int n;
+ unsigned int siz;
+ char base64_dhcid[8192];
+ const char *leader;
+
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_dhcid) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = b64_ntop(rdata, edata-rdata, base64_dhcid, siz);
+
+ if (len < 0)
+ goto formerr;
+
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_dhcid + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
+ case ns_t_ipseckey: {
+ int n;
+ unsigned int siz;
+ char base64_key[8192];
+ const char *leader;
+
+ if (rdlen < 2)
+ goto formerr;
+
+ switch (rdata[1]) {
+ case 0:
+ case 3:
+ if (rdlen < 3)
+ goto formerr;
+ break;
+ case 1:
+ if (rdlen < 7)
+ goto formerr;
+ break;
+ case 2:
+ if (rdlen < 19)
+ goto formerr;
+ break;
+ default:
+ comment = "unknown IPSECKEY gateway type";
+ goto hexify;
+ }
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ len = SPRINTF((tmp, "%u ", *rdata));
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+
+ switch (rdata[-2]) {
+ case 0:
+ T(addstr(".", 1, &buf, &buflen));
+ break;
+ case 1:
+ (void) inet_ntop(AF_INET, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += 4;
+ break;
+ case 2:
+ (void) inet_ntop(AF_INET6, rdata, buf, buflen);
+ addlen(strlen(buf), &buf, &buflen);
+ rdata += 16;
+ break;
+ case 3:
+ T(addname(msg, msglen, &rdata, origin, &buf, &buflen));
+ break;
+ }
+
+ if (rdata >= edata)
+ break;
+
+ siz = (edata-rdata)*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_key) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = b64_ntop(rdata, edata-rdata, base64_key, siz);
+
+ if (len < 0)
+ goto formerr;
+
+ else if (len > 15) {
+ T(addstr(" (", 2, &buf, &buflen));
+ leader = "\n\t\t";
+ spaced = 0;
+ }
+ else
+ leader = " ";
+
+ for (n = 0; n < len; n += 48) {
+ T(addstr(leader, strlen(leader),
+ &buf, &buflen));
+ T(addstr(base64_key + n, MIN(len - n, 48),
+ &buf, &buflen));
+ }
+ if (len > 15)
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ }
+
+ case ns_t_hip: {
+ unsigned int i, hip_len, algorithm, key_len;
+ char base64_key[NS_MD5RSA_MAX_BASE64];
+ unsigned int siz;
+ const char *leader = "\n\t\t\t\t\t";
+
+ hip_len = *rdata++;
+ algorithm = *rdata++;
+ key_len = ns_get16(rdata);
+ rdata += NS_INT16SZ;
+
+ siz = key_len*4/3 + 4; /* "+4" accounts for trailing \0 */
+ if (siz > sizeof(base64_key) * 3/4) {
+ const char *str = "record too long to print";
+ T(addstr(str, strlen(str), &buf, &buflen));
+ } else {
+ len = sprintf(tmp, "( %u ", algorithm);
+ T(addstr(tmp, len, &buf, &buflen));
+
+ for (i = 0; i < hip_len; i++) {
+ len = sprintf(tmp, "%02X", *rdata);
+ T(addstr(tmp, len, &buf, &buflen));
+ rdata++;
+ }
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+
+ len = b64_ntop(rdata, key_len, base64_key, siz);
+ if (len < 0)
+ goto formerr;
+
+ T(addstr(base64_key, len, &buf, &buflen));
+
+ rdata += key_len;
+ while (rdata < edata) {
+ T(addstr(leader, strlen(leader), &buf, &buflen));
+ T(addname(msg, msglen, &rdata, origin,
+ &buf, &buflen));
+ }
+ T(addstr(" )", 2, &buf, &buflen));
+ }
+ break;
+ }
+
default:
comment = "unknown RR type";
goto hexify;
diff --git a/lib/libc/nameser/ns_samedomain.c b/lib/libc/nameser/ns_samedomain.c
index 9c43c79..4470cd0 100644
--- a/lib/libc/nameser/ns_samedomain.c
+++ b/lib/libc/nameser/ns_samedomain.c
@@ -16,7 +16,7 @@
*/
#ifndef lint
-static const char rcsid[] = "$Id: ns_samedomain.c,v 1.5.18.1 2005/04/27 05:01:09 sra Exp $";
+static const char rcsid[] = "$Id: ns_samedomain.c,v 1.6 2005/04/27 04:56:40 sra Exp $";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/nameser/ns_ttl.c b/lib/libc/nameser/ns_ttl.c
index 627ddf1..da7df67 100644
--- a/lib/libc/nameser/ns_ttl.c
+++ b/lib/libc/nameser/ns_ttl.c
@@ -16,8 +16,10 @@
*/
#ifndef lint
-static const char rcsid[] = "$Id: ns_ttl.c,v 1.2.18.2 2005/07/28 07:38:10 marka Exp $";
+static const char rcsid[] = "$Id: ns_ttl.c,v 1.4 2005/07/28 06:51:49 marka Exp $";
#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
/* Import. */
diff --git a/lib/libc/net/getaddrinfo.c b/lib/libc/net/getaddrinfo.c
index b4c1a33..c50374e 100644
--- a/lib/libc/net/getaddrinfo.c
+++ b/lib/libc/net/getaddrinfo.c
@@ -30,8 +30,6 @@
*/
/*
- * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
- *
* Issues to be discussed:
* - Return values. There are nonstandard return values defined and used
* in the source code. This is because RFC2553 is silent about which error
@@ -101,10 +99,6 @@ __FBSDID("$FreeBSD$");
#include "nscache.h"
#endif
-#if defined(__KAME__) && defined(INET6)
-# define FAITH
-#endif
-
#define ANY 0
#define YES 1
#define NO 0
@@ -1316,47 +1310,6 @@ get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
{
char *p;
struct addrinfo *ai;
-#ifdef FAITH
- struct in6_addr faith_prefix;
- char *fp_str;
- int translate = 0;
-#endif
-
-#ifdef FAITH
- /*
- * Transfrom an IPv4 addr into a special IPv6 addr format for
- * IPv6->IPv4 translation gateway. (only TCP is supported now)
- *
- * +-----------------------------------+------------+
- * | faith prefix part (12 bytes) | embedded |
- * | | IPv4 addr part (4 bytes)
- * +-----------------------------------+------------+
- *
- * faith prefix part is specified as ascii IPv6 addr format
- * in environmental variable GAI.
- * For FAITH to work correctly, routing to faith prefix must be
- * setup toward a machine where a FAITH daemon operates.
- * Also, the machine must enable some mechanizm
- * (e.g. faith interface hack) to divert those packet with
- * faith prefixed destination addr to user-land FAITH daemon.
- */
- fp_str = getenv("GAI");
- if (fp_str && inet_pton(AF_INET6, fp_str, &faith_prefix) == 1 &&
- afd->a_af == AF_INET && pai->ai_socktype == SOCK_STREAM) {
- u_int32_t v4a;
- u_int8_t v4a_top;
-
- memcpy(&v4a, addr, sizeof v4a);
- v4a_top = v4a >> IN_CLASSA_NSHIFT;
- if (!IN_MULTICAST(v4a) && !IN_EXPERIMENTAL(v4a) &&
- v4a_top != 0 && v4a != IN_LOOPBACKNET) {
- afd = &afdl[N_INET6];
- memcpy(&faith_prefix.s6_addr[12], addr,
- sizeof(struct in_addr));
- translate = 1;
- }
- }
-#endif
ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
+ (afd->a_socklen));
@@ -1370,11 +1323,6 @@ get_ai(const struct addrinfo *pai, const struct afd *afd, const char *addr)
ai->ai_addrlen = afd->a_socklen;
ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
p = (char *)(void *)(ai->ai_addr);
-#ifdef FAITH
- if (translate == 1)
- memcpy(p + afd->a_off, &faith_prefix, (size_t)afd->a_addrlen);
- else
-#endif
memcpy(p + afd->a_off, addr, (size_t)afd->a_addrlen);
return ai;
}
diff --git a/lib/libc/net/getnameinfo.c b/lib/libc/net/getnameinfo.c
index ffd34a1..005b877 100644
--- a/lib/libc/net/getnameinfo.c
+++ b/lib/libc/net/getnameinfo.c
@@ -414,7 +414,6 @@ getnameinfo_link(const struct sockaddr *sa, socklen_t salen,
/*
* The following have zero-length addresses.
* IFT_ATM (net/if_atmsubr.c)
- * IFT_FAITH (net/if_faith.c)
* IFT_GIF (net/if_gif.c)
* IFT_LOOP (net/if_loop.c)
* IFT_PPP (net/if_ppp.c, net/if_spppsubr.c)
diff --git a/lib/libc/net/linkaddr.c b/lib/libc/net/linkaddr.c
index 86bb7a2..5be6e74 100644
--- a/lib/libc/net/linkaddr.c
+++ b/lib/libc/net/linkaddr.c
@@ -118,7 +118,7 @@ link_addr(addr, sdl)
return;
}
-static char hexlist[] = "0123456789abcdef";
+static const char hexlist[] = "0123456789abcdef";
char *
link_ntoa(sdl)
diff --git a/lib/libc/net/nsdispatch.c b/lib/libc/net/nsdispatch.c
index 4fbc9ba..c23315c 100644
--- a/lib/libc/net/nsdispatch.c
+++ b/lib/libc/net/nsdispatch.c
@@ -329,7 +329,6 @@ _nsdbtdump(const ns_dbt *dbt)
static int
nss_configure(void)
{
- static pthread_mutex_t conf_lock = PTHREAD_MUTEX_INITIALIZER;
static time_t confmod;
struct stat statbuf;
int result, isthreaded;
@@ -353,13 +352,14 @@ nss_configure(void)
if (statbuf.st_mtime <= confmod)
return (0);
if (isthreaded) {
- result = _pthread_mutex_trylock(&conf_lock);
- if (result != 0)
- return (0);
(void)_pthread_rwlock_unlock(&nss_lock);
result = _pthread_rwlock_wrlock(&nss_lock);
if (result != 0)
- goto fin2;
+ return (result);
+ if (stat(path, &statbuf) != 0)
+ goto fin;
+ if (statbuf.st_mtime <= confmod)
+ goto fin;
}
_nsyyin = fopen(path, "re");
if (_nsyyin == NULL)
@@ -390,9 +390,6 @@ fin:
if (result == 0)
result = _pthread_rwlock_rdlock(&nss_lock);
}
-fin2:
- if (isthreaded)
- (void)_pthread_mutex_unlock(&conf_lock);
return (result);
}
diff --git a/lib/libc/net/sctp_sys_calls.c b/lib/libc/net/sctp_sys_calls.c
index a7da95c..91527c3 100644
--- a/lib/libc/net/sctp_sys_calls.c
+++ b/lib/libc/net/sctp_sys_calls.c
@@ -350,12 +350,39 @@ sctp_opt_info(int sd, sctp_assoc_t id, int opt, void *arg, socklen_t * size)
case SCTP_REMOTE_UDP_ENCAPS_PORT:
((struct sctp_udpencaps *)arg)->sue_assoc_id = id;
break;
+ case SCTP_ECN_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_PR_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_AUTH_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_ASCONF_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_RECONFIG_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_NRSACK_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
+ case SCTP_PKTDROP_SUPPORTED:
+ ((struct sctp_assoc_value *)arg)->assoc_id = id;
+ break;
case SCTP_MAX_BURST:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
case SCTP_ENABLE_STREAM_RESET:
((struct sctp_assoc_value *)arg)->assoc_id = id;
break;
+ case SCTP_PR_STREAM_STATUS:
+ ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
+ break;
+ case SCTP_PR_ASSOC_STATUS:
+ ((struct sctp_prstatus *)arg)->sprstat_assoc_id = id;
+ break;
default:
break;
}
@@ -575,6 +602,7 @@ sctp_sendmsg(int s,
cmsg->cmsg_type = SCTP_SNDRCV;
cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo));
sinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg);
+ memset(sinfo, 0, sizeof(struct sctp_sndrcvinfo));
sinfo->sinfo_stream = stream_no;
sinfo->sinfo_ssn = 0;
sinfo->sinfo_flags = flags;
diff --git a/lib/libc/posix1e/acl.3 b/lib/libc/posix1e/acl.3
index a39b736..d37cd14 100644
--- a/lib/libc/posix1e/acl.3
+++ b/lib/libc/posix1e/acl.3
@@ -27,12 +27,12 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 12, 2013
+.Dd October 30, 2014
.Dt ACL 3
.Os
.Sh NAME
.Nm acl
-.Nd introduction to the POSIX.1e ACL security API
+.Nd introduction to the POSIX.1e/NFSv4 ACL security API
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
@@ -42,13 +42,15 @@
.Fx
permits file systems to export Access Control Lists via the VFS, and
provides a library for userland access to and manipulation of these ACLs.
-Not all file systems provide support for ACLs, and some may require that
+.Fx
+supports POSIX.1e and NFSv4 ACLs, but
+not all file systems provide support for ACLs, and some may require that
ACL support be explicitly enabled by the administrator.
The library calls include routines to allocate, duplicate, retrieve, set,
and validate ACLs associated with file objects.
As well as the POSIX.1e routines, there are a number of non-portable
-extensions defined that allow for alternative ACL semantics than the
-POSIX.1e semantics, such as NFSv4, AFS, NTFS, Coda, and NWFS semantics.
+extensions defined that allow for ACL semantics alternative to
+POSIX.1e, such as NFSv4.
Where routines are non-standard, they are suffixed with _np to indicate that
they are not portable.
.Pp
@@ -292,6 +294,8 @@ POSIX.1e support was introduced in
.Fx 5.0
was the first version to include a complete ACL implementation based
on extended attributes for the UFS and UFS2 file systems.
+NFSv4 ACL support was introduced in
+.Fx 8.0 .
.Pp
The
.Xr getfacl 1
diff --git a/lib/libc/posix1e/acl_add_flag_np.3 b/lib/libc/posix1e/acl_add_flag_np.3
index 9f7b21e..db8e565 100644
--- a/lib/libc/posix1e/acl_add_flag_np.3
+++ b/lib/libc/posix1e/acl_add_flag_np.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 25, 2009
+.Dd October 30, 2014
.Dt ACL_ADD_FLAG_NP 3
.Os
.Sh NAME
@@ -42,7 +42,7 @@
The
.Fn acl_add_flag_np
function
-is a non-portable call that adds the flags contained in
+is a non-portable call that adds the NFSv4 ACL flags contained in
.Fa flags
to the flagset
.Fa flagset_d .
diff --git a/lib/libc/posix1e/acl_clear_flags_np.3 b/lib/libc/posix1e/acl_clear_flags_np.3
index a3da481..06dee97 100644
--- a/lib/libc/posix1e/acl_clear_flags_np.3
+++ b/lib/libc/posix1e/acl_clear_flags_np.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 25, 2009
+.Dd October 30, 2014
.Dt ACL_CLEAR_FLAGS_NP 3
.Os
.Sh NAME
@@ -42,7 +42,7 @@
The
.Fn acl_clear_flags_np
function
-is a non-portable call that clears all flags from flagset
+is a non-portable call that clears all NFSv4 ACL flags from flagset
.Fa flagset_d .
.Sh RETURN VALUES
.Rv -std acl_clear_flags_np
diff --git a/lib/libc/posix1e/acl_delete_flag_np.3 b/lib/libc/posix1e/acl_delete_flag_np.3
index ba7a738..6a613eb 100644
--- a/lib/libc/posix1e/acl_delete_flag_np.3
+++ b/lib/libc/posix1e/acl_delete_flag_np.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 10, 2001
+.Dd October 30, 2014
.Dt ACL_DELETE_FLAG_NP 3
.Os
.Sh NAME
@@ -42,7 +42,7 @@
The
.Fn acl_delete_flag_np
function
-is a non-portable call that removes specific flags from flagset
+is a non-portable call that removes specific NFSv4 ACL flags from flagset
.Fa flags .
.Sh RETURN VALUES
.Rv -std acl_delete_flag_np
diff --git a/lib/libc/posix1e/acl_get_flag_np.3 b/lib/libc/posix1e/acl_get_flag_np.3
index d70ce84..f7ee5d7 100644
--- a/lib/libc/posix1e/acl_get_flag_np.3
+++ b/lib/libc/posix1e/acl_get_flag_np.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 25, 2009
+.Dd October 30, 2014
.Dt ACL_GET_FLAG_NP 3
.Os
.Sh NAME
@@ -42,7 +42,7 @@
The
.Fn acl_get_flag_np
function
-is a non-portable function that checks if a flag is set in
+is a non-portable function that checks if a NFSv4 ACL flag is set in
a flagset.
.Sh RETURN VALUES
If the flag in
diff --git a/lib/libc/posix1e/acl_get_flagset_np.3 b/lib/libc/posix1e/acl_get_flagset_np.3
index fd1c8b2..31573c1 100644
--- a/lib/libc/posix1e/acl_get_flagset_np.3
+++ b/lib/libc/posix1e/acl_get_flagset_np.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 25, 2009
+.Dd October 30, 2014
.Dt ACL_GET_FLAGSET_NP 3
.Os
.Sh NAME
@@ -44,7 +44,7 @@ The
function
is a non-portable call that returns via
.Fa flagset_np_p
-a descriptor to the flagset in the ACL entry
+a descriptor to the flagset in the NFSv4 ACL entry
.Fa entry_d .
Subsequent operations using the returned flagset operate
on the flagset within the ACL entry.
diff --git a/lib/libc/posix1e/acl_set_entry_type_np.3 b/lib/libc/posix1e/acl_set_entry_type_np.3
index 2257b53..90772e0 100644
--- a/lib/libc/posix1e/acl_set_entry_type_np.3
+++ b/lib/libc/posix1e/acl_set_entry_type_np.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 25, 2009
+.Dd October 30, 2014
.Dt ACL_SET_ENTRY_TYPE_NP 3
.Os
.Sh NAME
@@ -42,7 +42,7 @@
The
.Fn acl_set_entry_type_np
function
-is a non-portable call that sets the type of the ACL entry
+is a non-portable call that sets the type of the NFSv4 ACL entry
.Fa entry_d
to the value referred to by
.Fa entry_type .
diff --git a/lib/libc/posix1e/acl_set_flagset_np.3 b/lib/libc/posix1e/acl_set_flagset_np.3
index 3d271c8..2230c48 100644
--- a/lib/libc/posix1e/acl_set_flagset_np.3
+++ b/lib/libc/posix1e/acl_set_flagset_np.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd June 25, 2009
+.Dd October 30, 2014
.Dt ACL_SET_FLAGSET_NP 3
.Os
.Sh NAME
@@ -42,7 +42,7 @@
The
.Fn acl_set_flagset_np
function
-is a non-portable call that sets the flags of ACL entry
+is a non-portable call that sets the flags of NFSv4 ACL entry
.Fa entry_d
with the flags contained in
.Fa flagset_d .
diff --git a/lib/libc/powerpc/gen/_ctx_start.S b/lib/libc/powerpc/gen/_ctx_start.S
index 2d3cfcf..4b9fc1d 100644
--- a/lib/libc/powerpc/gen/_ctx_start.S
+++ b/lib/libc/powerpc/gen/_ctx_start.S
@@ -41,5 +41,6 @@
* above branch.
*/
bl PIC_PLT(CNAME(abort)) /* abort */
+ END(_cts_start)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/_setjmp.S b/lib/libc/powerpc/gen/_setjmp.S
index bbf8644..e28386c 100644
--- a/lib/libc/powerpc/gen/_setjmp.S
+++ b/lib/libc/powerpc/gen/_setjmp.S
@@ -58,6 +58,7 @@ ENTRY(_setjmp)
stmw %r9,20(%r3)
li %r3,0
blr
+END(_setjmp)
ENTRY(_longjmp)
lmw %r9,20(%r3)
@@ -68,5 +69,6 @@ ENTRY(_longjmp)
bnelr
li %r3,1
blr
+END(_longjmp)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/eabi.S b/lib/libc/powerpc/gen/eabi.S
index 59c2311..3296af8 100644
--- a/lib/libc/powerpc/gen/eabi.S
+++ b/lib/libc/powerpc/gen/eabi.S
@@ -29,5 +29,6 @@ __FBSDID("$FreeBSD$");
ENTRY(__eabi)
blr
+END(__eabi)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/fabs.S b/lib/libc/powerpc/gen/fabs.S
index 7891012..ac083ae 100644
--- a/lib/libc/powerpc/gen/fabs.S
+++ b/lib/libc/powerpc/gen/fabs.S
@@ -33,5 +33,6 @@ __FBSDID("$FreeBSD$");
ENTRY(fabs)
fabs %f1,%f1
blr
+END(fabs)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/setjmp.S b/lib/libc/powerpc/gen/setjmp.S
index 6df4f93..9325fc2 100644
--- a/lib/libc/powerpc/gen/setjmp.S
+++ b/lib/libc/powerpc/gen/setjmp.S
@@ -68,6 +68,7 @@ ENTRY(setjmp)
stmw %r9,20(%r6)
li %r3,0 /* return (0) */
blr
+END(setjmp)
WEAK_REFERENCE(CNAME(__longjmp), longjmp)
ENTRY(__longjmp)
@@ -86,5 +87,6 @@ ENTRY(__longjmp)
bnelr
li %r3,1
blr
+END(__longjmp)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/gen/sigsetjmp.S b/lib/libc/powerpc/gen/sigsetjmp.S
index 9639dd1..c67afc6 100644
--- a/lib/libc/powerpc/gen/sigsetjmp.S
+++ b/lib/libc/powerpc/gen/sigsetjmp.S
@@ -73,6 +73,7 @@ ENTRY(sigsetjmp)
stmw %r9,20(%r6)
li %r3,0
blr
+END(sigsetjmp)
ENTRY(siglongjmp)
lmw %r9,20(%r3)
@@ -94,5 +95,6 @@ ENTRY(siglongjmp)
bnelr
li %r3,1
blr
+END(siglongjmp)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/brk.S b/lib/libc/powerpc/sys/brk.S
index 018eec9..e14be10 100644
--- a/lib/libc/powerpc/sys/brk.S
+++ b/lib/libc/powerpc/sys/brk.S
@@ -71,5 +71,6 @@ ENTRY(brk)
1:
b PIC_PLT(HIDENAME(cerror))
+END(brk)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/exect.S b/lib/libc/powerpc/sys/exect.S
index 3c39b3c..701f5b0 100644
--- a/lib/libc/powerpc/sys/exect.S
+++ b/lib/libc/powerpc/sys/exect.S
@@ -37,5 +37,6 @@ ENTRY(exect)
blr
1:
b PIC_PLT(HIDENAME(cerror))
+END(exect)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/pipe.S b/lib/libc/powerpc/sys/pipe.S
index 3f6d9a4..1cbbef0 100644
--- a/lib/libc/powerpc/sys/pipe.S
+++ b/lib/libc/powerpc/sys/pipe.S
@@ -41,5 +41,6 @@ ENTRY(pipe)
blr /* and return 0 */
1:
b PIC_PLT(HIDENAME(cerror))
+END(pipe)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/ptrace.S b/lib/libc/powerpc/sys/ptrace.S
index 0bc25c9..cff463d 100644
--- a/lib/libc/powerpc/sys/ptrace.S
+++ b/lib/libc/powerpc/sys/ptrace.S
@@ -56,5 +56,6 @@ ENTRY(ptrace)
blr
1:
b PIC_PLT(HIDENAME(cerror))
+END(ptrace)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc/sys/sbrk.S b/lib/libc/powerpc/sys/sbrk.S
index a5e4020..f058d11 100644
--- a/lib/libc/powerpc/sys/sbrk.S
+++ b/lib/libc/powerpc/sys/sbrk.S
@@ -68,5 +68,6 @@ ENTRY(sbrk)
blr
2:
b PIC_PLT(HIDENAME(cerror))
+END(sbrk)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/_ctx_start.S b/lib/libc/powerpc64/gen/_ctx_start.S
index 79df041..17ec44e 100644
--- a/lib/libc/powerpc64/gen/_ctx_start.S
+++ b/lib/libc/powerpc64/gen/_ctx_start.S
@@ -46,5 +46,6 @@
nop
bl CNAME(abort) /* abort */
nop
+ END(_ctx_start)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/_setjmp.S b/lib/libc/powerpc64/gen/_setjmp.S
index ac0555e..207c4f7 100644
--- a/lib/libc/powerpc64/gen/_setjmp.S
+++ b/lib/libc/powerpc64/gen/_setjmp.S
@@ -80,6 +80,7 @@ ENTRY(_setjmp)
std %r31,40 + 22*8(%r3)
li %r3,0
blr
+END(_setjmp)
ENTRY(_longjmp)
ld %r9,40 + 0*8(%r3)
@@ -113,5 +114,6 @@ ENTRY(_longjmp)
bnelr
li %r3,1
blr
+END(_longjmp)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/fabs.S b/lib/libc/powerpc64/gen/fabs.S
index 7891012..ac083ae 100644
--- a/lib/libc/powerpc64/gen/fabs.S
+++ b/lib/libc/powerpc64/gen/fabs.S
@@ -33,5 +33,6 @@ __FBSDID("$FreeBSD$");
ENTRY(fabs)
fabs %f1,%f1
blr
+END(fabs)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/setjmp.S b/lib/libc/powerpc64/gen/setjmp.S
index 8fe2852..1495466 100644
--- a/lib/libc/powerpc64/gen/setjmp.S
+++ b/lib/libc/powerpc64/gen/setjmp.S
@@ -92,6 +92,7 @@ ENTRY(setjmp)
li %r3,0 /* return (0) */
blr
+END(setjmp)
WEAK_REFERENCE(__longjmp, longjmp)
ENTRY(__longjmp)
@@ -132,5 +133,6 @@ ENTRY(__longjmp)
bnelr
li %r3,1
blr
+END(__longjmp)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/gen/sigsetjmp.S b/lib/libc/powerpc64/gen/sigsetjmp.S
index d5341ea..5cfd684 100644
--- a/lib/libc/powerpc64/gen/sigsetjmp.S
+++ b/lib/libc/powerpc64/gen/sigsetjmp.S
@@ -97,6 +97,7 @@ ENTRY(sigsetjmp)
li %r3,0
blr
+END(sigsetjmp)
ENTRY(siglongjmp)
ld %r9,40 + 0*8(%r3)
@@ -141,5 +142,6 @@ ENTRY(siglongjmp)
bnelr
li %r3,1
blr
+END(siglongjmp)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/brk.S b/lib/libc/powerpc64/sys/brk.S
index 675b400..cbcecc7 100644
--- a/lib/libc/powerpc64/sys/brk.S
+++ b/lib/libc/powerpc64/sys/brk.S
@@ -69,5 +69,6 @@ ENTRY(brk)
ld %r0,16(%r1)
mtlr %r0
blr
+END(brk)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/exect.S b/lib/libc/powerpc64/sys/exect.S
index aa34b9e..b6cda9c 100644
--- a/lib/libc/powerpc64/sys/exect.S
+++ b/lib/libc/powerpc64/sys/exect.S
@@ -45,5 +45,6 @@ ENTRY(exect)
ld %r0,16(%r1)
mtlr %r0
blr
+END(exect)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/pipe.S b/lib/libc/powerpc64/sys/pipe.S
index efd3dd6..ee255a9 100644
--- a/lib/libc/powerpc64/sys/pipe.S
+++ b/lib/libc/powerpc64/sys/pipe.S
@@ -49,5 +49,6 @@ ENTRY(pipe)
ld %r0,16(%r1)
mtlr %r0
blr
+END(pipe)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/ptrace.S b/lib/libc/powerpc64/sys/ptrace.S
index ede00e7..69709dd 100644
--- a/lib/libc/powerpc64/sys/ptrace.S
+++ b/lib/libc/powerpc64/sys/ptrace.S
@@ -63,5 +63,6 @@ ENTRY(ptrace)
ld %r0,16(%r1)
mtlr %r0
blr
+END(ptrace)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/powerpc64/sys/sbrk.S b/lib/libc/powerpc64/sys/sbrk.S
index e147493..4e3b57a 100644
--- a/lib/libc/powerpc64/sys/sbrk.S
+++ b/lib/libc/powerpc64/sys/sbrk.S
@@ -64,5 +64,6 @@ ENTRY(sbrk)
ld %r0,16(%r1)
mtlr %r0
blr
+END(sbrk)
.section .note.GNU-stack,"",%progbits
diff --git a/lib/libc/quad/Makefile.inc b/lib/libc/quad/Makefile.inc
index 1b1ab60..94697fa 100644
--- a/lib/libc/quad/Makefile.inc
+++ b/lib/libc/quad/Makefile.inc
@@ -8,7 +8,7 @@
SRCS+= cmpdi2.c divdi3.c moddi3.c qdivrem.c ucmpdi2.c udivdi3.c umoddi3.c
-.elif ${LIBC_ARCH} == "arm" && ${MK_ARM_EABI} != "no"
+.elif ${LIBC_ARCH} == "arm"
SRCS+= adddi3.c anddi3.c floatunsdidf.c iordi3.c lshldi3.c notdi2.c \
qdivrem.c subdi3.c xordi3.c
diff --git a/lib/libc/resolv/Makefile.inc b/lib/libc/resolv/Makefile.inc
index c77a3ab..1a48687 100644
--- a/lib/libc/resolv/Makefile.inc
+++ b/lib/libc/resolv/Makefile.inc
@@ -8,3 +8,5 @@ SRCS+= herror.c h_errno.c mtctxres.c res_comp.c res_data.c res_debug.c \
res_query.c res_send.c res_state.c res_update.c
SYM_MAPS+= ${LIBC_SRCTOP}/resolv/Symbol.map
+
+CFLAGS+=-I${LIBC_SRCTOP}/../libmd
diff --git a/lib/libc/resolv/Symbol.map b/lib/libc/resolv/Symbol.map
index 211f2c4..1703333 100644
--- a/lib/libc/resolv/Symbol.map
+++ b/lib/libc/resolv/Symbol.map
@@ -105,3 +105,8 @@ FBSD_1.0 {
res_send;
__res_update;
};
+
+FBSD_1.4 {
+ __res_rndinit;
+ __res_nrandomid;
+};
diff --git a/lib/libc/resolv/herror.c b/lib/libc/resolv/herror.c
index cb9dd0e..d987609 100644
--- a/lib/libc/resolv/herror.c
+++ b/lib/libc/resolv/herror.c
@@ -46,7 +46,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)herror.c 8.1 (Berkeley) 6/4/93";
-static const char rcsid[] = "$Id: herror.c,v 1.3.18.1 2005/04/27 05:01:09 sra Exp $";
+static const char rcsid[] = "$Id: herror.c,v 1.4 2005/04/27 04:56:41 sra Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/resolv/res_comp.c b/lib/libc/resolv/res_comp.c
index 81bce5e..539d974 100644
--- a/lib/libc/resolv/res_comp.c
+++ b/lib/libc/resolv/res_comp.c
@@ -66,7 +66,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_comp.c 8.1 (Berkeley) 6/4/93";
-static const char rcsid[] = "$Id: res_comp.c,v 1.3.18.2 2005/07/28 07:38:11 marka Exp $";
+static const char rcsid[] = "$Id: res_comp.c,v 1.5 2005/07/28 06:51:50 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/resolv/res_data.c b/lib/libc/resolv/res_data.c
index 5a1a50c..f020838 100644
--- a/lib/libc/resolv/res_data.c
+++ b/lib/libc/resolv/res_data.c
@@ -16,7 +16,7 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
-static const char rcsid[] = "$Id: res_data.c,v 1.3.18.2 2007/09/14 05:35:47 marka Exp $";
+static const char rcsid[] = "$Id: res_data.c,v 1.7 2008/12/11 09:59:00 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -107,13 +107,6 @@ res_init(void) {
if (!(_res.options & RES_INIT))
_res.options = RES_DEFAULT;
- /*
- * This one used to initialize implicitly to zero, so unless the app
- * has set it to something in particular, we can randomize it now.
- */
- if (!_res.id)
- _res.id = res_randomid();
-
return (__res_vinit(&_res, 1));
}
@@ -264,6 +257,16 @@ res_querydomain(const char *name,
answer, anslen));
}
+u_int
+res_randomid(void) {
+ if ((_res.options & RES_INIT) == 0U && res_init() == -1) {
+ RES_SET_H_ERRNO(&_res, NETDB_INTERNAL);
+ return (-1);
+ }
+
+ return (res_nrandomid(&_res));
+}
+
int
res_opt(int n0, u_char *buf, int buflen, int anslen)
{
diff --git a/lib/libc/resolv/res_debug.c b/lib/libc/resolv/res_debug.c
index c2707bb..8ab0263 100644
--- a/lib/libc/resolv/res_debug.c
+++ b/lib/libc/resolv/res_debug.c
@@ -1,7 +1,24 @@
/*
+ * Portions Copyright (C) 2004, 2005, 2008, 2009 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
* Copyright (c) 1985
* The Regents of the University of California. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -13,7 +30,7 @@
* 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
@@ -29,14 +46,14 @@
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
+ *
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
@@ -72,26 +89,9 @@
* IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
-/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_debug.c 8.1 (Berkeley) 6/4/93";
-static const char rcsid[] = "$Id: res_debug.c,v 1.10.18.6 2008/04/03 23:15:15 marka Exp $";
+static const char rcsid[] = "$Id: res_debug.c,v 1.19 2009/02/26 11:20:20 tbox Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -327,7 +327,7 @@ res_pquery(const res_state statp, const u_char *msg, int len, FILE *file) {
fprintf(file, ", %s: %d",
p_section(ns_s_ar, opcode), arcount);
}
- if ((!statp->pfcode) || (statp->pfcode &
+ if ((!statp->pfcode) || (statp->pfcode &
(RES_PRF_HEADX | RES_PRF_HEAD2 | RES_PRF_HEAD1))) {
putc('\n',file);
}
@@ -494,6 +494,24 @@ const struct res_sym __p_type_syms[] = {
{ns_t_nimloc, "NIMLOC", "NIMROD locator (unimplemented)"},
{ns_t_srv, "SRV", "server selection"},
{ns_t_atma, "ATMA", "ATM address (unimplemented)"},
+ {ns_t_naptr, "NAPTR", "naptr"},
+ {ns_t_kx, "KX", "key exchange"},
+ {ns_t_cert, "CERT", "certificate"},
+ {ns_t_a6, "A", "IPv6 address (experminental)"},
+ {ns_t_dname, "DNAME", "non-terminal redirection"},
+ {ns_t_opt, "OPT", "opt"},
+ {ns_t_apl, "apl", "apl"},
+ {ns_t_ds, "DS", "delegation signer"},
+ {ns_t_sshfp, "SSFP", "SSH fingerprint"},
+ {ns_t_ipseckey, "IPSECKEY", "IPSEC key"},
+ {ns_t_rrsig, "RRSIG", "rrsig"},
+ {ns_t_nsec, "NSEC", "nsec"},
+ {ns_t_dnskey, "DNSKEY", "DNS key"},
+ {ns_t_dhcid, "DHCID", "dynamic host configuration identifier"},
+ {ns_t_nsec3, "NSEC3", "nsec3"},
+ {ns_t_nsec3param, "NSEC3PARAM", "NSEC3 parameters"},
+ {ns_t_hip, "HIP", "host identity protocol"},
+ {ns_t_spf, "SPF", "sender policy framework"},
{ns_t_tkey, "TKEY", "tkey"},
{ns_t_tsig, "TSIG", "transaction signature"},
{ns_t_ixfr, "IXFR", "incremental zone transfer"},
@@ -509,6 +527,7 @@ const struct res_sym __p_type_syms[] = {
{ns_t_sink, "SINK", "Kitchen Sink (experimental)"},
{ns_t_opt, "OPT", "EDNS Options"},
{ns_t_any, "ANY", "\"any\""},
+ {ns_t_dlv, "DLV", "DNSSEC look-aside validation"},
{0, NULL, NULL}
};
@@ -936,7 +955,7 @@ loc_aton(ascii, binary)
altsign = -1;
cp++;
}
-
+
if (*cp == '+')
cp++;
@@ -965,7 +984,7 @@ loc_aton(ascii, binary)
goto defaults;
siz = precsize_aton(&cp);
-
+
while (!isspace((unsigned char)*cp) && (cp < maxcp)) /*%< if trailing garbage or m */
cp++;
@@ -998,7 +1017,7 @@ loc_aton(ascii, binary)
PUTLONG(latit,bcp);
PUTLONG(longit,bcp);
PUTLONG(alt,bcp);
-
+
return (16); /*%< size of RR in octets */
}
@@ -1024,7 +1043,7 @@ loc_ntoa(binary, ascii)
int32_t latval, longval, altval;
u_int32_t templ;
u_int8_t sizeval, hpval, vpval, versionval;
-
+
char *sizestr, *hpstr, *vpstr;
versionval = *cp++;
@@ -1138,7 +1157,7 @@ dn_count_labels(const char *name) {
}
/*%
- * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
+ * Make dates expressed in seconds-since-Jan-1-1970 easy to read.
* SIG records are required to be printed like this, by the Secure DNS RFC.
*/
char *
@@ -1148,7 +1167,7 @@ p_secstodate (u_long secs) {
struct tm *time;
#ifdef HAVE_TIME_R
struct tm res;
-
+
time = gmtime_r(&clock, &res);
#else
time = gmtime(&clock);
diff --git a/lib/libc/resolv/res_findzonecut.c b/lib/libc/resolv/res_findzonecut.c
index 23c1af4..92ed5a3 100644
--- a/lib/libc/resolv/res_findzonecut.c
+++ b/lib/libc/resolv/res_findzonecut.c
@@ -1,5 +1,5 @@
#if !defined(lint) && !defined(SABER)
-static const char rcsid[] = "$Id: res_findzonecut.c,v 1.7.18.3 2005/10/11 00:25:11 marka Exp $";
+static const char rcsid[] = "$Id: res_findzonecut.c,v 1.10 2005/10/11 00:10:16 marka Exp $";
#endif /* not lint */
/*
diff --git a/lib/libc/resolv/res_init.c b/lib/libc/resolv/res_init.c
index 5193c1d..b5444ef 100644
--- a/lib/libc/resolv/res_init.c
+++ b/lib/libc/resolv/res_init.c
@@ -66,7 +66,7 @@
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93";
-static const char rcsid[] = "$Id: res_init.c,v 1.16.18.7 2007/07/09 01:52:58 marka Exp $";
+static const char rcsid[] = "$Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -91,6 +91,19 @@ __FBSDID("$FreeBSD$");
#include <unistd.h>
#include <netdb.h>
+#ifndef HAVE_MD5
+# include "../dst/md5.h"
+#else
+# ifdef SOLARIS2
+# include <sys/md5.h>
+# elif _LIBC
+# include <md5.h>
+# endif
+#endif
+#ifndef _MD5_H_
+# define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */
+#endif
+
#include "un-namespace.h"
#include "port_after.h"
@@ -178,9 +191,12 @@ __res_vinit(res_state statp, int preinit) {
statp->retrans = RES_TIMEOUT;
statp->retry = RES_DFLRETRY;
statp->options = RES_DEFAULT;
- statp->id = res_randomid();
}
+ statp->_rnd = malloc(16);
+ res_rndinit(statp);
+ statp->id = res_nrandomid(statp);
+
memset(u, 0, sizeof(u));
#ifdef USELOOPBACK
u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1);
@@ -715,12 +731,48 @@ net_mask(in) /*!< XXX - should really use system's version of this */
}
#endif
+static u_char srnd[16];
+
+void
+res_rndinit(res_state statp)
+{
+ struct timeval now;
+ u_int32_t u32;
+ u_int16_t u16;
+ u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
+
+ gettimeofday(&now, NULL);
+ u32 = now.tv_sec;
+ memcpy(rnd, &u32, 4);
+ u32 = now.tv_usec;
+ memcpy(rnd + 4, &u32, 4);
+ u32 += now.tv_sec;
+ memcpy(rnd + 8, &u32, 4);
+ u16 = getpid();
+ memcpy(rnd + 12, &u16, 2);
+}
+
u_int
-res_randomid(void) {
+res_nrandomid(res_state statp) {
struct timeval now;
+ u_int16_t u16;
+ MD5_CTX ctx;
+ u_char *rnd = statp->_rnd == NULL ? srnd : statp->_rnd;
gettimeofday(&now, NULL);
- return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid()));
+ u16 = (u_int16_t) (now.tv_sec ^ now.tv_usec);
+ memcpy(rnd + 14, &u16, 2);
+#ifndef HAVE_MD5
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, rnd, 16);
+ MD5_Final(rnd, &ctx);
+#else
+ MD5Init(&ctx);
+ MD5Update(&ctx, rnd, 16);
+ MD5Final(rnd, &ctx);
+#endif
+ memcpy(&u16, rnd + 14, 2);
+ return ((u_int) u16);
}
/*%
@@ -750,10 +802,15 @@ res_nclose(res_state statp) {
void
res_ndestroy(res_state statp) {
res_nclose(statp);
- if (statp->_u._ext.ext != NULL)
+ if (statp->_u._ext.ext != NULL) {
free(statp->_u._ext.ext);
+ statp->_u._ext.ext = NULL;
+ }
+ if (statp->_rnd != NULL) {
+ free(statp->_rnd);
+ statp->_rnd = NULL;
+ }
statp->options &= ~RES_INIT;
- statp->_u._ext.ext = NULL;
}
#ifndef _LIBC
diff --git a/lib/libc/resolv/res_mkquery.c b/lib/libc/resolv/res_mkquery.c
index 7bd9cda..b60d8f5 100644
--- a/lib/libc/resolv/res_mkquery.c
+++ b/lib/libc/resolv/res_mkquery.c
@@ -1,7 +1,24 @@
/*
+ * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
* Copyright (c) 1985, 1993
* The Regents of the University of California. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -13,7 +30,7 @@
* 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
@@ -29,14 +46,14 @@
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
+ *
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
@@ -47,26 +64,9 @@
* SOFTWARE.
*/
-/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_mkquery.c 8.1 (Berkeley) 6/4/93";
-static const char rcsid[] = "$Id: res_mkquery.c,v 1.5.18.2 2008/04/03 23:15:15 marka Exp $";
+static const char rcsid[] = "$Id: res_mkquery.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -121,7 +121,8 @@ res_nmkquery(res_state statp,
return (-1);
memset(buf, 0, HFIXEDSZ);
hp = (HEADER *) buf;
- hp->id = htons(++statp->id);
+ statp->id = res_nrandomid(statp);
+ hp->id = htons(statp->id);
hp->opcode = op;
hp->rd = (statp->options & RES_RECURSE) != 0U;
hp->rcode = NOERROR;
diff --git a/lib/libc/resolv/res_mkupdate.c b/lib/libc/resolv/res_mkupdate.c
index 589c056..00bce4c 100644
--- a/lib/libc/resolv/res_mkupdate.c
+++ b/lib/libc/resolv/res_mkupdate.c
@@ -22,7 +22,7 @@
*/
#if !defined(lint) && !defined(SABER)
-static const char rcsid[] = "$Id: res_mkupdate.c,v 1.4.18.4 2005/10/14 05:44:12 marka Exp $";
+static const char rcsid[] = "$Id: res_mkupdate.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
#endif /* not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -116,7 +116,8 @@ res_nmkupdate(res_state statp, ns_updrec *rrecp_in, u_char *buf, int buflen) {
return (-1);
memset(buf, 0, HFIXEDSZ);
hp = (HEADER *) buf;
- hp->id = htons(++statp->id);
+ statp->id = res_nrandomid(statp);
+ hp->id = htons(statp->id);
hp->opcode = ns_o_update;
hp->rcode = NOERROR;
cp = buf + HFIXEDSZ;
diff --git a/lib/libc/resolv/res_query.c b/lib/libc/resolv/res_query.c
index 854909c..4ae97f6 100644
--- a/lib/libc/resolv/res_query.c
+++ b/lib/libc/resolv/res_query.c
@@ -1,7 +1,24 @@
/*
+ * Portions Copyright (C) 2004, 2005, 2008 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2001, 2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -13,7 +30,7 @@
* 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
@@ -29,14 +46,14 @@
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
+ *
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
@@ -47,26 +64,9 @@
* SOFTWARE.
*/
-/*
- * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
- * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
-static const char rcsid[] = "$Id: res_query.c,v 1.7.18.2 2008/04/03 23:15:15 marka Exp $";
+static const char rcsid[] = "$Id: res_query.c,v 1.11 2008/11/14 02:36:51 marka Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
diff --git a/lib/libc/resolv/res_send.c b/lib/libc/resolv/res_send.c
index f7c38c5..fd1cd06 100644
--- a/lib/libc/resolv/res_send.c
+++ b/lib/libc/resolv/res_send.c
@@ -1,7 +1,24 @@
/*
+ * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
+ * Portions Copyright (C) 1996-2003 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+ * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
* Copyright (c) 1985, 1989, 1993
* The Regents of the University of California. All rights reserved.
- *
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -13,7 +30,7 @@
* 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
@@ -29,14 +46,14 @@
/*
* Portions Copyright (c) 1993 by Digital Equipment Corporation.
- *
+ *
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies, and that
* the name of Digital Equipment Corporation not be used in advertising or
* publicity pertaining to distribution of the document or software without
* specific, written prior permission.
- *
+ *
* THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
* WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
@@ -47,26 +64,9 @@
* SOFTWARE.
*/
-/*
- * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
- * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
#if defined(LIBC_SCCS) && !defined(lint)
static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
-static const char rcsid[] = "$Id: res_send.c,v 1.9.18.10 2008/01/27 02:06:26 marka Exp $";
+static const char rcsid[] = "$Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@@ -353,7 +353,7 @@ res_nsend(res_state statp,
if (EXT(statp).nssocks[ns] == -1)
continue;
peerlen = sizeof(peer);
- if (_getsockname(EXT(statp).nssocks[ns],
+ if (_getpeername(EXT(statp).nssocks[ns],
(struct sockaddr *)&peer, &peerlen) < 0) {
needclose++;
break;
@@ -404,7 +404,7 @@ res_nsend(res_state statp,
nstime = EXT(statp).nstimes[0];
for (ns = 0; ns < lastns; ns++) {
if (EXT(statp).ext != NULL)
- EXT(statp).ext->nsaddrs[ns] =
+ EXT(statp).ext->nsaddrs[ns] =
EXT(statp).ext->nsaddrs[ns + 1];
statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
@@ -687,12 +687,12 @@ send_vc(res_state statp,
/*
* Disable generation of SIGPIPE when writing to a closed
* socket. Write should return -1 and set errno to EPIPE
- * instead.
+ * instead.
*
* Push on even if setsockopt(SO_NOSIGPIPE) fails.
*/
(void)_setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
- sizeof(on));
+ sizeof(on));
#endif
errno = 0;
if (_connect(statp->_vcsock, nsap, nsaplen) < 0) {
diff --git a/lib/libc/resolv/res_update.c b/lib/libc/resolv/res_update.c
index a05e26d..8e866e3 100644
--- a/lib/libc/resolv/res_update.c
+++ b/lib/libc/resolv/res_update.c
@@ -1,5 +1,5 @@
#if !defined(lint) && !defined(SABER)
-static const char rcsid[] = "$Id: res_update.c,v 1.12.18.1 2005/04/27 05:01:12 sra Exp $";
+static const char rcsid[] = "$Id: res_update.c,v 1.13 2005/04/27 04:56:43 sra Exp $";
#endif /* not lint */
/*
diff --git a/lib/libc/rpc/clnt_vc.c b/lib/libc/rpc/clnt_vc.c
index 117cfba..b15d69b 100644
--- a/lib/libc/rpc/clnt_vc.c
+++ b/lib/libc/rpc/clnt_vc.c
@@ -141,7 +141,6 @@ static cond_t *vc_cv;
static const char clnt_vc_errstr[] = "%s : %s";
static const char clnt_vc_str[] = "clnt_vc_create";
-static const char clnt_read_vc_str[] = "read_vc";
static const char __no_mem_str[] = "out of memory";
/*
diff --git a/lib/libc/stdio/getline.3 b/lib/libc/stdio/getline.3
index 2161999..05f07d0 100644
--- a/lib/libc/stdio/getline.3
+++ b/lib/libc/stdio/getline.3
@@ -95,6 +95,7 @@ size_t linecap = 0;
ssize_t linelen;
while ((linelen = getline(&line, &linecap, fp)) > 0)
fwrite(line, linelen, 1, stdout);
+free(line);
.Ed
.Sh COMPATIBILITY
Many application writers used the name
diff --git a/lib/libc/stdio/open_memstream.3 b/lib/libc/stdio/open_memstream.3
index 9396830..117dcb2 100644
--- a/lib/libc/stdio/open_memstream.3
+++ b/lib/libc/stdio/open_memstream.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd February 27, 2013
+.Dd October 28, 2014
.Dt OPEN_MEMSTREAM 3
.Os
.Sh NAME
@@ -37,10 +37,10 @@
.Sh SYNOPSIS
.In stdio.h
.Ft FILE *
-.Fn open_memstream "char **bufp" "size_t **sizep"
+.Fn open_memstream "char **bufp" "size_t *sizep"
.In wchar.h
.Ft FILE *
-.Fn open_wmemstream "wchar_t **bufp" "size_t **sizep"
+.Fn open_wmemstream "wchar_t **bufp" "size_t *sizep"
.Sh DESCRIPTION
The
.Fn open_memstream
diff --git a/lib/libc/stdlib/Symbol.map b/lib/libc/stdlib/Symbol.map
index 64c0e16..8355f9a 100644
--- a/lib/libc/stdlib/Symbol.map
+++ b/lib/libc/stdlib/Symbol.map
@@ -106,6 +106,7 @@ FBSD_1.3 {
FBSD_1.4 {
atexit_b;
+ bsearch_b;
heapsort_b;
mergesort_b;
qsort_b;
diff --git a/lib/libc/stdlib/lsearch.c b/lib/libc/stdlib/lsearch.c
index e4d1dd5..9e9cdba 100644
--- a/lib/libc/stdlib/lsearch.c
+++ b/lib/libc/stdlib/lsearch.c
@@ -39,11 +39,7 @@ lwork(const void *key, const void *base, size_t *nelp, size_t width,
{
uint8_t *ep, *endp;
- /*
- * Cast to an integer value first to avoid the warning for removing
- * 'const' via a cast.
- */
- ep = (uint8_t *)(uintptr_t)base;
+ ep = __DECONST(uint8_t *, base);
for (endp = (uint8_t *)(ep + width * *nelp); ep < endp; ep += width) {
if (compar(key, ep) == 0)
return (ep);
diff --git a/lib/libc/stdlib/strtonum.c b/lib/libc/stdlib/strtonum.c
index 6dccd97..aa433d8 100644
--- a/lib/libc/stdlib/strtonum.c
+++ b/lib/libc/stdlib/strtonum.c
@@ -14,7 +14,7 @@
* 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 $
+ * $OpenBSD: strtonum.c,v 1.7 2013/04/17 18:40:58 tedu Exp $
*/
#include <sys/cdefs.h>
@@ -24,17 +24,17 @@ __FBSDID("$FreeBSD$");
#include <limits.h>
#include <stdlib.h>
-#define INVALID 1
-#define TOOSMALL 2
-#define TOOLARGE 3
+#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;
+ char *ep;
struct errval {
const char *errstr;
int err;
@@ -47,9 +47,9 @@ strtonum(const char *numstr, long long minval, long long maxval,
ev[0].err = errno;
errno = 0;
- if (minval > maxval)
+ if (minval > maxval) {
error = INVALID;
- else {
+ } else {
ll = strtoll(numstr, &ep, 10);
if (errno == EINVAL || numstr == ep || *ep != '\0')
error = INVALID;
diff --git a/lib/libc/stdtime/strptime.3 b/lib/libc/stdtime/strptime.3
index 34d2b79..2b50f0e 100644
--- a/lib/libc/stdtime/strptime.3
+++ b/lib/libc/stdtime/strptime.3
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\" "
-.Dd June 25, 2012
+.Dd October 2, 2014
.Dt STRPTIME 3
.Os
.Sh NAME
@@ -80,6 +80,11 @@ and
are now interpreted as beginning at 1969 per POSIX requirements.
Years 69-00 are interpreted in the 20th century (1969-2000), years
01-68 in the 21st century (2001-2068).
+The
+.Fa \&%U
+and
+.Fa %W
+format specifiers accept any value within the range 00 to 53.
.Pp
If the
.Fa format
@@ -161,14 +166,6 @@ and 12PM
is taken as noon.
.Pp
The
-.Fa \&%U
-and
-.Fa %W
-format specifiers accept any value within the range 00 to 53
-without validating against other values supplied (like month
-or day of the year, for example).
-.Pp
-The
.Fa %Z
format specifier only accepts time zone abbreviations of the local time zone,
or the value "GMT".
diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c
index 2333ab4..2be6358 100644
--- a/lib/libc/stdtime/strptime.c
+++ b/lib/libc/stdtime/strptime.c
@@ -55,10 +55,32 @@ __FBSDID("$FreeBSD$");
#include "un-namespace.h"
#include "libc_private.h"
#include "timelocal.h"
+#include "tzfile.h"
static char * _strptime(const char *, const char *, struct tm *, int *, locale_t);
-#define asizeof(a) (sizeof (a) / sizeof ((a)[0]))
+#define asizeof(a) (sizeof(a) / sizeof((a)[0]))
+
+#define FLAG_NONE (1 << 0)
+#define FLAG_YEAR (1 << 1)
+#define FLAG_MONTH (1 << 2)
+#define FLAG_YDAY (1 << 3)
+#define FLAG_MDAY (1 << 4)
+#define FLAG_WDAY (1 << 5)
+
+/*
+ * Calculate the week day of the first day of a year. Valid for
+ * the Gregorian calendar, which began Sept 14, 1752 in the UK
+ * and its colonies. Ref:
+ * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
+ */
+
+static int
+first_wday_of(int year)
+{
+ return (((2 * (3 - (year / 100) % 4)) + (year % 100) +
+ ((year % 100) / 4) + (isleap(year) ? 6 : 0) + 1) % 7);
+}
static char *
_strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
@@ -66,15 +88,21 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
{
char c;
const char *ptr;
+ int day_offset = -1, wday_offset;
+ int week_offset;
int i, len;
+ int flags;
int Ealternative, Oalternative;
- struct lc_time_T *tptr = __get_current_time_locale(locale);
+ const struct lc_time_T *tptr = __get_current_time_locale(locale);
+ static int start_of_month[2][13] = {
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365},
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366}
+ };
+
+ flags = FLAG_NONE;
ptr = fmt;
while (*ptr != 0) {
- if (*buf == 0)
- break;
-
c = *ptr++;
if (c != '%') {
@@ -92,7 +120,6 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp,
label:
c = *ptr++;
switch (c) {
- case 0:
case '%':
if (*buf++ != '%')
return (NULL);
@@ -102,6 +129,7 @@ label:
buf = _strptime(buf, tptr->date_fmt, tm, GMTp, locale);
if (buf == NULL)
return (NULL);
+ flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
break;
case 'C':
@@ -119,19 +147,23 @@ label:
if (i < 19)
return (NULL);
- tm->tm_year = i * 100 - 1900;
+ tm->tm_year = i * 100 - TM_YEAR_BASE;
+ flags |= FLAG_YEAR;
+
break;
case 'c':
buf = _strptime(buf, tptr->c_fmt, tm, GMTp, locale);
if (buf == NULL)
return (NULL);
+ flags |= FLAG_WDAY | FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
break;
case 'D':
buf = _strptime(buf, "%m/%d/%y", tm, GMTp, locale);
if (buf == NULL)
return (NULL);
+ flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
break;
case 'E':
@@ -150,6 +182,7 @@ label:
buf = _strptime(buf, "%Y-%m-%d", tm, GMTp, locale);
if (buf == NULL)
return (NULL);
+ flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
break;
case 'R':
@@ -180,6 +213,7 @@ label:
buf = _strptime(buf, tptr->x_fmt, tm, GMTp, locale);
if (buf == NULL)
return (NULL);
+ flags |= FLAG_MONTH | FLAG_MDAY | FLAG_YEAR;
break;
case 'j':
@@ -197,6 +231,8 @@ label:
return (NULL);
tm->tm_yday = i - 1;
+ flags |= FLAG_YDAY;
+
break;
case 'M':
@@ -302,8 +338,9 @@ label:
if (i == asizeof(tptr->weekday))
return (NULL);
- tm->tm_wday = i;
buf += len;
+ tm->tm_wday = i;
+ flags |= FLAG_WDAY;
break;
case 'U':
@@ -327,6 +364,14 @@ label:
if (i > 53)
return (NULL);
+ if (c == 'U')
+ day_offset = TM_SUNDAY;
+ else
+ day_offset = TM_MONDAY;
+
+
+ week_offset = i;
+
break;
case 'w':
@@ -338,6 +383,7 @@ label:
return (NULL);
tm->tm_wday = i;
+ flags |= FLAG_WDAY;
break;
@@ -374,6 +420,7 @@ label:
return (NULL);
tm->tm_mday = i;
+ flags |= FLAG_MDAY;
break;
@@ -413,6 +460,8 @@ label:
tm->tm_mon = i;
buf += len;
+ flags |= FLAG_MONTH;
+
break;
case 'm':
@@ -430,6 +479,7 @@ label:
return (NULL);
tm->tm_mon = i - 1;
+ flags |= FLAG_MONTH;
break;
@@ -449,8 +499,11 @@ label:
}
errno = sverrno;
buf = cp;
- gmtime_r(&t, tm);
+ if (gmtime_r(&t, tm) == NULL)
+ return (NULL);
*GMTp = 1;
+ flags |= FLAG_YDAY | FLAG_WDAY | FLAG_MONTH |
+ FLAG_MDAY | FLAG_YEAR;
}
break;
@@ -471,13 +524,14 @@ label:
len--;
}
if (c == 'Y')
- i -= 1900;
+ i -= TM_YEAR_BASE;
if (c == 'y' && i < 69)
i += 100;
if (i < 0)
return (NULL);
tm->tm_year = i;
+ flags |= FLAG_YEAR;
break;
@@ -494,7 +548,8 @@ label:
strncpy(zonestr, buf, cp - buf);
zonestr[cp - buf] = '\0';
tzset();
- if (0 == strcmp(zonestr, "GMT")) {
+ if (0 == strcmp(zonestr, "GMT") ||
+ 0 == strcmp(zonestr, "UTC")) {
*GMTp = 1;
} else if (0 == strcmp(zonestr, tzname[0])) {
tm->tm_isdst = 0;
@@ -541,12 +596,72 @@ label:
while (isspace_l((unsigned char)*buf, locale))
buf++;
break;
+
+ default:
+ return (NULL);
}
}
+
+ if (!(flags & FLAG_YDAY) && (flags & FLAG_YEAR)) {
+ if ((flags & (FLAG_MONTH | FLAG_MDAY)) ==
+ (FLAG_MONTH | FLAG_MDAY)) {
+ tm->tm_yday = start_of_month[isleap(tm->tm_year +
+ TM_YEAR_BASE)][tm->tm_mon] + (tm->tm_mday - 1);
+ flags |= FLAG_YDAY;
+ } else if (day_offset != -1) {
+ /* Set the date to the first Sunday (or Monday)
+ * of the specified week of the year.
+ */
+ if (!(flags & FLAG_WDAY)) {
+ tm->tm_wday = day_offset;
+ flags |= FLAG_WDAY;
+ }
+ tm->tm_yday = (7 -
+ first_wday_of(tm->tm_year + TM_YEAR_BASE) +
+ day_offset) % 7 + (week_offset - 1) * 7 +
+ tm->tm_wday - day_offset;
+ flags |= FLAG_YDAY;
+ }
+ }
+
+ if ((flags & (FLAG_YEAR | FLAG_YDAY)) == (FLAG_YEAR | FLAG_YDAY)) {
+ if (!(flags & FLAG_MONTH)) {
+ i = 0;
+ while (tm->tm_yday >=
+ start_of_month[isleap(tm->tm_year +
+ TM_YEAR_BASE)][i])
+ i++;
+ if (i > 12) {
+ i = 1;
+ tm->tm_yday -=
+ start_of_month[isleap(tm->tm_year +
+ TM_YEAR_BASE)][12];
+ tm->tm_year++;
+ }
+ tm->tm_mon = i - 1;
+ flags |= FLAG_MONTH;
+ }
+ if (!(flags & FLAG_MDAY)) {
+ tm->tm_mday = tm->tm_yday -
+ start_of_month[isleap(tm->tm_year + TM_YEAR_BASE)]
+ [tm->tm_mon] + 1;
+ flags |= FLAG_MDAY;
+ }
+ if (!(flags & FLAG_WDAY)) {
+ i = 0;
+ wday_offset = first_wday_of(tm->tm_year);
+ while (i++ <= tm->tm_yday) {
+ if (wday_offset++ >= 6)
+ wday_offset = 0;
+ }
+ tm->tm_wday = wday_offset;
+ flags |= FLAG_WDAY;
+ }
+ }
+
return ((char *)buf);
}
-
char *
strptime_l(const char * __restrict buf, const char * __restrict fmt,
struct tm * __restrict tm, locale_t loc)
@@ -559,11 +674,13 @@ strptime_l(const char * __restrict buf, const char * __restrict fmt,
ret = _strptime(buf, fmt, tm, &gmt, loc);
if (ret && gmt) {
time_t t = timegm(tm);
+
localtime_r(&t, tm);
}
return (ret);
}
+
char *
strptime(const char * __restrict buf, const char * __restrict fmt,
struct tm * __restrict tm)
diff --git a/lib/libc/string/Makefile.inc b/lib/libc/string/Makefile.inc
index 731f4fc..1217b7b 100644
--- a/lib/libc/string/Makefile.inc
+++ b/lib/libc/string/Makefile.inc
@@ -2,11 +2,13 @@
# $FreeBSD$
.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/string ${LIBC_SRCTOP}/string
+.PATH: ${LIBC_SRCTOP}/../../sys/libkern
CFLAGS+= -I${LIBC_SRCTOP}/locale
# machine-independent string sources
-MISRCS+=bcmp.c bcopy.c bzero.c ffs.c ffsl.c ffsll.c fls.c flsl.c flsll.c \
+MISRCS+=bcmp.c bcopy.c bzero.c explicit_bzero.c \
+ ffs.c ffsl.c ffsll.c fls.c flsl.c flsll.c \
memccpy.c memchr.c memrchr.c memcmp.c \
memcpy.c memmem.c memmove.c memset.c \
stpcpy.c stpncpy.c strcasecmp.c \
@@ -35,6 +37,7 @@ MAN+= bcmp.3 bcopy.3 bstring.3 bzero.3 ffs.3 index.3 memccpy.3 memchr.3 \
strspn.3 strstr.3 strtok.3 strxfrm.3 swab.3 wcscoll.3 wcstok.3 \
wcswidth.3 wcsxfrm.3 wmemchr.3
+MLINKS+=bzero.3 explicit_bzero.3
MLINKS+=ffs.3 ffsl.3 \
ffs.3 ffsll.3 \
ffs.3 fls.3 \
diff --git a/lib/libc/string/Symbol.map b/lib/libc/string/Symbol.map
index 8e80165..5961092 100644
--- a/lib/libc/string/Symbol.map
+++ b/lib/libc/string/Symbol.map
@@ -100,6 +100,10 @@ FBSD_1.3 {
wcwidth_l;
};
+FBSD_1.4 {
+ explicit_bzero;
+};
+
FBSDprivate_1.0 {
__strtok_r;
};
diff --git a/lib/libc/string/bzero.3 b/lib/libc/string/bzero.3
index 029644a..5af1bcf 100644
--- a/lib/libc/string/bzero.3
+++ b/lib/libc/string/bzero.3
@@ -31,11 +31,12 @@
.\" @(#)bzero.3 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd June 4, 1993
+.Dd October 6, 2014
.Dt BZERO 3
.Os
.Sh NAME
-.Nm bzero
+.Nm bzero ,
+.Nm explicit_bzero
.Nd write zeroes to a byte string
.Sh LIBRARY
.Lb libc
@@ -43,6 +44,8 @@
.In strings.h
.Ft void
.Fn bzero "void *b" "size_t len"
+.Ft void
+.Fn explicit_bzero "void *b" "size_t len"
.Sh DESCRIPTION
The
.Fn bzero
@@ -56,6 +59,12 @@ If
is zero,
.Fn bzero
does nothing.
+.Pp
+The
+.Fn explicit_bzero
+variant behaves the same, but will not be removed by a compiler's dead store
+optimization pass, making it useful for clearing sensitive memory such as a
+password.
.Sh SEE ALSO
.Xr memset 3 ,
.Xr swab 3
@@ -72,3 +81,10 @@ before it was moved to
for
.St -p1003.1-2001
compliance.
+.Pp
+The
+.Fn explicit_bzero
+function first appeared in
+.Ox 5.5
+and
+.Fx 11.0 .
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index 07a4537..c14b351 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -356,6 +356,7 @@ MLINKS+=pdfork.2 pdgetpid.2\
pdfork.2 pdkill.2 \
pdfork.2 pdwait4.2
MLINKS+=pipe.2 pipe2.2
+MLINKS+=poll.2 ppoll.2
MLINKS+=read.2 pread.2 \
read.2 preadv.2 \
read.2 readv.2
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index fe887c3..448bcce 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -399,6 +399,10 @@ FBSD_1.3 {
wait6;
};
+FBSD_1.4 {
+ ppoll;
+};
+
FBSDprivate_1.0 {
___acl_aclcheck_fd;
__sys___acl_aclcheck_fd;
@@ -821,6 +825,8 @@ FBSDprivate_1.0 {
__sys_pipe;
_poll;
__sys_poll;
+ _ppoll;
+ __sys_ppoll;
_preadv;
__sys_preadv;
_procctl;
diff --git a/lib/libc/sys/accept.2 b/lib/libc/sys/accept.2
index 0363158..7e60ccc 100644
--- a/lib/libc/sys/accept.2
+++ b/lib/libc/sys/accept.2
@@ -28,7 +28,7 @@
.\" @(#)accept.2 8.2 (Berkeley) 12/11/93
.\" $FreeBSD$
.\"
-.Dd October 1, 2013
+.Dd October 9, 2014
.Dt ACCEPT 2
.Os
.Sh NAME
@@ -201,7 +201,7 @@ The
.Fa addr
argument is not in a writable part of the
user address space.
-.It Bq Er EWOULDBLOCK
+.It Bo Er EWOULDBLOCK Bc or Bq Er EAGAIN
The socket is marked non-blocking and no connections
are present to be accepted.
.It Bq Er ECONNABORTED
diff --git a/lib/libc/sys/access.2 b/lib/libc/sys/access.2
index 65b8fb6..46bf948 100644
--- a/lib/libc/sys/access.2
+++ b/lib/libc/sys/access.2
@@ -28,7 +28,7 @@
.\" @(#)access.2 8.2 (Berkeley) 4/1/94
.\" $FreeBSD$
.\"
-.Dd April 10, 2008
+.Dd September 15, 2014
.Dt ACCESS 2
.Os
.Sh NAME
@@ -133,8 +133,16 @@ and
.Sh RETURN VALUES
.Rv -std
.Sh ERRORS
-Access to the file is denied if:
+.Fn access ,
+.Fn eaccess ,
+or
+.Fn faccessat
+will fail if:
.Bl -tag -width Er
+.It Bq Er EINVAL
+The value of the
+.Fa mode
+argument is invalid.
.It Bq Er ENOTDIR
A component of the path prefix is not a directory.
.It Bq Er ENAMETOOLONG
diff --git a/lib/libc/sys/connect.2 b/lib/libc/sys/connect.2
index 8ed3f12..e3e5783 100644
--- a/lib/libc/sys/connect.2
+++ b/lib/libc/sys/connect.2
@@ -28,7 +28,7 @@
.\" @(#)connect.2 8.1 (Berkeley) 6/4/93
.\" $FreeBSD$
.\"
-.Dd June 26, 2014
+.Dd September 29, 2014
.Dt CONNECT 2
.Os
.Sh NAME
@@ -160,6 +160,8 @@ Search permission is denied for a component of the path prefix.
Write access to the named socket is denied.
.It Bq Er ELOOP
Too many symbolic links were encountered in translating the pathname.
+.It Bq Er EPERM
+Write access to the named socket is denied.
.El
.Sh SEE ALSO
.Xr accept 2 ,
diff --git a/lib/libc/sys/kqueue.2 b/lib/libc/sys/kqueue.2
index f84bc05..9a7cc23 100644
--- a/lib/libc/sys/kqueue.2
+++ b/lib/libc/sys/kqueue.2
@@ -478,7 +478,6 @@ is in microseconds.
.It Dv NOTE_NSECONDS
.Va data
is in nanoseconds.
-.It
.El
.Pp
If
diff --git a/lib/libc/sys/mmap.2 b/lib/libc/sys/mmap.2
index 3dd8303..7380a7f 100644
--- a/lib/libc/sys/mmap.2
+++ b/lib/libc/sys/mmap.2
@@ -28,7 +28,7 @@
.\" @(#)mmap.2 8.4 (Berkeley) 5/11/95
.\" $FreeBSD$
.\"
-.Dd June 19, 2014
+.Dd September 17, 2014
.Dt MMAP 2
.Os
.Sh NAME
@@ -176,11 +176,6 @@ already exists within the range.
.It Dv MAP_HASSEMAPHORE
Notify the kernel that the region may contain semaphores and that special
handling may be necessary.
-.It Dv MAP_INHERIT
-This flag never operated as advertised and is no longer supported.
-Please refer to
-.Xr minherit 2
-for further information.
.It Dv MAP_NOCORE
Region is not included in a core file.
.It Dv MAP_NOSYNC
@@ -300,14 +295,6 @@ The
system call does not unmap pages, see
.Xr munmap 2
for further information.
-.Pp
-The current design does not allow a process to specify the location of
-swap space.
-In the future we may define an additional mapping type,
-.Dv MAP_SWAP ,
-in which
-the file descriptor argument specifies a file or device to which swapping
-should be done.
.Sh NOTES
Although this implementation does not impose any alignment restrictions on
the
@@ -372,6 +359,29 @@ The
argument
is not a valid open file descriptor.
.It Bq Er EINVAL
+An invalid value was passed in the
+.Fa prot
+argument.
+.It Bq Er EINVAL
+An undefined option was set in the
+.Fa flags
+argument.
+.It Bq Er EINVAL
+Both
+.Dv MAP_PRIVATE
+and
+.Dv MAP_SHARED
+were specified.
+.It Bq Er EINVAL
+None of
+.Dv MAP_ANON ,
+.Dv MAP_PRIVATE ,
+.Dv MAP_SHARED ,
+or
+.Dv MAP_STACK
+was specified.
+At least one of these flags must be included.
+.It Bq Er EINVAL
.Dv MAP_FIXED
was specified and the
.Fa addr
diff --git a/lib/libc/sys/mq_open.2 b/lib/libc/sys/mq_open.2
index 5acc59b..ef6154b 100644
--- a/lib/libc/sys/mq_open.2
+++ b/lib/libc/sys/mq_open.2
@@ -37,7 +37,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd November 29, 2005
+.Dd September 15, 2014
.Dt MQ_OPEN 2
.Os
.Sh NAME
@@ -223,6 +223,11 @@ The
and
.Xr kevent 2
system calls are supported for message queue descriptor.
+.Pp
+Please see the
+.Xr mqueuefs 5
+man page for instructions on loading the module or compiling the service into
+the kernel.
.Sh RETURN VALUES
Upon successful completion, the function returns a message queue
descriptor; otherwise, the function returns
@@ -294,7 +299,8 @@ There is insufficient space for the creation of the new message queue.
.Xr mq_setattr 2 ,
.Xr mq_timedreceive 3 ,
.Xr mq_timedsend 3 ,
-.Xr mq_unlink 3
+.Xr mq_unlink 3 ,
+.Xr mqueuefs 5
.Sh STANDARDS
The
.Fn mq_open
diff --git a/lib/libc/sys/poll.2 b/lib/libc/sys/poll.2
index 932186d..a1c7ada 100644
--- a/lib/libc/sys/poll.2
+++ b/lib/libc/sys/poll.2
@@ -28,7 +28,7 @@
.\" (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 July 8, 2002
+.Dd November 13, 2014
.Dt POLL 2
.Os
.Sh NAME
@@ -40,6 +40,13 @@
.In poll.h
.Ft int
.Fn poll "struct pollfd fds[]" "nfds_t nfds" "int timeout"
+.Ft int
+.Fo ppoll
+.Fa "struct pollfd fds[]"
+.Fa "nfds_t nfds"
+.Fa "const struct timespec * restrict timeout"
+.Fa "const sigset_t * restrict newsigmask"
+.Fc
.Sh DESCRIPTION
The
.Fn poll
@@ -139,6 +146,47 @@ If
is zero, then
.Fn poll
will return without blocking.
+.Pp
+The
+.Fn ppoll
+system call, unlike
+.Fn poll ,
+is used to safely wait until either a set of file descriptors becomes
+ready or until a signal is caught.
+The
+.Fa fds
+and
+.Fa nfds
+arguments are identical to the analogous arguments of
+.Fn poll .
+The
+.Fa timeout
+argument in
+.Fn ppoll
+points to a
+.Vt "const struct timespec"
+which is defined in
+.In sys/timespec.h
+(shown below) rather than the
+.Vt "int timeout"
+used by
+.Fn poll .
+A null pointer may be passed to indicate that
+.Fn ppoll
+should wait indefinitely.
+Finally,
+.Fa newsigmask
+specifies a signal mask which is set while waiting for input.
+When
+.Fn ppoll
+returns, the original signal mask is restored.
+.Pp
+.Bd -literal
+struct timespec {
+ time_t tv_sec; /* seconds */
+ long tv_nsec; /* and nanoseconds */
+};
+.Ed
.Sh RETURN VALUES
The
.Fn poll
@@ -185,17 +233,26 @@ points outside the process's allocated address space.
A signal was delivered before the time limit expired and
before any of the selected events occurred.
.It Bq Er EINVAL
-The specified time limit is negative.
+The specified time limit is invalid. One of its components is negative or too large.
.El
.Sh SEE ALSO
.Xr accept 2 ,
.Xr connect 2 ,
.Xr kqueue 2 ,
+.Xr pselect 2 ,
.Xr read 2 ,
.Xr recv 2 ,
.Xr select 2 ,
.Xr send 2 ,
.Xr write 2
+.Sh STANDARDS
+The
+.Fn poll
+function conforms to
+.St -p1003.1-2001 .
+The
+.Fn ppoll
+is not specified by POSIX.
.Sh HISTORY
The
.Fn poll
@@ -203,6 +260,10 @@ function appeared in
.At V .
This manual page and the core of the implementation was taken from
.Nx .
+The
+.Fn ppoll
+function first appeared in
+.Fx 11.0
.Sh BUGS
The distinction between some of the fields in the
.Fa events
diff --git a/lib/libc/sys/recv.2 b/lib/libc/sys/recv.2
index e0a1f04..326e7ff 100644
--- a/lib/libc/sys/recv.2
+++ b/lib/libc/sys/recv.2
@@ -28,7 +28,7 @@
.\" @(#)recv.2 8.3 (Berkeley) 2/21/94
.\" $FreeBSD$
.\"
-.Dd March 19, 2013
+.Dd October 15, 2014
.Dt RECV 2
.Os
.Sh NAME
@@ -324,9 +324,9 @@ In this case the descriptors are
closed, any pending data can be returned by another call to
.Fn recvmsg .
.It Bq Er EAGAIN
-The socket is marked non-blocking, and the receive operation
+The socket is marked non-blocking and the receive operation
would block, or
-a receive timeout had been set,
+a receive timeout had been set
and the timeout expired before data were received.
.It Bq Er EINTR
The receive was interrupted by delivery of a signal before
diff --git a/lib/libc/sys/utrace.2 b/lib/libc/sys/utrace.2
index 5177288..9d24f20 100644
--- a/lib/libc/sys/utrace.2
+++ b/lib/libc/sys/utrace.2
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 28, 2000
+.Dd November 1, 2014
.Dt UTRACE 2
.Os
.Sh NAME
@@ -37,7 +37,6 @@
.Sh LIBRARY
.Lb libc
.Sh SYNOPSIS
-.In sys/types.h
.In sys/param.h
.In sys/time.h
.In sys/uio.h
diff --git a/lib/libc/tests/Makefile b/lib/libc/tests/Makefile
new file mode 100644
index 0000000..3036ce9
--- /dev/null
+++ b/lib/libc/tests/Makefile
@@ -0,0 +1,32 @@
+# $FreeBSD$
+
+.include <src.opts.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc
+
+SUBDIR= tls_dso
+
+TESTS_SUBDIRS= c063
+TESTS_SUBDIRS+= db
+TESTS_SUBDIRS+= gen
+TESTS_SUBDIRS+= hash
+TESTS_SUBDIRS+= inet
+TESTS_SUBDIRS+= net
+TESTS_SUBDIRS+= regex
+TESTS_SUBDIRS+= stdio
+TESTS_SUBDIRS+= stdlib
+TESTS_SUBDIRS+= string
+TESTS_SUBDIRS+= sys
+TESTS_SUBDIRS+= termios
+TESTS_SUBDIRS+= tls
+TESTS_SUBDIRS+= ttyio
+
+.if ${MK_LOCALES} != "no"
+TESTS_SUBDIRS+= locale
+.endif
+
+.if ${MK_SSP} != "no"
+TESTS_SUBDIRS+= ssp
+.endif
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/Makefile.netbsd-tests b/lib/libc/tests/Makefile.netbsd-tests
new file mode 100644
index 0000000..f364b1c
--- /dev/null
+++ b/lib/libc/tests/Makefile.netbsd-tests
@@ -0,0 +1,7 @@
+# $FreeBSD$
+
+OBJTOP?= ${.OBJDIR:H:H:H:H}
+SRCTOP?= ${.CURDIR:H:H:H:H}
+TESTSRC?= ${SRCTOP}/contrib/netbsd-tests/lib/libc/${.CURDIR:T}
+
+.include <netbsd-tests.test.mk>
diff --git a/lib/libc/tests/c063/Makefile b/lib/libc/tests/c063/Makefile
new file mode 100644
index 0000000..b743165
--- /dev/null
+++ b/lib/libc/tests/c063/Makefile
@@ -0,0 +1,24 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/c063
+
+#TODO: t_o_search, t_utimensat
+
+NETBSD_ATF_TESTS_C= t_faccessat
+NETBSD_ATF_TESTS_C+= t_fchmodat
+NETBSD_ATF_TESTS_C+= t_fchownat
+NETBSD_ATF_TESTS_C+= t_fexecve
+NETBSD_ATF_TESTS_C+= t_fstatat
+NETBSD_ATF_TESTS_C+= t_linkat
+NETBSD_ATF_TESTS_C+= t_mkdirat
+NETBSD_ATF_TESTS_C+= t_mkfifoat
+NETBSD_ATF_TESTS_C+= t_mknodat
+NETBSD_ATF_TESTS_C+= t_openat
+NETBSD_ATF_TESTS_C+= t_readlinkat
+NETBSD_ATF_TESTS_C+= t_renameat
+NETBSD_ATF_TESTS_C+= t_symlinkat
+NETBSD_ATF_TESTS_C+= t_unlinkat
+
+CFLAGS+= -D_INCOMPLETE_XOPEN_C063
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/db/Makefile b/lib/libc/tests/db/Makefile
new file mode 100644
index 0000000..323a9f0
--- /dev/null
+++ b/lib/libc/tests/db/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/db
+
+BINDIR= ${TESTSDIR}
+
+PROGS= h_db
+
+FILESDIR= ${TESTSDIR}
+
+FILES= README
+
+NETBSD_ATF_TESTS_SH+= db_test
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/gen/Makefile b/lib/libc/tests/gen/Makefile
new file mode 100644
index 0000000..f9a0bd4
--- /dev/null
+++ b/lib/libc/tests/gen/Makefile
@@ -0,0 +1,61 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/gen
+
+ATF_TESTS_C= arc4random_test
+ATF_TESTS_C+= fpclassify2_test
+
+# TODO: t_closefrom, t_cpuset, t_fmtcheck, t_randomid, t_sleep
+# TODO: t_siginfo (fixes require further inspection)
+# TODO: t_sethostname_test (consistently screws up the hostname)
+
+NETBSD_ATF_TESTS_C= alarm_test
+NETBSD_ATF_TESTS_C+= assert_test
+NETBSD_ATF_TESTS_C+= basedirname_test
+NETBSD_ATF_TESTS_C+= dir_test
+NETBSD_ATF_TESTS_C+= floatunditf_test
+NETBSD_ATF_TESTS_C+= fnmatch_test
+NETBSD_ATF_TESTS_C+= fpclassify_test
+NETBSD_ATF_TESTS_C+= fpsetmask_test
+NETBSD_ATF_TESTS_C+= fpsetround_test
+NETBSD_ATF_TESTS_C+= ftok_test
+NETBSD_ATF_TESTS_C+= getcwd_test
+NETBSD_ATF_TESTS_C+= getgrent_test
+NETBSD_ATF_TESTS_C+= glob_test
+NETBSD_ATF_TESTS_C+= humanize_number_test
+NETBSD_ATF_TESTS_C+= isnan_test
+NETBSD_ATF_TESTS_C+= nice_test
+NETBSD_ATF_TESTS_C+= pause_test
+NETBSD_ATF_TESTS_C+= raise_test
+NETBSD_ATF_TESTS_C+= realpath_test
+NETBSD_ATF_TESTS_C+= setdomainname_test
+NETBSD_ATF_TESTS_C+= sethostname_test
+NETBSD_ATF_TESTS_C+= sleep_test
+NETBSD_ATF_TESTS_C+= syslog_test
+NETBSD_ATF_TESTS_C+= time_test
+NETBSD_ATF_TESTS_C+= ttyname_test
+NETBSD_ATF_TESTS_C+= vis_test
+
+.include "../Makefile.netbsd-tests"
+
+LDADD.humanize_number_test+= -lutil
+DPADD.humanize_number_test+= ${LIBUTIL}
+
+LDADD.fpclassify_test+= -lm
+DPADD.fpclassify_test+= ${LIBM}
+LDADD.fpsetround_test+= -lm
+DPADD.fpsetround_test+= ${LIBM}
+LDADD.siginfo_test+= -lm
+DPADD.siginfo_test+= ${LIBM}
+
+LDADD.nice_test+= -lpthread
+DPADD.nice_test+= ${LIBPTHREAD}
+LDADD.syslog_test+= -lpthread
+DPADD.syslog_test+= ${LIBPTHREAD}
+
+TESTS_SUBDIRS= execve
+TESTS_SUBDIRS+= posix_spawn
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/gen/arc4random_test.c b/lib/libc/tests/gen/arc4random_test.c
new file mode 100644
index 0000000..ec82c32
--- /dev/null
+++ b/lib/libc/tests/gen/arc4random_test.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2011 David Schultz
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <atf-c.h>
+
+/*
+ * BUFSIZE is the number of bytes of rc4 output to compare. The probability
+ * that this test fails spuriously is 2**(-BUFSIZE * 8).
+ */
+#define BUFSIZE 8
+
+/*
+ * Test whether arc4random_buf() returns the same sequence of bytes in both
+ * parent and child processes. (Hint: It shouldn't.)
+ */
+ATF_TC_WITHOUT_HEAD(test_arc4random);
+ATF_TC_BODY(test_arc4random, tc)
+{
+ struct shared_page {
+ char parentbuf[BUFSIZE];
+ char childbuf[BUFSIZE];
+ } *page;
+ pid_t pid;
+ char c;
+
+ printf("1..1\n");
+
+ page = mmap(NULL, sizeof(struct shared_page), PROT_READ | PROT_WRITE,
+ MAP_ANON | MAP_SHARED, -1, 0);
+ if (page == MAP_FAILED) {
+ printf("fail 1 - mmap\n");
+ exit(1);
+ }
+
+ arc4random_buf(&c, 1);
+
+ pid = fork();
+ ATF_REQUIRE(0 <= pid);
+ if (pid == 0) {
+ /* child */
+ arc4random_buf(page->childbuf, BUFSIZE);
+ exit(0);
+ } else {
+ /* parent */
+ int status;
+ arc4random_buf(page->parentbuf, BUFSIZE);
+ wait(&status);
+ }
+ ATF_CHECK_MSG(memcmp(page->parentbuf, page->childbuf, BUFSIZE) != 0,
+ "sequences are the same");
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, test_arc4random);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/execve/Makefile b/lib/libc/tests/gen/execve/Makefile
new file mode 100644
index 0000000..2106a15
--- /dev/null
+++ b/lib/libc/tests/gen/execve/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/gen/${.CURDIR:T}
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/gen/execve
+
+NETBSD_ATF_TESTS_C= execve_test
+
+.include "../../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/gen/fpclassify2_test.c b/lib/libc/tests/gen/fpclassify2_test.c
new file mode 100644
index 0000000..a6bb1df
--- /dev/null
+++ b/lib/libc/tests/gen/fpclassify2_test.c
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(test_fpclassify);
+ATF_TC_BODY(test_fpclassify, tc)
+{
+
+ ATF_CHECK(fpclassify((float)0) == FP_ZERO);
+ ATF_CHECK(fpclassify((float)-0.0) == FP_ZERO);
+ ATF_CHECK(fpclassify((float)1) == FP_NORMAL);
+ ATF_CHECK(fpclassify((float)1000) == FP_NORMAL);
+ ATF_CHECK(fpclassify(HUGE_VALF) == FP_INFINITE);
+ ATF_CHECK(fpclassify((float)HUGE_VAL) == FP_INFINITE);
+ ATF_CHECK(fpclassify((float)HUGE_VALL) == FP_INFINITE);
+ ATF_CHECK(fpclassify(NAN) == FP_NAN);
+
+ ATF_CHECK(fpclassify((double)0) == FP_ZERO);
+ ATF_CHECK(fpclassify((double)-0) == FP_ZERO);
+ ATF_CHECK(fpclassify((double)1) == FP_NORMAL);
+ ATF_CHECK(fpclassify((double)1000) == FP_NORMAL);
+ ATF_CHECK(fpclassify(HUGE_VAL) == FP_INFINITE);
+ ATF_CHECK(fpclassify((double)HUGE_VALF) == FP_INFINITE);
+ ATF_CHECK(fpclassify((double)HUGE_VALL) == FP_INFINITE);
+ ATF_CHECK(fpclassify((double)NAN) == FP_NAN);
+
+ ATF_CHECK(fpclassify((long double)0) == FP_ZERO);
+ ATF_CHECK(fpclassify((long double)-0.0) == FP_ZERO);
+ ATF_CHECK(fpclassify((long double)1) == FP_NORMAL);
+ ATF_CHECK(fpclassify((long double)1000) == FP_NORMAL);
+ ATF_CHECK(fpclassify(HUGE_VALL) == FP_INFINITE);
+ ATF_CHECK(fpclassify((long double)HUGE_VALF) == FP_INFINITE);
+ ATF_CHECK(fpclassify((long double)HUGE_VAL) == FP_INFINITE);
+ ATF_CHECK(fpclassify((long double)NAN) == FP_NAN);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, test_fpclassify);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/gen/posix_spawn/Makefile b/lib/libc/tests/gen/posix_spawn/Makefile
new file mode 100644
index 0000000..a1c9b9e
--- /dev/null
+++ b/lib/libc/tests/gen/posix_spawn/Makefile
@@ -0,0 +1,34 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/gen/${.CURDIR:T}
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/gen/posix_spawn
+
+BINDIR= ${TESTSDIR}
+
+# TODO: t_spawnattr (fix from pho@ needs additional review)
+NETBSD_ATF_TESTS_C= fileactions_test
+NETBSD_ATF_TESTS_C+= spawn_test
+
+PROGS= h_fileactions
+PROGS+= h_spawn
+PROGS+= h_spawnattr
+
+SCRIPTS= h_nonexec
+SCRIPTS+= h_zero
+
+.include "../../Makefile.netbsd-tests"
+
+h_zero:
+ dd if=/dev/zero of=h_zero bs=1k count=2
+ chmod a+x h_zero
+
+CLEANFILES+= h_zero
+
+WARNS?=3
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/hash/Makefile b/lib/libc/tests/hash/Makefile
new file mode 100644
index 0000000..df9d6d9
--- /dev/null
+++ b/lib/libc/tests/hash/Makefile
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/hash
+
+NETBSD_ATF_TESTS_C= sha2_test
+
+NETBSD_ATF_TESTS_SH= hash_test
+
+BINDIR= ${TESTSDIR}
+
+PROGS+= h_hash
+
+FILESDIR= ${TESTSDIR}/data
+
+FILES+= data/md5test-in
+FILES+= data/md5test-out
+FILES+= data/sha1test-in
+FILES+= data/sha1test-out
+FILES+= data/sha1test2-out
+
+DPADD+= ${LIBMD}
+LDADD+= -lmd
+DPADD.sha2_test+= ${LIBCRYPTO}
+LDADD.sha2_test+= -lcrypto
+
+CFLAGS.sha2_test+= -I${.CURDIR}/../../../../crypto/openssh/openbsd-compat
+CFLAGS.sha2_test+= -I${.CURDIR}/../../../../crypto/openssh
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/inet/Makefile b/lib/libc/tests/inet/Makefile
new file mode 100644
index 0000000..a15b96a
--- /dev/null
+++ b/lib/libc/tests/inet/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/inet
+
+NETBSD_ATF_TESTS_C= inet_network_test
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/locale/Makefile b/lib/libc/tests/locale/Makefile
new file mode 100644
index 0000000..e4dc553
--- /dev/null
+++ b/lib/libc/tests/locale/Makefile
@@ -0,0 +1,22 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/locale
+
+NETBSD_ATF_TESTS_C= io_test
+NETBSD_ATF_TESTS_C+= mbrtowc_test
+NETBSD_ATF_TESTS_C+= mbstowcs_test
+NETBSD_ATF_TESTS_C+= mbsnrtowcs_test
+NETBSD_ATF_TESTS_C+= mbtowc_test
+NETBSD_ATF_TESTS_C+= wcscspn_test
+NETBSD_ATF_TESTS_C+= wcspbrk_test
+NETBSD_ATF_TESTS_C+= wcsspn_test
+NETBSD_ATF_TESTS_C+= wcstod_test
+NETBSD_ATF_TESTS_C+= wctomb_test
+
+CFLAGS.t_wctomb.c+= -Wno-stack-protector
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/net/Makefile b/lib/libc/tests/net/Makefile
new file mode 100644
index 0000000..eb199f0
--- /dev/null
+++ b/lib/libc/tests/net/Makefile
@@ -0,0 +1,39 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/net
+
+BINDIR= ${TESTSDIR}
+
+NETBSD_ATF_TESTS_C= getprotoent_test
+NETBSD_ATF_TESTS_C+= ether_aton_test
+
+SRCS.t_ether_aton= aton_ether_subr.c t_ether_aton.c
+
+aton_ether_subr.c: gen_ether_subr ${.CURDIR:H:H:H:H}/sys/net/if_ethersubr.c
+ ${HOST_SH} ${.ALLSRC} ${.TARGET}
+
+# TODO: hostent_test
+NETBSD_ATF_TESTS_SH= nsdispatch_test
+NETBSD_ATF_TESTS_SH+= protoent_test
+NETBSD_ATF_TESTS_SH+= servent_test
+
+PROGS= h_nsd_recurse
+PROGS+= h_protoent
+PROGS+= h_servent
+PROGS+= h_dns_server
+
+DPADD.h_nsd_recurse+= ${LIBPTHREAD}
+LDADD.h_nsd_recurse+= -lpthread
+
+CLEANFILES+= aton_ether_subr.c
+
+.include "../Makefile.netbsd-tests"
+
+# TODO: the testcases needs to be ported to FreeBSD
+#TESTS_SUBDIRS= getaddrinfo
+FILES= hosts
+FILES+= resolv.conf
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/net/getaddrinfo/Makefile b/lib/libc/tests/net/getaddrinfo/Makefile
new file mode 100644
index 0000000..a6b9eb1
--- /dev/null
+++ b/lib/libc/tests/net/getaddrinfo/Makefile
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/net/${.CURDIR:T}
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/net/getaddrinfo
+
+BINDIR= ${TESTSDIR}
+
+.error "This testcase needs to be ported to FreeBSD (the output from getaddrinfo_test differs from NetBSD)"
+
+NETBSD_ATF_TESTS_SH= getaddrinfo_test
+
+PROGS= h_gai
+
+FILESDIR= ${TESTSDIR}/data
+
+FILES= basics_v4.exp basics_v4v6.exp
+FILES+= no_host_v4.exp no_host_v4v6.exp
+FILES+= no_serv_v4.exp no_serv_v4v6.exp
+FILES+= sock_raw_v4.exp sock_raw_v4v6.exp
+FILES+= spec_fam_v4.exp spec_fam_v4v6.exp
+FILES+= scoped.exp
+FILES+= unsup_fam.exp
+
+.include "../../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/regex/Makefile b/lib/libc/tests/regex/Makefile
new file mode 100644
index 0000000..37b3277
--- /dev/null
+++ b/lib/libc/tests/regex/Makefile
@@ -0,0 +1,59 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+BINDIR= ${TESTSDIR}
+
+TESTSDIR= ${TESTSBASE}/lib/libc/regex
+
+IMPLEMENTATION?= -DREGEX_SPENCER
+
+CFLAGS.h_regex+=-I${TESTSRC} -I${.CURDIR:H:H}/regex
+PROGS+= h_regex
+SRCS.h_regex= main.c split.c debug.c
+
+NETBSD_ATF_TESTS_SH= regex_test
+
+FILESDIR= ${TESTSDIR}/data
+FILES+= README
+FILES+= data/anchor.in
+FILES+= data/backref.in
+FILES+= data/basic.in
+FILES+= data/bracket.in
+FILES+= data/c_comments.in
+FILES+= data/complex.in
+FILES+= data/error.in
+FILES+= data/meta.in
+FILES+= data/nospec.in
+FILES+= data/paren.in
+FILES+= data/regress.in
+FILES+= data/repet_bounded.in
+FILES+= data/repet_multi.in
+FILES+= data/repet_ordinary.in
+FILES+= data/startend.in
+FILES+= data/subexp.in
+FILES+= data/subtle.in
+FILES+= data/word_bound.in
+FILES+= data/zero.in
+#FILES+= data/att/README
+FILES+= data/att/basic.dat
+FILES+= data/att/categorization.dat
+FILES+= data/att/forcedassoc.dat
+FILES+= data/att/leftassoc.dat
+FILES+= data/att/nullsubexpr.dat
+FILES+= data/att/repetition.dat
+FILES+= data/att/rightassoc.dat
+
+NETBSD_ATF_TESTS_C= exhaust_test
+NETBSD_ATF_TESTS_C+= regex_att_test
+
+.for t in ${NETBSD_ATF_TESTS_C}
+CFLAGS.$t+= -I${TESTSRC} ${IMPLEMENTATION}
+.endfor
+
+.include "../Makefile.netbsd-tests"
+
+DPADD.regex_att_test+= ${LIBUTIL}
+LDADD.regex_att_test+= -lutil
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/rpc/Makefile b/lib/libc/tests/rpc/Makefile
new file mode 100644
index 0000000..0380294
--- /dev/null
+++ b/lib/libc/tests/rpc/Makefile
@@ -0,0 +1,27 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/rpc
+SRCS.xdr_test= ${RPCSRC:.x=_xdr.c} t_xdr.c ${RPCSRC:.x=.h}
+
+NETBSD_ATF_TESTS_C= rpc_test
+NETBSD_ATF_TESTS_C+= xdr_test
+
+RPCSRC= h_testbits.x
+RPCGEN= RPCGEN_CPP=${CPP:Q} rpcgen -L -C
+
+h_testbits.h: ${RPCSRC}
+ ${RPCGEN} -h -o ${.TARGET} ${.ALLSRC}
+
+h_testbits_xdr.c: ${RPCSRC} h_testbits.h
+ ${RPCGEN} ${.ALLSRC:M*.x}
+
+CLEANFILES+= ${RPCSRC:.x=.h} ${RPCSRC:.x=.c} h_testbits_xdr.c
+CFLAGS+= -I${.OBJDIR}
+DPSRCS+= h_testbits.h
+
+LDADD+= -lrpcsvc -lutil
+DPADD+= ${LIBRPCSVC} ${LIBUTIL}
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/setjmp/Makefile b/lib/libc/tests/setjmp/Makefile
new file mode 100644
index 0000000..e4c7ae5
--- /dev/null
+++ b/lib/libc/tests/setjmp/Makefile
@@ -0,0 +1,13 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/setjmp
+
+NETBSD_ATF_TESTS_C= t_setjmp
+NETBSD_ATF_TESTS_C+= t_threadjmp
+
+DPADD.t_threadjmp+= ${LIBPTHREAD}
+LDADD.t_threadjmp+= -lpthread
+
+WARNS?= 4
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/ssp/Makefile b/lib/libc/tests/ssp/Makefile
new file mode 100644
index 0000000..cf767ce
--- /dev/null
+++ b/lib/libc/tests/ssp/Makefile
@@ -0,0 +1,45 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/ssp
+
+NO_WERROR=
+WARNS?= 2
+
+CFLAGS.h_raw+= -fstack-protector-all -Wstack-protector
+.if ${COMPILER_TYPE} == "clang"
+CFLAGS.h_raw+= -fsanitize=bounds
+.elif ${COMPILER_TYPE} == "gcc"
+CFLAGS.h_raw+= --param ssp-buffer-size=1
+DPADD+= ${LIBSSP}
+LDADD+= -lssp
+.endif
+
+NETBSD_ATF_TESTS_SH= ssp_test
+
+BINDIR= ${TESTSDIR}
+
+PROGS= h_fgets
+PROGS+= h_gets
+PROGS+= h_getcwd
+PROGS+= h_memcpy
+PROGS+= h_memmove
+PROGS+= h_memset
+PROGS+= h_raw
+PROGS+= h_read
+PROGS+= h_readlink
+PROGS+= h_snprintf
+PROGS+= h_sprintf
+PROGS+= h_stpcpy
+PROGS+= h_stpncpy
+PROGS+= h_strcat
+PROGS+= h_strcpy
+PROGS+= h_strncat
+PROGS+= h_strncpy
+PROGS+= h_vsnprintf
+PROGS+= h_vsprintf
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/stdio/Makefile b/lib/libc/tests/stdio/Makefile
new file mode 100644
index 0000000..23d5c1e
--- /dev/null
+++ b/lib/libc/tests/stdio/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libc/stdio
+
+ATF_TESTS_C= fmemopen2_test
+
+NETBSD_ATF_TESTS_C= clearerr_test
+NETBSD_ATF_TESTS_C+= fflush_test
+NETBSD_ATF_TESTS_C+= fmemopen_test
+NETBSD_ATF_TESTS_C+= fopen_test
+NETBSD_ATF_TESTS_C+= fputc_test
+NETBSD_ATF_TESTS_C+= mktemp_test
+NETBSD_ATF_TESTS_C+= popen_test
+NETBSD_ATF_TESTS_C+= printf_test
+NETBSD_ATF_TESTS_C+= scanf_test
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/stdio/fmemopen2_test.c b/lib/libc/tests/stdio/fmemopen2_test.c
new file mode 100644
index 0000000..d137780
--- /dev/null
+++ b/lib/libc/tests/stdio/fmemopen2_test.c
@@ -0,0 +1,300 @@
+/*-
+Copyright (C) 2013 Pietro Cerutti <gahr@FreeBSD.org>
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+*/
+
+/*
+ * Test basic FILE * functions (fread, fwrite, fseek, fclose) against
+ * a FILE * retrieved using fmemopen()
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <atf-c.h>
+
+ATF_TC_WITHOUT_HEAD(test_preexisting);
+ATF_TC_BODY(test_preexisting, tc)
+{
+ /*
+ * Use a pre-existing buffer.
+ */
+
+ char buf[512];
+ char buf2[512];
+ char str[] = "Test writing some stuff";
+ char str2[] = "AAAAAAAAA";
+ char str3[] = "AAAA writing some stuff";
+ FILE *fp;
+ size_t nofw, nofr;
+ int rc;
+
+ /* Open a FILE * using fmemopen. */
+ fp = fmemopen(buf, sizeof(buf), "w");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write to the buffer. */
+ nofw = fwrite(str, 1, sizeof(str), fp);
+ ATF_REQUIRE(nofw == sizeof(str));
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Re-open the FILE * to read back the data. */
+ fp = fmemopen(buf, sizeof(buf), "r");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Read from the buffer. */
+ bzero(buf2, sizeof(buf2));
+ nofr = fread(buf2, 1, sizeof(buf2), fp);
+ ATF_REQUIRE(nofr == sizeof(buf2));
+
+ /*
+ * Since a write on a FILE * retrieved by fmemopen
+ * will add a '\0' (if there's space), we can check
+ * the strings for equality.
+ */
+ ATF_REQUIRE(strcmp(str, buf2) == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Now open a FILE * on the first 4 bytes of the string. */
+ fp = fmemopen(str, 4, "w");
+ ATF_REQUIRE(fp != NULL);
+
+ /*
+ * Try to write more bytes than we shoud, we'll get a short count (4).
+ */
+ nofw = fwrite(str2, 1, sizeof(str2), fp);
+ ATF_REQUIRE(nofw == 4);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+
+ /* Check that the string was not modified after the first 4 bytes. */
+ ATF_REQUIRE(strcmp(str, str3) == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_autoalloc);
+ATF_TC_BODY(test_autoalloc, tc)
+{
+ /*
+ * Let fmemopen allocate the buffer.
+ */
+
+ char str[] = "A quick test";
+ FILE *fp;
+ long pos;
+ size_t nofw, nofr, i;
+ int rc;
+
+ /* Open a FILE * using fmemopen. */
+ fp = fmemopen(NULL, 512, "w+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* fill the buffer */
+ for (i = 0; i < 512; i++) {
+ nofw = fwrite("a", 1, 1, fp);
+ ATF_REQUIRE(nofw == 1);
+ }
+
+ /* Get the current position into the stream. */
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == 512);
+
+ /*
+ * Try to write past the end, we should get a short object count (0)
+ */
+ nofw = fwrite("a", 1, 1, fp);
+ ATF_REQUIRE(nofw == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Open a FILE * using a wrong mode */
+ fp = fmemopen(NULL, 512, "r");
+ ATF_REQUIRE(fp == NULL);
+
+ fp = fmemopen(NULL, 512, "w");
+ ATF_REQUIRE(fp == NULL);
+}
+
+ATF_TC_WITHOUT_HEAD(test_data_length);
+ATF_TC_BODY(test_data_length, tc)
+{
+ /*
+ * Here we test that a read operation doesn't go past the end of the
+ * data actually written, and that a SEEK_END seeks from the end of the
+ * data, not of the whole buffer.
+ */
+ FILE *fp;
+ char buf[512] = {'\0'};
+ char str[] = "Test data length. ";
+ char str2[] = "Do we have two sentences?";
+ char str3[sizeof(str) + sizeof(str2) -1];
+ long pos;
+ size_t nofw, nofr;
+ int rc;
+
+ /* Open a FILE * for updating our buffer. */
+ fp = fmemopen(buf, sizeof(buf), "w+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write our string into the buffer. */
+ nofw = fwrite(str, 1, sizeof(str), fp);
+ ATF_REQUIRE(nofw == sizeof(str));
+
+ /*
+ * Now seek to the end and check that ftell
+ * gives us sizeof(str).
+ */
+ rc = fseek(fp, 0, SEEK_END);
+ ATF_REQUIRE(rc == 0);
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == sizeof(str));
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+
+ /* Reopen the buffer for appending. */
+ fp = fmemopen(buf, sizeof(buf), "a+");
+ ATF_REQUIRE(fp != NULL);
+
+ /* We should now be writing after the first string. */
+ nofw = fwrite(str2, 1, sizeof(str2), fp);
+ ATF_REQUIRE(nofw == sizeof(str2));
+
+ /* Rewind the FILE *. */
+ rc = fseek(fp, 0, SEEK_SET);
+ ATF_REQUIRE(rc == 0);
+
+ /* Make sure we're at the beginning. */
+ pos = ftell(fp);
+ ATF_REQUIRE(pos == 0);
+
+ /* Read the whole buffer. */
+ nofr = fread(str3, 1, sizeof(buf), fp);
+ ATF_REQUIRE(nofr == sizeof(str3));
+
+ /* Make sure the two strings are there. */
+ ATF_REQUIRE(strncmp(str3, str, sizeof(str) - 1) == 0);
+ ATF_REQUIRE(strncmp(str3 + sizeof(str) - 1, str2, sizeof(str2)) == 0);
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_binary);
+ATF_TC_BODY(test_binary, tc)
+{
+ /*
+ * Make sure that NULL bytes are never appended when opening a buffer
+ * in binary mode.
+ */
+
+ FILE *fp;
+ char buf[20];
+ char str[] = "Test";
+ size_t nofw;
+ int rc, i;
+
+ /* Pre-fill the buffer. */
+ memset(buf, 'A', sizeof(buf));
+
+ /* Open a FILE * in binary mode. */
+ fp = fmemopen(buf, sizeof(buf), "w+b");
+ ATF_REQUIRE(fp != NULL);
+
+ /* Write some data into it. */
+ nofw = fwrite(str, 1, strlen(str), fp);
+ ATF_REQUIRE(nofw == strlen(str));
+
+ /* Make sure that the buffer doesn't contain any NULL bytes. */
+ for (i = 0; i < sizeof(buf); i++)
+ ATF_REQUIRE(buf[i] != '\0');
+
+ /* Close the FILE *. */
+ rc = fclose(fp);
+ ATF_REQUIRE(rc == 0);
+}
+
+ATF_TC_WITHOUT_HEAD(test_append_binary_pos);
+ATF_TC_BODY(test_append_binary_pos, tc)
+{
+ /*
+ * For compatibility with other implementations (glibc), we set the
+ * position to 0 when opening an automatically allocated binary stream
+ * for appending.
+ */
+
+ FILE *fp;
+
+ fp = fmemopen(NULL, 16, "ab+");
+ ATF_REQUIRE(ftell(fp) == 0L);
+ fclose(fp);
+
+ /*
+ * Make sure that a pre-allocated buffer behaves correctly.
+ */
+ char buf[] = "Hello";
+ fp = fmemopen(buf, sizeof(buf), "ab+");
+ ATF_REQUIRE(ftell(fp) == strlen(buf));
+ fclose(fp);
+}
+
+ATF_TC_WITHOUT_HEAD(test_size_0);
+ATF_TC_BODY(test_size_0, tc)
+{
+ /*
+ * POSIX mandates that we return EINVAL if size is 0.
+ */
+
+ FILE *fp;
+
+ fp = fmemopen(NULL, 0, "r+");
+ ATF_REQUIRE(fp == NULL);
+ ATF_REQUIRE(errno == EINVAL);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, test_autoalloc);
+ ATF_TP_ADD_TC(tp, test_preexisting);
+ ATF_TP_ADD_TC(tp, test_data_length);
+ ATF_TP_ADD_TC(tp, test_binary);
+ ATF_TP_ADD_TC(tp, test_append_binary_pos);
+ ATF_TP_ADD_TC(tp, test_size_0);
+
+ return (atf_no_error());
+}
diff --git a/lib/libc/tests/stdlib/Makefile b/lib/libc/tests/stdlib/Makefile
new file mode 100644
index 0000000..9171601
--- /dev/null
+++ b/lib/libc/tests/stdlib/Makefile
@@ -0,0 +1,44 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/stdlib
+
+# TODO: t_getenv_thread, t_mi_vector_hash
+NETBSD_ATF_TESTS_C= abs_test
+NETBSD_ATF_TESTS_C+= atoi_test
+NETBSD_ATF_TESTS_C+= div_test
+NETBSD_ATF_TESTS_C+= getenv_test
+NETBSD_ATF_TESTS_C+= exit_test
+NETBSD_ATF_TESTS_C+= hsearch_test
+NETBSD_ATF_TESTS_C+= posix_memalign_test
+NETBSD_ATF_TESTS_C+= random_test
+NETBSD_ATF_TESTS_C+= strtod_test
+NETBSD_ATF_TESTS_C+= strtol_test
+NETBSD_ATF_TESTS_C+= system_test
+
+# TODO: need to come up with a correct explanation of what the patch pho does
+# with h_atexit
+#ATF_TESTS_SH= atexit_test
+NETBSD_ATF_TESTS_SH= getopt_test
+
+.include "../Makefile.netbsd-tests"
+
+BINDIR= ${TESTSDIR}
+
+# TODO: see comment above
+#PROGS+= h_atexit
+PROGS+= h_getopt h_getopt_long
+
+.for t in h_getopt h_getopt_long
+CFLAGS.$t+= -I${LIBNETBSD_SRCDIR} -I${SRCTOP}/contrib/netbsd-tests
+LDFLAGS.$t+= -L${LIBNETBSD_OBJDIR}
+
+DPADD.$t+= ${LIBNETBSD} ${LIBUTIL}
+LDADD.$t+= -lnetbsd -lutil
+.endfor
+
+DPADD.strtod_test+= ${LIBM}
+LDADD.strtod_test+= -lm
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/string/Makefile b/lib/libc/tests/string/Makefile
new file mode 100644
index 0000000..3c30ab6
--- /dev/null
+++ b/lib/libc/tests/string/Makefile
@@ -0,0 +1,33 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/string
+
+# TODO: popcount, stresep
+
+NETBSD_ATF_TESTS_C+= memchr
+NETBSD_ATF_TESTS_C+= memcpy
+NETBSD_ATF_TESTS_C+= memmem
+NETBSD_ATF_TESTS_C+= memset
+NETBSD_ATF_TESTS_C+= strcat
+NETBSD_ATF_TESTS_C+= strchr
+NETBSD_ATF_TESTS_C+= strcmp
+NETBSD_ATF_TESTS_C+= strcpy
+NETBSD_ATF_TESTS_C+= strcspn
+NETBSD_ATF_TESTS_C+= strerror
+NETBSD_ATF_TESTS_C+= strlen
+NETBSD_ATF_TESTS_C+= strpbrk
+NETBSD_ATF_TESTS_C+= strrchr
+NETBSD_ATF_TESTS_C+= strspn
+NETBSD_ATF_TESTS_C+= swab
+
+.include "../Makefile.netbsd-tests"
+
+LDADD.memchr+= -lmd
+DPADD.memchr+= ${LIBMD}
+
+LDADD.memcpy+= -lmd
+DPADD.memcpy+= ${LIBMD}
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/sys/Makefile b/lib/libc/tests/sys/Makefile
new file mode 100644
index 0000000..89431bc
--- /dev/null
+++ b/lib/libc/tests/sys/Makefile
@@ -0,0 +1,85 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/sys
+
+# TODO: clone, lwp_create, lwp_ctl, posix_fadvise, recvmmsg,
+# swapcontext
+NETBSD_ATF_TESTS_C+= access_test
+NETBSD_ATF_TESTS_C+= chroot_test
+NETBSD_ATF_TESTS_C+= clock_gettime_test
+NETBSD_ATF_TESTS_C+= connect_test
+NETBSD_ATF_TESTS_C+= dup_test
+NETBSD_ATF_TESTS_C+= fsync_test
+NETBSD_ATF_TESTS_C+= getcontext_test
+NETBSD_ATF_TESTS_C+= getgroups_test
+NETBSD_ATF_TESTS_C+= getitimer_test
+NETBSD_ATF_TESTS_C+= getlogin_test
+NETBSD_ATF_TESTS_C+= getpid_test
+NETBSD_ATF_TESTS_C+= getrusage_test
+NETBSD_ATF_TESTS_C+= getsid_test
+NETBSD_ATF_TESTS_C+= gettimeofday_test
+NETBSD_ATF_TESTS_C+= issetugid_test
+NETBSD_ATF_TESTS_C+= kevent_test
+NETBSD_ATF_TESTS_C+= kill_test
+NETBSD_ATF_TESTS_C+= link_test
+NETBSD_ATF_TESTS_C+= listen_test
+NETBSD_ATF_TESTS_C+= mincore_test
+NETBSD_ATF_TESTS_C+= mkdir_test
+NETBSD_ATF_TESTS_C+= mkfifo_test
+NETBSD_ATF_TESTS_C+= mknod_test
+NETBSD_ATF_TESTS_C+= mlock_test
+NETBSD_ATF_TESTS_C+= mmap_test
+NETBSD_ATF_TESTS_C+= mprotect_test
+NETBSD_ATF_TESTS_C+= msgctl_test
+NETBSD_ATF_TESTS_C+= msgget_test
+NETBSD_ATF_TESTS_C+= msgrcv_test
+NETBSD_ATF_TESTS_C+= msgsnd_test
+NETBSD_ATF_TESTS_C+= msync_test
+NETBSD_ATF_TESTS_C+= nanosleep_test
+NETBSD_ATF_TESTS_C+= pipe_test
+NETBSD_ATF_TESTS_C+= pipe2_test
+NETBSD_ATF_TESTS_C+= poll_test
+NETBSD_ATF_TESTS_C+= revoke_test
+NETBSD_ATF_TESTS_C+= select_test
+NETBSD_ATF_TESTS_C+= setrlimit_test
+NETBSD_ATF_TESTS_C+= setuid_test
+NETBSD_ATF_TESTS_C+= sigaction_test
+NETBSD_ATF_TESTS_C+= sigqueue_test
+NETBSD_ATF_TESTS_C+= sigtimedwait_test
+NETBSD_ATF_TESTS_C+= socketpair_test
+NETBSD_ATF_TESTS_C+= stat_test
+NETBSD_ATF_TESTS_C+= timer_create_test
+NETBSD_ATF_TESTS_C+= truncate_test
+NETBSD_ATF_TESTS_C+= ucontext_test
+NETBSD_ATF_TESTS_C+= umask_test
+NETBSD_ATF_TESTS_C+= unlink_test
+NETBSD_ATF_TESTS_C+= write_test
+
+DPADD.getpid_test+= ${LIBPTHREAD}
+LDADD.getpid_test+= -lpthread
+DPADD.timer_create_test+= ${LIBRT}
+LDADD.timer_create_test+= -lrt
+
+.include "../Makefile.netbsd-tests"
+
+.if ${COMPILER_TYPE} == "gcc"
+WARNS?= 3
+.else
+WARNS?= 4
+.endif
+
+FILESGROUPS= FILES truncate_test_FILES
+
+truncate_test_FILES= truncate_test.root_owned
+truncate_test_FILESDIR= ${TESTSDIR}
+truncate_test_FILESMODE= 0600
+truncate_test_FILESOWNER= root
+truncate_test_FILESGRP= wheel
+
+CLEANFILES= truncate_test.root_owned
+truncate_test.root_owned:
+ dd if=/dev/null bs=1 count=1 of=${.TARGET}
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/termios/Makefile b/lib/libc/tests/termios/Makefile
new file mode 100644
index 0000000..9a3fd66
--- /dev/null
+++ b/lib/libc/tests/termios/Makefile
@@ -0,0 +1,11 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/termios
+
+NETBSD_ATF_TESTS_C= tcsetpgrp_test
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/time/Makefile b/lib/libc/tests/time/Makefile
new file mode 100644
index 0000000..c2a55df
--- /dev/null
+++ b/lib/libc/tests/time/Makefile
@@ -0,0 +1,12 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/time
+
+NETBSD_ATF_TESTS_C= mktime_test
+NETBSD_ATF_TESTS_C+= strptime_test
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/tls/Makefile b/lib/libc/tests/tls/Makefile
new file mode 100644
index 0000000..e224895
--- /dev/null
+++ b/lib/libc/tests/tls/Makefile
@@ -0,0 +1,35 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/tls
+.if !defined(NO_PIC)
+SUBDIR+= dso
+.endif
+
+# TODO: doesn't link properly (for some odd reason it's trying to link in
+# libatf.so)
+#NETBSD_ATF_TESTS_C= tls_static_test
+.if !defined(NO_PIC)
+NETBSD_ATF_TESTS_C+= tls_dlopen_test
+NETBSD_ATF_TESTS_C+= tls_dynamic_test
+.endif
+
+.include "../Makefile.netbsd-tests"
+
+DSODIR= ${.OBJDIR}/../tls_dso
+
+DPADD.tls_static_test+= ${LIBPTHREAD}
+LDADD.tls_static_test+= -lpthread
+LDFLAGS.tls_static_test+= -static
+SRCS.tls_static_test= t_tls_static.c t_tls_static_helper.c
+
+DPADD.tls_dynamic_test+= ${LIBPTHREAD} ${DSODIR}/libh_tls_dynamic.so
+LDADD.tls_dynamic_test+= -lpthread -lh_tls_dynamic
+LDFLAGS.tls_dynamic_test+= -Wl,-rpath,${TESTSDIR} -L${DSODIR}
+
+DPADD.tls_dlopen_test+= ${LIBPTHREAD}
+LDADD.tls_dlopen_test+= -lpthread
+LDFLAGS.tls_dlopen_test+= -Wl,-rpath,${TESTSDIR} -Wl,-export-dynamic
+
+.include <bsd.test.mk>
diff --git a/lib/libc/tests/tls/dso/Makefile b/lib/libc/tests/tls/dso/Makefile
new file mode 100644
index 0000000..466f950
--- /dev/null
+++ b/lib/libc/tests/tls/dso/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libc/tls/${.CURDIR:T}
+
+LIB= h_tls_dlopen
+SHLIB_NAME= h_tls_dlopen.so
+SRCS= h_tls_dlopen.c
+
+MAN=
+
+LIBDIR= ${TESTSBASE}/lib/libc/tls
+SHLIB_MAJOR= 1
+
+.include "../../Makefile.netbsd-tests"
+
+.include <bsd.lib.mk>
diff --git a/lib/libc/tests/tls_dso/Makefile b/lib/libc/tests/tls_dso/Makefile
new file mode 100644
index 0000000..5449799
--- /dev/null
+++ b/lib/libc/tests/tls_dso/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+LIB= h_tls_dynamic
+SRCS= h_tls_dynamic.c
+
+LIBDIR= ${TESTSBASE}/lib/libc/tls
+SHLIBDIR= ${TESTSBASE}/lib/libc/tls
+SHLIB_MAJOR= 1
+
+WITHOUT_STATIC=
+WITHOUT_PROFILE=
+WITHOUT_PIC=
+
+MAN=
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.lib.mk>
diff --git a/lib/libc/tests/ttyio/Makefile b/lib/libc/tests/ttyio/Makefile
new file mode 100644
index 0000000..a1f320d
--- /dev/null
+++ b/lib/libc/tests/ttyio/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libc/ttyio
+
+# TODO: ptm_test
+NETBSD_ATF_TESTS_C= ttyio_test
+
+DPADD.ttyio_test+= ${LIBUTIL}
+LDADD.ttyio_test+= -lutil
+
+.include "../Makefile.netbsd-tests"
+
+.include <bsd.test.mk>
diff --git a/lib/libcompiler_rt/Makefile b/lib/libcompiler_rt/Makefile
index 91ce965..c31eced 100644
--- a/lib/libcompiler_rt/Makefile
+++ b/lib/libcompiler_rt/Makefile
@@ -144,8 +144,7 @@ SRCF+= adddf3 \
truncdfsf2
.endif
-.if ${MACHINE_CPUARCH} != "mips" && \
- (${MACHINE_CPUARCH} != "arm" || ${MK_ARM_EABI} != "no")
+.if ${MACHINE_CPUARCH} != "mips"
SRCF+= divsi3 \
modsi3 \
udivsi3 \
@@ -165,16 +164,16 @@ SRCF+= stdatomic
.endif
.for file in ${SRCF}
-. if ${MACHINE_ARCH} == "armv6hf" && exists(${CRTSRC}/${CRTARCH}/${file}vfp.S)
+. if ${MACHINE_ARCH:Marm*hf*} != "" && exists(${CRTSRC}/${CRTARCH}/${file}vfp.S)
SRCS+= ${file}vfp.S
-. elif (${MACHINE_CPUARCH} != "arm" || ${MACHINE_ARCH} == "armv6hf") && exists(${CRTSRC}/${CRTARCH}/${file}.S)
+. elif !(${MACHINE_CPUARCH} == "arm" && ${MACHINE_ARCH:Marm*hf*} == "") && exists(${CRTSRC}/${CRTARCH}/${file}.S)
SRCS+= ${file}.S
. else
SRCS+= ${file}.c
. endif
.endfor
-.if ${MACHINE_CPUARCH} == "arm" && ${MK_ARM_EABI} != "no"
+.if ${MACHINE_CPUARCH} == "arm"
SRCS+= aeabi_idivmod.S \
aeabi_ldivmod.S \
aeabi_memcmp.S \
diff --git a/lib/libcrypt/crypt.c b/lib/libcrypt/crypt.c
index c3ca4c2..623809e 100644
--- a/lib/libcrypt/crypt.c
+++ b/lib/libcrypt/crypt.c
@@ -37,24 +37,26 @@ __FBSDID("$FreeBSD$");
#include "crypt.h"
/*
- * List of supported crypt(3) formats. The first element in the list will
- * be the default.
+ * List of supported crypt(3) formats.
+ *
+ * The default algorithm is the last entry in the list (second-to-last
+ * array element since the last is a sentinel). The reason for placing
+ * the default last rather than first is that DES needs to be at the
+ * bottom for the algorithm guessing logic in crypt(3) to work correctly,
+ * and it needs to be the default for backward compatibility.
*/
static const struct crypt_format {
const char *const name;
char *(*const func)(const char *, const char *);
const char *const magic;
} crypt_formats[] = {
- /* default format */
- { "sha512", crypt_sha512, "$6$" },
-
- /* other supported formats */
{ "md5", crypt_md5, "$1$" },
#ifdef HAS_BLOWFISH
{ "blf", crypt_blowfish, "$2" },
#endif
{ "nth", crypt_nthash, "$3$" },
{ "sha256", crypt_sha256, "$5$" },
+ { "sha512", crypt_sha512, "$6$" },
#ifdef HAS_DES
{ "des", crypt_des, "_" },
#endif
@@ -63,7 +65,8 @@ static const struct crypt_format {
{ NULL, NULL, NULL }
};
-static const struct crypt_format *crypt_format = &crypt_formats[0];
+static const struct crypt_format *crypt_format =
+ &crypt_formats[(sizeof crypt_formats / sizeof *crypt_formats) - 2];
#define DES_SALT_ALPHABET \
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
diff --git a/lib/libcrypt/tests/Makefile b/lib/libcrypt/tests/Makefile
index 2a0f1fb..20993e2 100644
--- a/lib/libcrypt/tests/Makefile
+++ b/lib/libcrypt/tests/Makefile
@@ -7,6 +7,7 @@ TESTSDIR= ${TESTSBASE}/lib/libcrypt
ATF_TESTS_C= crypt_tests
CFLAGS+= -I${.CURDIR:H}
-LDADD+= -L${.OBJDIR:H} -lcrypt
+DPADD+= ${LIBCRYPT}
+LDADD+= -lcrypt
.include <bsd.test.mk>
diff --git a/lib/libcuse/Makefile b/lib/libcuse/Makefile
index 6269cbe..2d1ded5 100644
--- a/lib/libcuse/Makefile
+++ b/lib/libcuse/Makefile
@@ -36,6 +36,7 @@ CFLAGS+= -D_GNU_SOURCE
CFLAGS+= -g
CFLAGS+= -DHAVE_DEBUG
.endif
+DPADD+= ${LIBPTHREAD}
LDADD+= ${PTHREAD_LIBS}
MLINKS=
diff --git a/lib/libcuse/cuse_lib.c b/lib/libcuse/cuse_lib.c
index 9d8352f..321522d 100644
--- a/lib/libcuse/cuse_lib.c
+++ b/lib/libcuse/cuse_lib.c
@@ -79,23 +79,19 @@ struct cuse_dev {
void *priv1;
};
-static TAILQ_HEAD(, cuse_dev) h_cuse;
-static TAILQ_HEAD(, cuse_dev_entered) h_cuse_entered;
static int f_cuse = -1;
+
static pthread_mutex_t m_cuse;
-static struct cuse_vm_allocation a_cuse[CUSE_ALLOC_UNIT_MAX];
+static TAILQ_HEAD(, cuse_dev) h_cuse __guarded_by(m_cuse);
+static TAILQ_HEAD(, cuse_dev_entered) h_cuse_entered __guarded_by(m_cuse);
+static struct cuse_vm_allocation a_cuse[CUSE_ALLOC_UNIT_MAX]
+ __guarded_by(m_cuse);
-static void
-cuse_lock(void)
-{
- pthread_mutex_lock(&m_cuse);
-}
+#define CUSE_LOCK() \
+ pthread_mutex_lock(&m_cuse)
-static void
-cuse_unlock(void)
-{
- pthread_mutex_unlock(&m_cuse);
-}
+#define CUSE_UNLOCK() \
+ pthread_mutex_unlock(&m_cuse)
int
cuse_init(void)
@@ -148,7 +144,7 @@ cuse_vmoffset(void *_ptr)
unsigned long remainder;
int n;
- cuse_lock();
+ CUSE_LOCK();
for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
if (a_cuse[n].ptr == NULL)
continue;
@@ -158,7 +154,7 @@ cuse_vmoffset(void *_ptr)
if ((ptr >= ptr_min) && (ptr <= ptr_max)) {
- cuse_unlock();
+ CUSE_UNLOCK();
remainder = (ptr - ptr_min);
@@ -167,7 +163,7 @@ cuse_vmoffset(void *_ptr)
return ((n * PAGE_SIZE * CUSE_ALLOC_PAGES_MAX) + remainder);
}
}
- cuse_unlock();
+ CUSE_UNLOCK();
return (0x80000000UL); /* failure */
}
@@ -190,7 +186,7 @@ cuse_vmalloc(int size)
info.page_count = (size + PAGE_SIZE - 1) / PAGE_SIZE;
- cuse_lock();
+ CUSE_LOCK();
for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
if (a_cuse[n].ptr != NULL)
@@ -199,7 +195,7 @@ cuse_vmalloc(int size)
a_cuse[n].ptr = ((uint8_t *)1); /* reserve */
a_cuse[n].size = 0;
- cuse_unlock();
+ CUSE_UNLOCK();
info.alloc_nr = n;
@@ -207,7 +203,7 @@ cuse_vmalloc(int size)
if (error) {
- cuse_lock();
+ CUSE_LOCK();
a_cuse[n].ptr = NULL;
@@ -228,20 +224,20 @@ cuse_vmalloc(int size)
if (error) {
/* ignore */
}
- cuse_lock();
+ CUSE_LOCK();
a_cuse[n].ptr = NULL;
break;
}
- cuse_lock();
+ CUSE_LOCK();
a_cuse[n].ptr = ptr;
a_cuse[n].size = size;
- cuse_unlock();
+ CUSE_UNLOCK();
return (ptr); /* success */
}
- cuse_unlock();
+ CUSE_UNLOCK();
return (NULL); /* failure */
}
@@ -253,12 +249,12 @@ cuse_is_vmalloc_addr(void *ptr)
if (f_cuse < 0 || ptr == NULL)
return (0); /* false */
- cuse_lock();
+ CUSE_LOCK();
for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
if (a_cuse[n].ptr == ptr)
break;
}
- cuse_unlock();
+ CUSE_UNLOCK();
return (n != CUSE_ALLOC_UNIT_MAX);
}
@@ -266,6 +262,7 @@ cuse_is_vmalloc_addr(void *ptr)
void
cuse_vmfree(void *ptr)
{
+ struct cuse_vm_allocation temp;
struct cuse_alloc_info info;
int error;
int n;
@@ -273,32 +270,35 @@ cuse_vmfree(void *ptr)
if (f_cuse < 0)
return;
- memset(&info, 0, sizeof(info));
-
- cuse_lock();
+ CUSE_LOCK();
for (n = 0; n != CUSE_ALLOC_UNIT_MAX; n++) {
if (a_cuse[n].ptr != ptr)
continue;
- cuse_unlock();
+ temp = a_cuse[n];
- info.alloc_nr = n;
+ CUSE_UNLOCK();
+
+ munmap(temp.ptr, temp.size);
- munmap(ptr, a_cuse[n].size);
+ memset(&info, 0, sizeof(info));
+
+ info.alloc_nr = n;
error = ioctl(f_cuse, CUSE_IOCTL_FREE_MEMORY, &info);
- if (error) {
- /* ignore */
+ if (error != 0) {
+ /* ignore any errors */
+ DPRINTF("Freeing memory failed: %d\n", errno);
}
- cuse_lock();
+ CUSE_LOCK();
a_cuse[n].ptr = NULL;
a_cuse[n].size = 0;
break;
}
- cuse_unlock();
+ CUSE_UNLOCK();
}
int
@@ -405,9 +405,9 @@ cuse_dev_create(const struct cuse_methods *mtod, void *priv0, void *priv1,
free(cdev);
return (NULL);
}
- cuse_lock();
+ CUSE_LOCK();
TAILQ_INSERT_TAIL(&h_cuse, cdev, entry);
- cuse_unlock();
+ CUSE_UNLOCK();
return (cdev);
}
@@ -421,9 +421,9 @@ cuse_dev_destroy(struct cuse_dev *cdev)
if (f_cuse < 0)
return;
- cuse_lock();
+ CUSE_LOCK();
TAILQ_REMOVE(&h_cuse, cdev, entry);
- cuse_unlock();
+ CUSE_UNLOCK();
error = ioctl(f_cuse, CUSE_IOCTL_DESTROY_DEV, &cdev);
if (error)
@@ -475,7 +475,7 @@ cuse_wait_and_process(void)
cdev = info.dev;
- cuse_lock();
+ CUSE_LOCK();
enter.thread = curr;
enter.per_file_handle = (void *)info.per_file_handle;
enter.cmd = info.command;
@@ -483,7 +483,7 @@ cuse_wait_and_process(void)
enter.got_signal = 0;
enter.cdev = cdev;
TAILQ_INSERT_TAIL(&h_cuse_entered, &enter, entry);
- cuse_unlock();
+ CUSE_UNLOCK();
DPRINTF("cuse: Command = %d = %s, flags = %d, arg = 0x%08x, ptr = 0x%08x\n",
(int)info.command, cuse_cmd_str(info.command), (int)info.fflags,
@@ -505,7 +505,7 @@ cuse_wait_and_process(void)
error = 0;
- cuse_lock();
+ CUSE_LOCK();
TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
if (pe->cdev != cdev)
continue;
@@ -518,7 +518,7 @@ cuse_wait_and_process(void)
pthread_kill(pe->thread, SIGHUP);
error = CUSE_ERR_BUSY;
}
- cuse_unlock();
+ CUSE_UNLOCK();
if (error == 0)
break;
@@ -569,7 +569,7 @@ cuse_wait_and_process(void)
break;
case CUSE_CMD_SIGNAL:
- cuse_lock();
+ CUSE_LOCK();
TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
if (pe->cdev != cdev)
continue;
@@ -581,7 +581,7 @@ cuse_wait_and_process(void)
pe->got_signal = 1;
pthread_kill(pe->thread, SIGHUP);
}
- cuse_unlock();
+ CUSE_UNLOCK();
break;
default:
@@ -592,9 +592,9 @@ cuse_wait_and_process(void)
DPRINTF("cuse: Command error = %d for %s\n",
error, cuse_cmd_str(info.command));
- cuse_lock();
+ CUSE_LOCK();
TAILQ_REMOVE(&h_cuse_entered, &enter, entry);
- cuse_unlock();
+ CUSE_UNLOCK();
/* we ignore any sync command failures */
ioctl(f_cuse, CUSE_IOCTL_SYNC_COMMAND, &error);
@@ -608,12 +608,12 @@ cuse_dev_get_entered(void)
struct cuse_dev_entered *pe;
pthread_t curr = pthread_self();
- cuse_lock();
+ CUSE_LOCK();
TAILQ_FOREACH(pe, &h_cuse_entered, entry) {
if (pe->thread == curr)
break;
}
- cuse_unlock();
+ CUSE_UNLOCK();
return (pe);
}
diff --git a/lib/libcxxrt/Version.map b/lib/libcxxrt/Version.map
index a97c66f..b9e4cf9 100644
--- a/lib/libcxxrt/Version.map
+++ b/lib/libcxxrt/Version.map
@@ -26,6 +26,7 @@ CXXABI_1.3 {
__cxa_pure_virtual;
__cxa_rethrow;
__cxa_throw;
+ __cxa_throw_bad_array_new_length;
__cxa_type_match;
__cxa_vec_cctor;
__cxa_vec_cleanup;
@@ -273,6 +274,9 @@ CXXRT_1.0 {
"std::bad_alloc::bad_alloc(std::bad_alloc const&)";
"std::bad_alloc::bad_alloc()";
"std::bad_alloc::operator=(std::bad_alloc const&)";
+ "std::bad_array_new_length::bad_array_new_length(std::bad_array_new_length const&)";
+ "std::bad_array_new_length::bad_array_new_length()";
+ "std::bad_array_new_length::operator=(std::bad_array_new_length const&)";
};
__cxa_allocate_dependent_exception;
@@ -307,6 +311,7 @@ GLIBCXX_3.4 {
"std::bad_typeid::~bad_typeid()";
"std::exception::~exception()";
"std::bad_alloc::~bad_alloc()";
+ "std::bad_array_new_length::~bad_array_new_length()";
"std::exception::what() const";
@@ -320,17 +325,20 @@ GLIBCXX_3.4 {
"vtable for std::bad_typeid";
"vtable for std::exception";
"vtable for std::type_info";
+ "vtable for std::bad_array_new_length";
"typeinfo for std::bad_alloc";
"typeinfo for std::bad_typeid";
"typeinfo for std::bad_cast";
"typeinfo for std::exception";
"typeinfo for std::type_info";
+ "typeinfo for std::bad_array_new_length";
"typeinfo name for std::bad_alloc";
"typeinfo name for std::bad_typeid";
"typeinfo name for std::bad_cast";
"typeinfo name for std::exception";
"typeinfo name for std::type_info";
+ "typeinfo name for std::bad_array_new_length";
};
};
@@ -340,6 +348,7 @@ GLIBCXX_3.4.9 {
"std::bad_typeid::what() const";
"std::bad_cast::what() const";
"std::bad_alloc::what() const";
+ "std::bad_array_new_length::what() const";
};
} GLIBCXX_3.4;
diff --git a/lib/libdpv/Makefile b/lib/libdpv/Makefile
new file mode 100644
index 0000000..8096cc9
--- /dev/null
+++ b/lib/libdpv/Makefile
@@ -0,0 +1,18 @@
+# $FreeBSD$
+
+LIB= dpv
+SHLIB_MAJOR= 1
+INCS= dpv.h
+MAN= dpv.3
+MLINKS= dpv.3 dpv_free.3
+
+DPADD= ${LIBDIALOG} ${LIBFIGPAR} ${LIBNCURSESW} ${LIBUTIL}
+LDADD= -ldialog -lfigpar -lncursesw -lutil
+
+SRCS= dialog_util.c dialogrc.c dprompt.c dpv.c status.c util.c
+
+CFLAGS+= -I${.CURDIR}
+
+WARNS?= 6
+
+.include <bsd.lib.mk>
diff --git a/lib/libdpv/dialog_util.c b/lib/libdpv/dialog_util.c
new file mode 100644
index 0000000..d047a25
--- /dev/null
+++ b/lib/libdpv/dialog_util.c
@@ -0,0 +1,633 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/ioctl.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "dialog_util.h"
+#include "dpv.h"
+#include "dpv_private.h"
+
+extern char **environ;
+
+#define TTY_DEFAULT_ROWS 24
+#define TTY_DEFAULT_COLS 80
+
+/* [X]dialog(1) characteristics */
+uint8_t dialog_test = 0;
+uint8_t use_dialog = 0;
+uint8_t use_libdialog = 1;
+uint8_t use_xdialog = 0;
+uint8_t use_color = 1;
+char dialog[PATH_MAX] = DIALOG;
+
+/* [X]dialog(1) functionality */
+char *title = NULL;
+char *backtitle = NULL;
+int dheight = 0;
+int dwidth = 0;
+static char *dargv[64] = { NULL };
+
+/* TTY/Screen characteristics */
+static struct winsize *maxsize = NULL;
+
+/* Function prototypes */
+static void tty_maxsize_update(void);
+static void x11_maxsize_update(void);
+
+/*
+ * Update row/column fields of `maxsize' global (used by dialog_maxrows() and
+ * dialog_maxcols()). If the `maxsize' pointer is NULL, it will be initialized.
+ * The `ws_row' and `ws_col' fields of `maxsize' are updated to hold current
+ * maximum height and width (respectively) for a dialog(1) widget based on the
+ * active TTY size.
+ *
+ * This function is called automatically by dialog_maxrows/cols() to reflect
+ * changes in terminal size in-between calls.
+ */
+static void
+tty_maxsize_update(void)
+{
+ int fd = STDIN_FILENO;
+ struct termios t;
+
+ if (maxsize == NULL) {
+ if ((maxsize = malloc(sizeof(struct winsize))) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ memset((void *)maxsize, '\0', sizeof(struct winsize));
+ }
+
+ if (!isatty(fd))
+ fd = open("/dev/tty", O_RDONLY);
+ if ((tcgetattr(fd, &t) < 0) || (ioctl(fd, TIOCGWINSZ, maxsize) < 0)) {
+ maxsize->ws_row = TTY_DEFAULT_ROWS;
+ maxsize->ws_col = TTY_DEFAULT_COLS;
+ }
+}
+
+/*
+ * Update row/column fields of `maxsize' global (used by dialog_maxrows() and
+ * dialog_maxcols()). If the `maxsize' pointer is NULL, it will be initialized.
+ * The `ws_row' and `ws_col' fields of `maxsize' are updated to hold current
+ * maximum height and width (respectively) for an Xdialog(1) widget based on
+ * the active video resolution of the X11 environment.
+ *
+ * This function is called automatically by dialog_maxrows/cols() to initialize
+ * `maxsize'. Since video resolution changes are less common and more obtrusive
+ * than changes to terminal size, the dialog_maxrows/cols() functions only call
+ * this function when `maxsize' is set to NULL.
+ */
+static void
+x11_maxsize_update(void)
+{
+ FILE *f = NULL;
+ char *cols;
+ char *cp;
+ char *rows;
+ char cmdbuf[LINE_MAX];
+ char rbuf[LINE_MAX];
+
+ if (maxsize == NULL) {
+ if ((maxsize = malloc(sizeof(struct winsize))) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ memset((void *)maxsize, '\0', sizeof(struct winsize));
+ }
+
+ /* Assemble the command necessary to get X11 sizes */
+ snprintf(cmdbuf, LINE_MAX, "%s --print-maxsize 2>&1", dialog);
+
+ fflush(STDIN_FILENO); /* prevent popen(3) from seeking on stdin */
+
+ if ((f = popen(cmdbuf, "r")) == NULL) {
+ if (debug)
+ warnx("WARNING! Command `%s' failed", cmdbuf);
+ return;
+ }
+
+ /* Read in the line returned from Xdialog(1) */
+ if ((fgets(rbuf, LINE_MAX, f) == NULL) || (pclose(f) < 0))
+ return;
+
+ /* Check for X11-related errors */
+ if (strncmp(rbuf, "Xdialog: Error", 14) == 0)
+ return;
+
+ /* Parse expected output: MaxSize: YY, XXX */
+ if ((rows = strchr(rbuf, ' ')) == NULL)
+ return;
+ if ((cols = strchr(rows, ',')) != NULL) {
+ /* strtonum(3) doesn't like trailing junk */
+ *(cols++) = '\0';
+ if ((cp = strchr(cols, '\n')) != NULL)
+ *cp = '\0';
+ }
+
+ /* Convert to unsigned short */
+ maxsize->ws_row = (unsigned short)strtonum(
+ rows, 0, USHRT_MAX, (const char **)NULL);
+ maxsize->ws_col = (unsigned short)strtonum(
+ cols, 0, USHRT_MAX, (const char **)NULL);
+}
+
+/*
+ * Return the current maximum height (rows) for an [X]dialog(1) widget.
+ */
+int
+dialog_maxrows(void)
+{
+
+ if (use_xdialog && maxsize == NULL)
+ x11_maxsize_update(); /* initialize maxsize for GUI */
+ else if (!use_xdialog)
+ tty_maxsize_update(); /* update maxsize for TTY */
+ return (maxsize->ws_row);
+}
+
+/*
+ * Return the current maximum width (cols) for an [X]dialog(1) widget.
+ */
+int
+dialog_maxcols(void)
+{
+
+ if (use_xdialog && maxsize == NULL)
+ x11_maxsize_update(); /* initialize maxsize for GUI */
+ else if (!use_xdialog)
+ tty_maxsize_update(); /* update maxsize for TTY */
+
+ if (use_dialog || use_libdialog) {
+ if (use_shadow)
+ return (maxsize->ws_col - 2);
+ else
+ return (maxsize->ws_col);
+ } else
+ return (maxsize->ws_col);
+}
+
+/*
+ * Return the current maximum width (cols) for the terminal.
+ */
+int
+tty_maxcols(void)
+{
+
+ if (use_xdialog && maxsize == NULL)
+ x11_maxsize_update(); /* initialize maxsize for GUI */
+ else if (!use_xdialog)
+ tty_maxsize_update(); /* update maxsize for TTY */
+
+ return (maxsize->ws_col);
+}
+
+/*
+ * Spawn an [X]dialog(1) `--gauge' box with a `--prompt' value of init_prompt.
+ * Writes the resulting process ID to the pid_t pointed at by `pid'. Returns a
+ * file descriptor (int) suitable for writing data to the [X]dialog(1) instance
+ * (data written to the file descriptor is seen as standard-in by the spawned
+ * [X]dialog(1) process).
+ */
+int
+dialog_spawn_gauge(char *init_prompt, pid_t *pid)
+{
+ char dummy_init[2] = "";
+ char *cp;
+ int height;
+ int width;
+ int error;
+ posix_spawn_file_actions_t action;
+#if DIALOG_SPAWN_DEBUG
+ unsigned int i;
+#endif
+ unsigned int n = 0;
+ int stdin_pipe[2] = { -1, -1 };
+
+ /* Override `dialog' with a path from ENV_DIALOG if provided */
+ if ((cp = getenv(ENV_DIALOG)) != NULL)
+ snprintf(dialog, PATH_MAX, "%s", cp);
+
+ /* For Xdialog(1), set ENV_XDIALOG_HIGH_DIALOG_COMPAT */
+ setenv(ENV_XDIALOG_HIGH_DIALOG_COMPAT, "1", 1);
+
+ /* Constrain the height/width */
+ height = dialog_maxrows();
+ if (backtitle != NULL)
+ height -= use_shadow ? 5 : 4;
+ if (dheight < height)
+ height = dheight;
+ width = dialog_maxcols();
+ if (dwidth < width)
+ width = dwidth;
+
+ /* Populate argument array */
+ dargv[n++] = dialog;
+ if (title != NULL) {
+ if ((dargv[n] = malloc(8)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ sprintf(dargv[n++], "--title");
+ dargv[n++] = title;
+ }
+ if (backtitle != NULL) {
+ if ((dargv[n] = malloc(12)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ sprintf(dargv[n++], "--backtitle");
+ dargv[n++] = backtitle;
+ }
+ if (use_color) {
+ if ((dargv[n] = malloc(11)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ sprintf(dargv[n++], "--colors");
+ }
+ if (use_xdialog) {
+ if ((dargv[n] = malloc(7)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ sprintf(dargv[n++], "--left");
+
+ /*
+ * NOTE: Xdialog(1)'s `--wrap' appears to be broken for the
+ * `--gauge' widget prompt-updates. Add it anyway (in-case it
+ * gets fixed in some later release).
+ */
+ if ((dargv[n] = malloc(7)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ sprintf(dargv[n++], "--wrap");
+ }
+ if ((dargv[n] = malloc(8)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ sprintf(dargv[n++], "--gauge");
+ dargv[n++] = use_xdialog ? dummy_init : init_prompt;
+ if ((dargv[n] = malloc(40)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ snprintf(dargv[n++], 40, "%u", height);
+ if ((dargv[n] = malloc(40)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ snprintf(dargv[n++], 40, "%u", width);
+ dargv[n] = NULL;
+
+ /* Open a pipe(2) to communicate with [X]dialog(1) */
+ if (pipe(stdin_pipe) < 0)
+ err(EXIT_FAILURE, "%s: pipe(2)", __func__);
+
+ /* Fork [X]dialog(1) process */
+#if DIALOG_SPAWN_DEBUG
+ fprintf(stderr, "%s: spawning `", __func__);
+ for (i = 0; i < n; i++) {
+ if (i == 0)
+ fprintf(stderr, "%s", dargv[i]);
+ else if (*dargv[i] == '-' && *(dargv[i] + 1) == '-')
+ fprintf(stderr, " %s", dargv[i]);
+ else
+ fprintf(stderr, " \"%s\"", dargv[i]);
+ }
+ fprintf(stderr, "'\n");
+#endif
+ posix_spawn_file_actions_init(&action);
+ posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
+ posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
+ error = posix_spawnp(pid, dialog, &action,
+ (const posix_spawnattr_t *)NULL, dargv, environ);
+ if (error != 0)
+ err(EXIT_FAILURE, "%s: posix_spawnp(3)", __func__);
+
+ /* NB: Do not free(3) *dargv[], else SIGSEGV */
+
+ return (stdin_pipe[1]);
+}
+
+/*
+ * Returns the number of lines in buffer pointed to by `prompt'. Takes both
+ * newlines and escaped-newlines into account.
+ */
+unsigned int
+dialog_prompt_numlines(const char *prompt, uint8_t nlstate)
+{
+ uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+ const char *cp = prompt;
+ unsigned int nlines = 1;
+
+ if (prompt == NULL || *prompt == '\0')
+ return (0);
+
+ while (*cp != '\0') {
+ if (use_dialog) {
+ if (strncmp(cp, "\\n", 2) == 0) {
+ cp++;
+ nlines++;
+ nls = TRUE; /* See declaration comment */
+ } else if (*cp == '\n') {
+ if (!nls)
+ nlines++;
+ nls = FALSE; /* See declaration comment */
+ }
+ } else if (use_libdialog) {
+ if (*cp == '\n')
+ nlines++;
+ } else if (strncmp(cp, "\\n", 2) == 0) {
+ cp++;
+ nlines++;
+ }
+ cp++;
+ }
+
+ return (nlines);
+}
+
+/*
+ * Returns the length in bytes of the longest line in buffer pointed to by
+ * `prompt'. Takes newlines and escaped newlines into account. Also discounts
+ * dialog(1) color escape codes if enabled (via `use_color' global).
+ */
+unsigned int
+dialog_prompt_longestline(const char *prompt, uint8_t nlstate)
+{
+ uint8_t backslash = 0;
+ uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+ const char *p = prompt;
+ int longest = 0;
+ int n = 0;
+
+ /* `prompt' parameter is required */
+ if (prompt == NULL)
+ return (0);
+ if (*prompt == '\0')
+ return (0); /* shortcut */
+
+ /* Loop until the end of the string */
+ while (*p != '\0') {
+ /* dialog(1) and dialog(3) will render literal newlines */
+ if (use_dialog || use_libdialog) {
+ if (*p == '\n') {
+ if (!use_libdialog && nls)
+ n++;
+ else {
+ if (n > longest)
+ longest = n;
+ n = 0;
+ }
+ nls = FALSE; /* See declaration comment */
+ p++;
+ continue;
+ }
+ }
+
+ /* Check for backslash character */
+ if (*p == '\\') {
+ /* If second backslash, count as a single-char */
+ if ((backslash ^= 1) == 0)
+ n++;
+ } else if (backslash) {
+ if (*p == 'n' && !use_libdialog) { /* new line */
+ /* NB: dialog(3) ignores escaped newlines */
+ nls = TRUE; /* See declaration comment */
+ if (n > longest)
+ longest = n;
+ n = 0;
+ } else if (use_color && *p == 'Z') {
+ if (*++p != '\0')
+ p++;
+ backslash = 0;
+ continue;
+ } else /* [X]dialog(1)/dialog(3) only expand those */
+ n += 2;
+
+ backslash = 0;
+ } else
+ n++;
+ p++;
+ }
+ if (n > longest)
+ longest = n;
+
+ return (longest);
+}
+
+/*
+ * Returns a pointer to the last line in buffer pointed to by `prompt'. Takes
+ * both newlines (if using dialog(1) versus Xdialog(1)) and escaped newlines
+ * into account. If no newlines (escaped or otherwise) appear in the buffer,
+ * `prompt' is returned. If passed a NULL pointer, returns NULL.
+ */
+char *
+dialog_prompt_lastline(char *prompt, uint8_t nlstate)
+{
+ uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+ char *lastline;
+ char *p;
+
+ if (prompt == NULL)
+ return (NULL);
+ if (*prompt == '\0')
+ return (prompt); /* shortcut */
+
+ lastline = p = prompt;
+ while (*p != '\0') {
+ /* dialog(1) and dialog(3) will render literal newlines */
+ if (use_dialog || use_libdialog) {
+ if (*p == '\n') {
+ if (use_libdialog || !nls)
+ lastline = p + 1;
+ nls = FALSE; /* See declaration comment */
+ }
+ }
+ /* dialog(3) does not expand escaped newlines */
+ if (use_libdialog) {
+ p++;
+ continue;
+ }
+ if (*p == '\\' && *(p + 1) != '\0' && *(++p) == 'n') {
+ nls = TRUE; /* See declaration comment */
+ lastline = p + 1;
+ }
+ p++;
+ }
+
+ return (lastline);
+}
+
+/*
+ * Returns the number of extra lines generated by wrapping the text in buffer
+ * pointed to by `prompt' within `ncols' columns (for prompts, this should be
+ * dwidth - 4). Also discounts dialog(1) color escape codes if enabled (via
+ * `use_color' global).
+ */
+int
+dialog_prompt_wrappedlines(char *prompt, int ncols, uint8_t nlstate)
+{
+ uint8_t backslash = 0;
+ uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
+ char *cp;
+ char *p = prompt;
+ int n = 0;
+ int wlines = 0;
+
+ /* `prompt' parameter is required */
+ if (p == NULL)
+ return (0);
+ if (*p == '\0')
+ return (0); /* shortcut */
+
+ /* Loop until the end of the string */
+ while (*p != '\0') {
+ /* dialog(1) and dialog(3) will render literal newlines */
+ if (use_dialog || use_libdialog) {
+ if (*p == '\n') {
+ if (use_dialog || !nls)
+ n = 0;
+ nls = FALSE; /* See declaration comment */
+ }
+ }
+
+ /* Check for backslash character */
+ if (*p == '\\') {
+ /* If second backslash, count as a single-char */
+ if ((backslash ^= 1) == 0)
+ n++;
+ } else if (backslash) {
+ if (*p == 'n' && !use_libdialog) { /* new line */
+ /* NB: dialog(3) ignores escaped newlines */
+ nls = TRUE; /* See declaration comment */
+ n = 0;
+ } else if (use_color && *p == 'Z') {
+ if (*++p != '\0')
+ p++;
+ backslash = 0;
+ continue;
+ } else /* [X]dialog(1)/dialog(3) only expand those */
+ n += 2;
+
+ backslash = 0;
+ } else
+ n++;
+
+ /* Did we pass the width barrier? */
+ if (n > ncols) {
+ /*
+ * Work backward to find the first whitespace on-which
+ * dialog(1) will wrap the line (but don't go before
+ * the start of this line).
+ */
+ cp = p;
+ while (n > 1 && !isspace(*cp)) {
+ cp--;
+ n--;
+ }
+ if (n > 0 && isspace(*cp))
+ p = cp;
+ wlines++;
+ n = 1;
+ }
+
+ p++;
+ }
+
+ return (wlines);
+}
+
+/*
+ * Returns zero if the buffer pointed to by `prompt' contains an escaped
+ * newline but only if appearing after any/all literal newlines. This is
+ * specific to dialog(1) and does not apply to Xdialog(1).
+ *
+ * As an attempt to make shell scripts easier to read, dialog(1) will "eat"
+ * the first literal newline after an escaped newline. This however has a bug
+ * in its implementation in that rather than allowing `\\n\n' to be treated
+ * similar to `\\n' or `\n', dialog(1) expands the `\\n' and then translates
+ * the following literal newline (with or without characters between [!]) into
+ * a single space.
+ *
+ * If you want to be compatible with Xdialog(1), it is suggested that you not
+ * use literal newlines (they aren't supported); but if you have to use them,
+ * go right ahead. But be forewarned... if you set $DIALOG in your environment
+ * to something other than `cdialog' (our current dialog(1)), then it should
+ * do the same thing w/respect to how to handle a literal newline after an
+ * escaped newline (you could do no wrong by translating every literal newline
+ * into a space but only when you've previously encountered an escaped one;
+ * this is what dialog(1) is doing).
+ *
+ * The ``newline state'' (or nlstate for short; as I'm calling it) is helpful
+ * if you plan to combine multiple strings into a single prompt text. In lead-
+ * up to this procedure, a common task is to calculate and utilize the widths
+ * and heights of each piece of prompt text to later be combined. However, if
+ * (for example) the first string ends in a positive newline state (has an
+ * escaped newline without trailing literal), the first literal newline in the
+ * second string will be mangled.
+ *
+ * The return value of this function should be used as the `nlstate' argument
+ * to dialog_*() functions that require it to allow accurate calculations in
+ * the event such information is needed.
+ */
+uint8_t
+dialog_prompt_nlstate(const char *prompt)
+{
+ const char *cp;
+
+ if (prompt == NULL)
+ return 0;
+
+ /*
+ * Work our way backward from the end of the string for efficiency.
+ */
+ cp = prompt + strlen(prompt);
+ while (--cp >= prompt) {
+ /*
+ * If we get to a literal newline first, this prompt ends in a
+ * clean state for rendering with dialog(1). Otherwise, if we
+ * get to an escaped newline first, this prompt ends in an un-
+ * clean state (following literal will be mangled; see above).
+ */
+ if (*cp == '\n')
+ return (0);
+ else if (*cp == 'n' && --cp > prompt && *cp == '\\')
+ return (1);
+ }
+
+ return (0); /* no newlines (escaped or otherwise) */
+}
+
+/*
+ * Free allocated items initialized by tty_maxsize_update() and
+ * x11_maxsize_update()
+ */
+void
+dialog_maxsize_free(void)
+{
+ if (maxsize != NULL) {
+ free(maxsize);
+ maxsize = NULL;
+ }
+}
diff --git a/lib/libdpv/dialog_util.h b/lib/libdpv/dialog_util.h
new file mode 100644
index 0000000..e279c3f
--- /dev/null
+++ b/lib/libdpv/dialog_util.h
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DIALOG_UTIL_H_
+#define _DIALOG_UTIL_H_
+
+#include <sys/types.h>
+
+#include "dialogrc.h"
+
+#define DIALOG_SPAWN_DEBUG 0 /* Debug spawning of [X]dialog(1) */
+
+/* dialog(3) and [X]dialog(1) characteristics */
+#define DIALOG "dialog"
+#define XDIALOG "Xdialog"
+#define PROMPT_MAX 16384
+#define ENV_DIALOG "DIALOG"
+#define ENV_USE_COLOR "USE_COLOR"
+#define ENV_XDIALOG_HIGH_DIALOG_COMPAT "XDIALOG_HIGH_DIALOG_COMPAT"
+extern uint8_t dialog_test;
+extern uint8_t use_libdialog;
+extern uint8_t use_dialog;
+extern uint8_t use_xdialog;
+extern uint8_t use_color;
+extern char dialog[];
+
+/* dialog(3) and [X]dialog(1) functionality */
+extern char *title, *backtitle;
+extern int dheight, dwidth;
+
+__BEGIN_DECLS
+uint8_t dialog_prompt_nlstate(const char *_prompt);
+void dialog_gauge_free(void);
+void dialog_maxsize_free(void);
+char *dialog_prompt_lastline(char *_prompt, uint8_t _nlstate);
+int dialog_maxcols(void);
+int dialog_maxrows(void);
+int dialog_prompt_wrappedlines(char *_prompt, int _ncols,
+ uint8_t _nlstate);
+int dialog_spawn_gauge(char *_init_prompt, pid_t *_pid);
+int tty_maxcols(void);
+#define tty_maxrows() dialog_maxrows()
+unsigned int dialog_prompt_longestline(const char *_prompt,
+ uint8_t _nlstate);
+unsigned int dialog_prompt_numlines(const char *_prompt, uint8_t _nlstate);
+__END_DECLS
+
+#endif /* !_DIALOG_UTIL_H_ */
diff --git a/lib/libdpv/dialogrc.c b/lib/libdpv/dialogrc.c
new file mode 100644
index 0000000..eb4a536
--- /dev/null
+++ b/lib/libdpv/dialogrc.c
@@ -0,0 +1,359 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <err.h>
+#include <errno.h>
+#include <figpar.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_m.h>
+
+#include "dialogrc.h"
+
+#define STR_BUFSIZE 255
+
+/* dialog(1) `.dialogrc' characteristics */
+uint8_t use_colors = 1;
+uint8_t use_shadow = 1;
+char gauge_color[STR_BUFSIZE] = "47b"; /* (BLUE,WHITE,ON) */
+char separator[STR_BUFSIZE] = "";
+
+/* Function prototypes */
+static int setattr(struct fp_config *, uint32_t, char *, char *);
+static int setbool(struct fp_config *, uint32_t, char *, char *);
+static int setnum(struct fp_config *, uint32_t, char *, char *);
+static int setstr(struct fp_config *, uint32_t, char *, char *);
+
+/*
+ * Anatomy of DIALOGRC (~/.dialogrc by default)
+ * NOTE: Must appear after private function prototypes (above)
+ * NB: Brace-initialization of union requires cast to *first* member of union
+ */
+static struct fp_config dialogrc_config[] = {
+ /* TYPE Directive DEFAULT HANDLER */
+ {FP_TYPE_INT, "aspect", {(void *)0}, &setnum},
+ {FP_TYPE_STR, "separate_widget", {separator}, &setstr},
+ {FP_TYPE_INT, "tab_len", {(void *)0}, &setnum},
+ {FP_TYPE_BOOL, "visit_items", {(void *)0}, &setbool},
+ {FP_TYPE_BOOL, "use_shadow", {(void *)1}, &setbool},
+ {FP_TYPE_BOOL, "use_colors", {(void *)1}, &setbool},
+ {FP_TYPE_STR, "screen_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "shadow_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "dialog_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "title_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "border_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "button_active_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "button_inactive_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "button_key_active_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "button_key_inactive_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "button_label_active_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "button_label_inactive_color",{NULL}, &setattr},
+ {FP_TYPE_STR, "inputbox_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "inputbox_border_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "searchbox_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "searchbox_title_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "searchbox_border_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "position_indicator_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "menubox_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "menubox_border_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "item_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "item_selected_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "tag_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "tag_selected_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "tag_key_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "tag_key_selected_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "check_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "check_selected_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "uarrow_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "darrow_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "itemhelp_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "form_active_text_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "form_text_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "form_item_readonly_color", {NULL}, &setattr},
+ {FP_TYPE_STR, "gauge_color", {gauge_color}, &setattr},
+ {0, NULL, {0}, NULL}
+};
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `Attribute'
+ */
+static int
+setattr(struct fp_config *option, uint32_t line __unused,
+ char *directive __unused, char *value)
+{
+ char *cp = value;
+ char *val;
+ size_t len;
+ char attrbuf[4];
+
+ if (option == NULL) {
+ warnx("%s:%d:%s: Missing callback parameter", __FILE__,
+ __LINE__, __func__);
+ return (-1); /* Abort processing */
+ }
+
+ /* Allocate memory for the data if not already done */
+ if (option->value.str == NULL) {
+ if ((option->value.str = malloc(STR_BUFSIZE)) == NULL)
+ return (-1);
+ }
+
+ /*
+ * If the first character is left-parenthesis, the format is
+ * `(background,foreground,highlight)' otherwise, we should take it
+ * as a reference to another color.
+ */
+ if (*cp != '(') {
+ /* Copy the [current] value from the referenced color */
+ val = dialogrc_config_option(cp)->value.str;
+ if (val != NULL)
+ snprintf(option->value.str, STR_BUFSIZE, "%s", val);
+
+ return (0);
+ } else
+ cp++;
+
+ strtolower(cp);
+
+ /* Initialize the attrbuf (fg,bg,hi,NUL) */
+ attrbuf[0] = '0';
+ attrbuf[1] = '0';
+ attrbuf[2] = 'B'; /* \ZB = disable; \Zb = enable (see dialog(1)) */
+ attrbuf[3] = '\0';
+
+ /* Interpret the foreground color */
+ if (strncmp(cp, "red,", 4) == 0) attrbuf[0] = '1';
+ else if (strncmp(cp, "green,", 6) == 0) attrbuf[0] = '2';
+ else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[0] = '3';
+ else if (strncmp(cp, "blue,", 5) == 0) attrbuf[0] = '4';
+ else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[0] = '5';
+ else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[0] = '6';
+ else if (strncmp(cp, "white,", 6) == 0) attrbuf[0] = '7';
+ else if (strncmp(cp, "black,", 6) == 0) attrbuf[0] = '8';
+
+ /* Advance to the background color */
+ cp = strchr(cp, ',');
+ if (cp == NULL)
+ goto write_attrbuf;
+ else
+ cp++;
+
+ /* Interpret the background color */
+ if (strncmp(cp, "red,", 4) == 0) attrbuf[1] = '1';
+ else if (strncmp(cp, "green,", 6) == 0) attrbuf[1] = '2';
+ else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[1] = '3';
+ else if (strncmp(cp, "blue,", 5) == 0) attrbuf[1] = '4';
+ else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[1] = '5';
+ else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[1] = '6';
+ else if (strncmp(cp, "white,", 6) == 0) attrbuf[1] = '7';
+ else if (strncmp(cp, "black,", 6) == 0) attrbuf[1] = '8';
+
+ /* Advance to the highlight */
+ cp = strchr(cp, ',');
+ if (cp == NULL)
+ goto write_attrbuf;
+ else
+ cp++;
+
+ /* Trim trailing parenthesis */
+ len = strlen(cp);
+ if (cp[len - 1] == ')')
+ cp[len - 1] = '\0';
+
+ /* Interpret the highlight (initialized to off above) */
+ if (strcmp(cp, "on") == 0 || strncmp(cp, "on,", 3) == 0)
+ attrbuf[2] = 'b'; /* \Zb = enable bold (see dialog(1)) */
+
+write_attrbuf:
+ sprintf(option->value.str, "%s", attrbuf);
+
+ return (0);
+}
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `Boolean'
+ */
+static int
+setbool(struct fp_config *option, uint32_t line __unused,
+ char *directive __unused, char *value)
+{
+
+ if (option == NULL) {
+ warnx("%s:%d:%s: Missing callback parameter", __FILE__,
+ __LINE__, __func__);
+ return (-1); /* Abort processing */
+ }
+
+ /* Assume ON, check for OFF (case-insensitive) */
+ option->value.boolean = 1;
+ strtolower(value);
+ if (strcmp(value, "off") == 0)
+ option->value.boolean = 0;
+
+ return (0);
+}
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `Number'
+ */
+static int
+setnum(struct fp_config *option, uint32_t line __unused,
+ char *directive __unused, char *value)
+{
+
+ if (option == NULL) {
+ warnx("%s:%d:%s: Missing callback parameter", __FILE__,
+ __LINE__, __func__);
+ return (-1); /* Abort processing */
+ }
+
+ /* Convert the string to a 32-bit signed integer */
+ option->value.num = (int32_t)strtol(value, (char **)NULL, 10);
+
+ return (0);
+}
+
+/*
+ * figpar call-back for interpreting value as .dialogrc `String'
+ */
+static int
+setstr(struct fp_config *option, uint32_t line __unused,
+ char *directive __unused, char *value)
+{
+ size_t len;
+
+ if (option == NULL) {
+ warnx("%s:%d:%s: Missing callback parameter", __FILE__,
+ __LINE__, __func__);
+ return (-1); /* Abort processing */
+ }
+
+ /* Allocate memory for the data if not already done */
+ if (option->value.str == NULL) {
+ if ((option->value.str = malloc(STR_BUFSIZE)) == NULL)
+ return (-1);
+ }
+
+ /* Trim leading quote */
+ if (*value == '"')
+ value++;
+
+ /* Write the data into the buffer */
+ snprintf(option->value.str, STR_BUFSIZE, "%s", value);
+
+ /* Trim trailing quote */
+ len = strlen(option->value.str);
+ if (option->value.str[len - 1] == '"')
+ option->value.str[len - 1] = '\0';
+
+ return (0);
+}
+
+/*
+ * Parse (in order of preference) $DIALOGRC or `$HOME/.dialogrc'. Returns zero
+ * on success, -1 on failure (and errno should be consulted).
+ */
+int
+parse_dialogrc(void)
+{
+ char *cp;
+ int res;
+ size_t len;
+ char path[PATH_MAX];
+
+ /* Allow $DIALOGRC to override `$HOME/.dialogrc' default */
+ if ((cp = getenv(ENV_DIALOGRC)) != NULL && *cp != '\0')
+ snprintf(path, PATH_MAX, "%s", cp);
+ else if ((cp = getenv(ENV_HOME)) != NULL) {
+ /* Copy $HOME into buffer and append trailing `/' if missing */
+ snprintf(path, PATH_MAX, "%s", cp);
+ len = strlen(path);
+ cp = path + len;
+ if (len > 0 && len < (PATH_MAX - 1) && *(cp - 1) != '/') {
+ *cp++ = '/';
+ *cp = '\0';
+ len++;
+ }
+
+ /* If we still have room, shove in the name of rc file */
+ if (len < (PATH_MAX - 1))
+ snprintf(cp, PATH_MAX - len, "%s", DIALOGRC);
+ } else {
+ /* Like dialog(1), don't process a file if $HOME is unset */
+ errno = ENOENT;
+ return (-1);
+ }
+
+ /* Process file (either $DIALOGRC if set, or `$HOME/.dialogrc') */
+ res = parse_config(dialogrc_config, path, NULL, FP_BREAK_ON_EQUALS);
+
+ /* Set some globals based on what we parsed */
+ use_shadow = dialogrc_config_option("use_shadow")->value.boolean;
+ use_colors = dialogrc_config_option("use_colors")->value.boolean;
+ snprintf(gauge_color, STR_BUFSIZE, "%s",
+ dialogrc_config_option("gauge_color")->value.str);
+
+ return (res);
+}
+
+/*
+ * Return a pointer to the `.dialogrc' config option specific to `directive' or
+ * static fp_dummy_config (full of NULLs) if none found (see
+ * get_config_option(3); part of figpar(3)).
+ */
+struct fp_config *
+dialogrc_config_option(const char *directive)
+{
+ return (get_config_option(dialogrc_config, directive));
+}
+
+/*
+ * Free allocated items initialized by setattr() (via parse_config() callback
+ * matrix [dialogrc_config] used in parse_dialogrc() above).
+ */
+void
+dialogrc_free(void)
+{
+ char *value;
+ uint32_t n;
+
+ for (n = 0; dialogrc_config[n].directive != NULL; n++) {
+ if (dialogrc_config[n].action != &setattr)
+ continue;
+ value = dialogrc_config[n].value.str;
+ if (value != NULL && value != gauge_color) {
+ free(dialogrc_config[n].value.str);
+ dialogrc_config[n].value.str = NULL;
+ }
+ }
+}
diff --git a/lib/libproc/test/t3-name2sym/t3-name2sym.c b/lib/libdpv/dialogrc.h
index 0be8653..7d17235 100644
--- a/lib/libproc/test/t3-name2sym/t3-name2sym.c
+++ b/lib/libdpv/dialogrc.h
@@ -1,51 +1,56 @@
-/*
- * Copyright (c) 2010 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Rui Paulo under sponsorship from the
- * FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
*/
+
+#ifndef _DIALOGRC_H_
+#define _DIALOGRC_H_
+
#include <sys/types.h>
-#include <assert.h>
-#include <stdio.h>
-#include <libproc.h>
-#include <gelf.h>
-#include <string.h>
-
-int
-main(int argc, char *argv[])
-{
- prmap_t *map = NULL;
- struct proc_handle *phdl;
- GElf_Sym sym;
-
- proc_create("./t3-name2sym", argv, NULL, NULL, &phdl);
- memset(&sym, 0, sizeof(sym));
- assert(proc_name2sym(phdl, "ld-elf.so.1", "r_debug_state", &sym) == 0);
- printf("0x%lx\n", sym.st_value);
- assert(proc_name2sym(phdl, "t3-name2sym", "main", &sym) == 0);
- printf("0x%lx\n", sym.st_value);
-}
+
+#include <figpar.h>
+
+/* dialog(3) dlg_color_table[] attributes */
+#define GAUGE_ATTR 33 /* entry used for gauge_color */
+
+/* dialog(1) characteristics */
+#define DIALOGRC ".dialogrc"
+#define ENV_DIALOGRC "DIALOGRC"
+#define ENV_HOME "HOME"
+
+/* dialog(1) `.dialogrc' characteristics */
+extern uint8_t use_colors;
+extern uint8_t use_shadow;
+extern char gauge_color[];
+extern char separator[];
+
+__BEGIN_DECLS
+void dialogrc_free(void);
+int parse_dialogrc(void);
+struct fp_config *dialogrc_config_option(const char *_directive);
+__END_DECLS
+
+#endif /* !_DIALOGRC_H_ */
diff --git a/lib/libdpv/dprompt.c b/lib/libdpv/dprompt.c
new file mode 100644
index 0000000..031f550
--- /dev/null
+++ b/lib/libdpv/dprompt.c
@@ -0,0 +1,770 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#define _BSD_SOURCE /* to get dprintf() prototype in stdio.h below */
+#include <dialog.h>
+#include <err.h>
+#include <libutil.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_m.h>
+#include <unistd.h>
+
+#include "dialog_util.h"
+#include "dialogrc.h"
+#include "dprompt.h"
+#include "dpv.h"
+#include "dpv_private.h"
+
+#define FLABEL_MAX 1024
+
+static int fheight = 0; /* initialized by dprompt_init() */
+static char dprompt[PROMPT_MAX + 1] = "";
+static char *dprompt_pos = (char *)(0); /* treated numerically */
+
+/* Display characteristics */
+#define FM_DONE 0x01
+#define FM_FAIL 0x02
+#define FM_PEND 0x04
+static uint8_t dprompt_free_mask;
+static char *done = NULL;
+static char *fail = NULL;
+static char *pend = NULL;
+int display_limit = DISPLAY_LIMIT_DEFAULT; /* Max entries to show */
+int label_size = LABEL_SIZE_DEFAULT; /* Max width for labels */
+int pbar_size = PBAR_SIZE_DEFAULT; /* Mini-progressbar size */
+static int gauge_percent = 0;
+static int done_size, done_lsize, done_rsize;
+static int fail_size, fail_lsize, fail_rsize;
+static int mesg_size, mesg_lsize, mesg_rsize;
+static int pend_size, pend_lsize, pend_rsize;
+static int pct_lsize, pct_rsize;
+static void *gauge = NULL;
+#define SPIN_SIZE 4
+static char spin[SPIN_SIZE + 1] = "/-\\|";
+static char msg[PROMPT_MAX + 1];
+static char *spin_cp = spin;
+
+/* Function prototypes */
+static char spin_char(void);
+static int dprompt_add_files(struct dpv_file_node *file_list,
+ struct dpv_file_node *curfile, int pct);
+
+/*
+ * Returns a pointer to the current spin character in the spin string and
+ * advances the global position to the next character for the next call.
+ */
+static char
+spin_char(void)
+{
+ char ch;
+
+ if (spin_cp == '\0')
+ spin_cp = spin;
+ ch = *spin_cp;
+
+ /* Advance the spinner to the next char */
+ if (++spin_cp >= (spin + SPIN_SIZE))
+ spin_cp = spin;
+
+ return (ch);
+}
+
+/*
+ * Initialize heights and widths based on various strings and environment
+ * variables (such as ENV_USE_COLOR).
+ */
+void
+dprompt_init(struct dpv_file_node *file_list)
+{
+ uint8_t nls = 0;
+ int len;
+ int max_cols;
+ int max_rows;
+ int nthfile;
+ int numlines;
+ struct dpv_file_node *curfile;
+
+ /*
+ * Initialize dialog(3) `colors' support and draw backtitle
+ */
+ if (use_libdialog && !debug) {
+ init_dialog(stdin, stdout);
+ dialog_vars.colors = 1;
+ if (backtitle != NULL) {
+ dialog_vars.backtitle = (char *)backtitle;
+ dlg_put_backtitle();
+ }
+ }
+
+ /* Calculate width of dialog(3) or [X]dialog(1) --gauge box */
+ dwidth = label_size + pbar_size + 9;
+
+ /*
+ * Calculate height of dialog(3) or [X]dialog(1) --gauge box
+ */
+ dheight = 5;
+ max_rows = dialog_maxrows();
+ /* adjust max_rows for backtitle and/or dialog(3) statusLine */
+ if (backtitle != NULL)
+ max_rows -= use_shadow ? 3 : 2;
+ if (use_libdialog && use_shadow)
+ max_rows -= 2;
+ /* add lines for `-p text' */
+ numlines = dialog_prompt_numlines(pprompt, 0);
+ if (debug)
+ warnx("`-p text' is %i line%s long", numlines,
+ numlines == 1 ? "" : "s");
+ dheight += numlines;
+ /* adjust dheight for various implementations */
+ if (use_dialog) {
+ dheight -= dialog_prompt_nlstate(pprompt);
+ nls = dialog_prompt_nlstate(pprompt);
+ } else if (use_xdialog) {
+ if (pprompt == NULL || *pprompt == '\0')
+ dheight++;
+ } else if (use_libdialog) {
+ if (pprompt != NULL && *pprompt != '\0')
+ dheight--;
+ }
+ /* limit the number of display items (necessary per dialog(1,3)) */
+ if (display_limit == 0 || display_limit > DPV_DISPLAY_LIMIT)
+ display_limit = DPV_DISPLAY_LIMIT;
+ /* verify fheight will fit (stop if we hit 1) */
+ for (; display_limit > 0; display_limit--) {
+ nthfile = numlines = 0;
+ fheight = (int)dpv_nfiles > display_limit ?
+ (unsigned int)display_limit : dpv_nfiles;
+ for (curfile = file_list; curfile != NULL;
+ curfile = curfile->next) {
+ nthfile++;
+ numlines += dialog_prompt_numlines(curfile->name, nls);
+ if ((nthfile % display_limit) == 0) {
+ if (numlines > fheight)
+ fheight = numlines;
+ numlines = nthfile = 0;
+ }
+ }
+ if (numlines > fheight)
+ fheight = numlines;
+ if ((dheight + fheight +
+ (int)dialog_prompt_numlines(aprompt, use_dialog) -
+ (use_dialog ? (int)dialog_prompt_nlstate(aprompt) : 0))
+ <= max_rows)
+ break;
+ }
+ /* don't show any items if we run the risk of hitting a blank set */
+ if ((max_rows - (use_shadow ? 5 : 4)) >= fheight)
+ dheight += fheight;
+ else
+ fheight = 0;
+ /* add lines for `-a text' */
+ numlines = dialog_prompt_numlines(aprompt, use_dialog);
+ if (debug)
+ warnx("`-a text' is %i line%s long", numlines,
+ numlines == 1 ? "" : "s");
+ dheight += numlines;
+
+ /* If using Xdialog(1), adjust accordingly (based on testing) */
+ if (use_xdialog)
+ dheight += dheight / 4;
+
+ /* For wide mode, long prefix (`pprompt') or append (`aprompt')
+ * strings will bump width */
+ if (wide) {
+ len = (int)dialog_prompt_longestline(pprompt, 0); /* !nls */
+ if ((len + 4) > dwidth)
+ dwidth = len + 4;
+ len = (int)dialog_prompt_longestline(aprompt, 1); /* nls */
+ if ((len + 4) > dwidth)
+ dwidth = len + 4;
+ }
+
+ /* Enforce width constraints to maximum values */
+ max_cols = dialog_maxcols();
+ if (max_cols > 0 && dwidth > max_cols)
+ dwidth = max_cols;
+
+ /* Optimize widths to sane values*/
+ if (pbar_size > dwidth - 9) {
+ pbar_size = dwidth - 9;
+ label_size = 0;
+ /* -9 = "| - [" ... "] |" */
+ }
+ if (pbar_size < 0)
+ label_size = dwidth - 8;
+ /* -8 = "| " ... " - |" */
+ else if (label_size > (dwidth - pbar_size - 9) || wide)
+ label_size = no_labels ? 0 : dwidth - pbar_size - 9;
+ /* -9 = "| " ... " - [" ... "] |" */
+
+ /* Hide labels if requested */
+ if (no_labels)
+ label_size = 0;
+
+ /* Touch up the height (now that we know dwidth) */
+ dheight += dialog_prompt_wrappedlines(pprompt, dwidth - 4, 0);
+ dheight += dialog_prompt_wrappedlines(aprompt, dwidth - 4, 1);
+
+ if (debug)
+ warnx("dheight = %i dwidth = %i fheight = %i",
+ dheight, dwidth, fheight);
+
+ /* Calculate left/right portions of % */
+ pct_lsize = (pbar_size - 4) / 2; /* -4 == printf("%-3s%%", pct) */
+ pct_rsize = pct_lsize;
+ /* If not evenly divisible by 2, increment the right-side */
+ if ((pct_rsize + pct_rsize + 4) != pbar_size)
+ pct_rsize++;
+
+ /* Initialize "Done" text */
+ if (done == NULL && (done = msg_done) == NULL) {
+ if ((done = getenv(ENV_MSG_DONE)) != NULL)
+ done_size = strlen(done);
+ else {
+ done_size = strlen(DPV_DONE_DEFAULT);
+ if ((done = malloc(done_size + 1)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ dprompt_free_mask |= FM_DONE;
+ snprintf(done, done_size + 1, DPV_DONE_DEFAULT);
+ }
+ }
+ if (pbar_size < done_size) {
+ done_lsize = done_rsize = 0;
+ *(done + pbar_size) = '\0';
+ done_size = pbar_size;
+ } else {
+ /* Calculate left/right portions for mini-progressbar */
+ done_lsize = (pbar_size - done_size) / 2;
+ done_rsize = done_lsize;
+ /* If not evenly divisible by 2, increment the right-side */
+ if ((done_rsize + done_size + done_lsize) != pbar_size)
+ done_rsize++;
+ }
+
+ /* Initialize "Fail" text */
+ if (fail == NULL && (fail = msg_fail) == NULL) {
+ if ((fail = getenv(ENV_MSG_FAIL)) != NULL)
+ fail_size = strlen(fail);
+ else {
+ fail_size = strlen(DPV_FAIL_DEFAULT);
+ if ((fail = malloc(fail_size + 1)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ dprompt_free_mask |= FM_FAIL;
+ snprintf(fail, fail_size + 1, DPV_FAIL_DEFAULT);
+ }
+ }
+ if (pbar_size < fail_size) {
+ fail_lsize = fail_rsize = 0;
+ *(fail + pbar_size) = '\0';
+ fail_size = pbar_size;
+ } else {
+ /* Calculate left/right portions for mini-progressbar */
+ fail_lsize = (pbar_size - fail_size) / 2;
+ fail_rsize = fail_lsize;
+ /* If not evenly divisible by 2, increment the right-side */
+ if ((fail_rsize + fail_size + fail_lsize) != pbar_size)
+ fail_rsize++;
+ }
+
+ /* Initialize "Pending" text */
+ if (pend == NULL && (pend = msg_pending) == NULL) {
+ if ((pend = getenv(ENV_MSG_PENDING)) != NULL)
+ pend_size = strlen(pend);
+ else {
+ pend_size = strlen(DPV_PENDING_DEFAULT);
+ if ((pend = malloc(pend_size + 1)) == NULL)
+ errx(EXIT_FAILURE, "Out of memory?!");
+ dprompt_free_mask |= FM_PEND;
+ snprintf(pend, pend_size + 1, DPV_PENDING_DEFAULT);
+ }
+ }
+ if (pbar_size < pend_size) {
+ pend_lsize = pend_rsize = 0;
+ *(pend + pbar_size) = '\0';
+ pend_size = pbar_size;
+ } else {
+ /* Calculate left/right portions for mini-progressbar */
+ pend_lsize = (pbar_size - pend_size) / 2;
+ pend_rsize = pend_lsize;
+ /* If not evenly divisible by 2, increment the right-side */
+ if ((pend_rsize + pend_lsize + pend_size) != pbar_size)
+ pend_rsize++;
+ }
+
+ if (debug)
+ warnx("label_size = %i pbar_size = %i", label_size, pbar_size);
+
+ dprompt_clear();
+}
+
+/*
+ * Clear the [X]dialog(1) `--gauge' prompt buffer.
+ */
+void
+dprompt_clear(void)
+{
+
+ *dprompt = '\0';
+ dprompt_pos = dprompt;
+}
+
+/*
+ * Append to the [X]dialog(1) `--gauge' prompt buffer. Syntax is like printf(3)
+ * and returns the number of bytes appended to the buffer.
+ */
+int
+dprompt_add(const char *format, ...)
+{
+ int len;
+ va_list ap;
+
+ if (dprompt_pos >= (dprompt + PROMPT_MAX))
+ return (0);
+
+ va_start(ap, format);
+ len = vsnprintf(dprompt_pos, (size_t)(PROMPT_MAX -
+ (dprompt_pos - dprompt)), format, ap);
+ va_end(ap);
+ if (len == -1)
+ errx(EXIT_FAILURE, "%s: Oops, dprompt buffer overflow",
+ __func__);
+
+ if ((dprompt_pos + len) < (dprompt + PROMPT_MAX))
+ dprompt_pos += len;
+ else
+ dprompt_pos = dprompt + PROMPT_MAX;
+
+ return (len);
+}
+
+/*
+ * Append active files to the [X]dialog(1) `--gauge' prompt buffer. Syntax
+ * requires a pointer to the head of the dpv_file_node linked-list. Returns the
+ * number of files processed successfully.
+ */
+static int
+dprompt_add_files(struct dpv_file_node *file_list,
+ struct dpv_file_node *curfile, int pct)
+{
+ char c;
+ char bold_code = 'b'; /* default: enabled */
+ char color_code = '4'; /* default: blue */
+ uint8_t after_curfile = curfile != NULL ? FALSE : TRUE;
+ uint8_t nls = 0;
+ char *cp;
+ char *lastline;
+ char *name;
+ const char *bg_code;
+ const char *estext;
+ const char *format;
+ enum dprompt_state dstate;
+ int estext_lsize;
+ int estext_rsize;
+ int estext_size;
+ int flabel_size;
+ int hlen;
+ int lsize;
+ int nlines = 0;
+ int nthfile = 0;
+ int pwidth;
+ int rsize;
+ struct dpv_file_node *fp;
+ char flabel[FLABEL_MAX + 1];
+ char human[32];
+ char pbar[pbar_size + 16]; /* +15 for optional color */
+ char pbar_cap[sizeof(pbar)];
+ char pbar_fill[sizeof(pbar)];
+
+
+ /* Override color defaults with that of main progress bar */
+ if (use_colors || use_shadow) { /* NB: shadow enables color */
+ color_code = gauge_color[0];
+ /* NB: str[1] aka bg is unused */
+ bold_code = gauge_color[2];
+ }
+
+ /*
+ * Create mini-progressbar for current file (if applicable)
+ */
+ *pbar = '\0';
+ if (pbar_size >= 0 && pct >= 0 && curfile != NULL &&
+ (curfile->length >= 0 || dialog_test)) {
+ snprintf(pbar, pbar_size + 1, "%*s%3u%%%*s", pct_lsize, "",
+ pct, pct_rsize, "");
+ if (use_color) {
+ /* Calculate the fill-width of progressbar */
+ pwidth = pct * pbar_size / 100;
+ /* Round up based on one-tenth of a percent */
+ if ((pct * pbar_size % 100) > 50)
+ pwidth++;
+
+ /*
+ * Make two copies of pbar. Make one represent the fill
+ * and the other the remainder (cap). We'll insert the
+ * ANSI delimiter in between.
+ */
+ *pbar_fill = '\0';
+ *pbar_cap = '\0';
+ strncat(pbar_fill, (const char *)(pbar), dwidth);
+ *(pbar_fill + pwidth) = '\0';
+ strncat(pbar_cap, (const char *)(pbar+pwidth), dwidth);
+
+ /* Finalize the mini [color] progressbar */
+ snprintf(pbar, sizeof(pbar),
+ "\\Z%c\\Zr\\Z%c%s%s%s\\Zn", bold_code, color_code,
+ pbar_fill, "\\ZR", pbar_cap);
+ }
+ }
+
+ for (fp = file_list; fp != NULL; fp = fp->next) {
+ flabel_size = label_size;
+ name = fp->name;
+ nthfile++;
+
+ /*
+ * Support multiline filenames (where the filename is taken as
+ * the last line and the text leading up to the last line can
+ * be used as (for example) a heading/separator between files.
+ */
+ if (use_dialog)
+ nls = dialog_prompt_nlstate(pprompt);
+ nlines += dialog_prompt_numlines(name, nls);
+ lastline = dialog_prompt_lastline(name, 1);
+ if (name != lastline) {
+ c = *lastline;
+ *lastline = '\0';
+ dprompt_add("%s", name);
+ *lastline = c;
+ name = lastline;
+ }
+
+ /* Support color codes (for dialog(1,3)) in file names */
+ if ((use_dialog || use_libdialog) && use_color) {
+ cp = name;
+ while (*cp != '\0') {
+ if (*cp == '\\' && *(cp + 1) != '\0' &&
+ *(++cp) == 'Z' && *(cp + 1) != '\0') {
+ cp++;
+ flabel_size += 3;
+ }
+ cp++;
+ }
+ if (flabel_size > FLABEL_MAX)
+ flabel_size = FLABEL_MAX;
+ }
+
+ /* If no mini-progressbar, increase label width */
+ if (pbar_size < 0 && flabel_size <= FLABEL_MAX - 2 &&
+ no_labels == FALSE)
+ flabel_size += 2;
+
+ /* If name is too long, add an ellipsis */
+ if (snprintf(flabel, flabel_size + 1, "%s", name) >
+ flabel_size) sprintf(flabel + flabel_size - 3, "...");
+
+ /*
+ * Append the label (processing the current file differently)
+ */
+ if (fp == curfile && pct < 100) {
+ /*
+ * Add an ellipsis to current file name if it will fit.
+ * There may be an ellipsis already from truncating the
+ * label (in which case, we already have one).
+ */
+ cp = flabel + strlen(flabel);
+ if (cp < (flabel + flabel_size))
+ snprintf(cp, flabel_size -
+ (cp - flabel) + 1, "...");
+
+ /* Append label (with spinner and optional color) */
+ dprompt_add("%s%-*s%s %c", use_color ? "\\Zb" : "",
+ flabel_size, flabel, use_color ? "\\Zn" : "",
+ spin_char());
+ } else
+ dprompt_add("%-*s%s %s", flabel_size,
+ flabel, use_color ? "\\Zn" : "", " ");
+
+ /*
+ * Append pbar/status (processing the current file differently)
+ */
+ dstate = DPROMPT_NONE;
+ if (fp->msg != NULL)
+ dstate = DPROMPT_CUSTOM_MSG;
+ else if (pbar_size < 0)
+ dstate = DPROMPT_NONE;
+ else if (pbar_size < 4)
+ dstate = DPROMPT_MINIMAL;
+ else if (after_curfile)
+ dstate = DPROMPT_PENDING;
+ else if (fp == curfile) {
+ if (*pbar == '\0') {
+ if (fp->length < 0)
+ dstate = DPROMPT_DETAILS;
+ else if (fp->status == DPV_STATUS_RUNNING)
+ dstate = DPROMPT_DETAILS;
+ else
+ dstate = DPROMPT_END_STATE;
+ }
+ else if (dialog_test) /* status/length ignored */
+ dstate = pct < 100 ?
+ DPROMPT_PBAR : DPROMPT_END_STATE;
+ else if (fp->status == DPV_STATUS_RUNNING)
+ dstate = fp->length < 0 ?
+ DPROMPT_DETAILS : DPROMPT_PBAR;
+ else /* not running */
+ dstate = fp->length < 0 ?
+ DPROMPT_DETAILS : DPROMPT_END_STATE;
+ } else { /* before curfile */
+ if (dialog_test)
+ dstate = DPROMPT_END_STATE;
+ else
+ dstate = fp->length < 0 ?
+ DPROMPT_DETAILS : DPROMPT_END_STATE;
+ }
+ format = use_color ?
+ " [\\Z%c%s%-*s%s%-*s\\Zn]\\n" :
+ " [%-*s%s%-*s]\\n";
+ if (fp->status == DPV_STATUS_FAILED) {
+ bg_code = "\\Zr\\Z1"; /* Red */
+ estext_lsize = fail_lsize;
+ estext_rsize = fail_rsize;
+ estext_size = fail_size;
+ estext = fail;
+ } else { /* e.g., DPV_STATUS_DONE */
+ bg_code = "\\Zr\\Z2"; /* Green */
+ estext_lsize = done_lsize;
+ estext_rsize = done_rsize;
+ estext_size = done_size;
+ estext = done;
+ }
+ switch (dstate) {
+ case DPROMPT_PENDING: /* Future file(s) */
+ dprompt_add(" [%-*s%s%-*s]\\n",
+ pend_lsize, "", pend, pend_rsize, "");
+ break;
+ case DPROMPT_PBAR: /* Current file */
+ dprompt_add(" [%s]\\n", pbar);
+ break;
+ case DPROMPT_END_STATE: /* Past/Current file(s) */
+ if (use_color)
+ dprompt_add(format, bold_code, bg_code,
+ estext_lsize, "", estext,
+ estext_rsize, "");
+ else
+ dprompt_add(format,
+ estext_lsize, "", estext,
+ estext_rsize, "");
+ break;
+ case DPROMPT_DETAILS: /* Past/Current file(s) */
+ humanize_number(human, pbar_size + 2, fp->read, "",
+ HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000);
+
+ /* Calculate center alignment */
+ hlen = (int)strlen(human);
+ lsize = (pbar_size - hlen) / 2;
+ rsize = lsize;
+ if ((lsize+hlen+rsize) != pbar_size)
+ rsize++;
+
+ if (use_color)
+ dprompt_add(format, bold_code, bg_code,
+ lsize, "", human, rsize, "");
+ else
+ dprompt_add(format,
+ lsize, "", human, rsize, "");
+ break;
+ case DPROMPT_CUSTOM_MSG: /* File-specific message override */
+ snprintf(msg, PROMPT_MAX + 1, "%s", fp->msg);
+ if (pbar_size < (mesg_size = strlen(msg))) {
+ mesg_lsize = mesg_rsize = 0;
+ *(msg + pbar_size) = '\0';
+ mesg_size = pbar_size;
+ } else {
+ mesg_lsize = (pbar_size - mesg_size) / 2;
+ mesg_rsize = mesg_lsize;
+ if ((mesg_rsize + mesg_size + mesg_lsize)
+ != pbar_size)
+ mesg_rsize++;
+ }
+ if (use_color)
+ dprompt_add(format, bold_code, bg_code,
+ mesg_lsize, "", msg, mesg_rsize, "");
+ else
+ dprompt_add(format, mesg_lsize, "", msg,
+ mesg_rsize, "");
+ break;
+ case DPROMPT_MINIMAL: /* Short progress bar, minimal room */
+ if (use_color)
+ dprompt_add(format, bold_code, bg_code,
+ pbar_size, "", "", 0, "");
+ else
+ dprompt_add(format, pbar_size, "", "", 0, "");
+ break;
+ case DPROMPT_NONE: /* pbar_size < 0 */
+ /* FALLTHROUGH */
+ default:
+ dprompt_add(" \\n");
+ /*
+ * NB: Leading space required for the case when
+ * spin_char() returns a single backslash [\] which
+ * without the space, changes the meaning of `\n'
+ */
+ }
+
+ /* Stop building if we've hit the internal limit */
+ if (nthfile >= display_limit)
+ break;
+
+ /* If this is the current file, all others are pending */
+ if (fp == curfile)
+ after_curfile = TRUE;
+ }
+
+ /*
+ * Since we cannot change the height/width of the [X]dialog(1) widget
+ * after spawn, to make things look nice let's pad the height so that
+ * the `-a text' always appears in the same spot.
+ *
+ * NOTE: fheight is calculated in dprompt_init(). It represents the
+ * maximum height required to display the set of items (broken up into
+ * pieces of display_limit chunks) whose names contain the most
+ * newlines for any given set.
+ */
+ while (nlines < fheight) {
+ dprompt_add("\n");
+ nlines++;
+ }
+
+ return (nthfile);
+}
+
+/*
+ * Process the dpv_file_node linked-list of named files, re-generating the
+ * [X]dialog(1) `--gauge' prompt text for the current state of transfers.
+ */
+void
+dprompt_recreate(struct dpv_file_node *file_list,
+ struct dpv_file_node *curfile, int pct)
+{
+ size_t len;
+
+ /*
+ * Re-Build the prompt text
+ */
+ dprompt_clear();
+ if (display_limit > 0)
+ dprompt_add_files(file_list, curfile, pct);
+
+ /* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
+ if (use_xdialog) {
+ /* Replace `\n' with `\n\\n\n' in dprompt */
+ len = strlen(dprompt);
+ len += strcount(dprompt, "\\n") * 5; /* +5 chars per count */
+ if (len > PROMPT_MAX)
+ errx(EXIT_FAILURE, "%s: Oops, dprompt buffer overflow "
+ "(%zu > %i)", __func__, len, PROMPT_MAX);
+ if (replaceall(dprompt, "\\n", "\n\\n\n") < 0)
+ err(EXIT_FAILURE, "%s: replaceall()", __func__);
+ }
+ else if (use_libdialog)
+ strexpandnl(dprompt);
+}
+
+/*
+ * Print the [X]dialog(1) `--gauge' prompt text to a buffer.
+ */
+int
+dprompt_sprint(char * restrict str, const char *prefix, const char *append)
+{
+
+ return (snprintf(str, PROMPT_MAX, "%s%s%s%s", use_color ? "\\Zn" : "",
+ prefix ? prefix : "", dprompt, append ? append : ""));
+}
+
+/*
+ * Print the [X]dialog(1) `--gauge' prompt text to file descriptor fd (could
+ * be STDOUT_FILENO or a pipe(2) file descriptor to actual [X]dialog(1)).
+ */
+void
+dprompt_dprint(int fd, const char *prefix, const char *append, int overall)
+{
+ int percent = gauge_percent;
+
+ if (overall >= 0 && overall <= 100)
+ gauge_percent = percent = overall;
+ dprintf(fd, "XXX\n%s%s%s%s\nXXX\n%i\n", use_color ? "\\Zn" : "",
+ prefix ? prefix : "", dprompt, append ? append : "", percent);
+ fsync(fd);
+}
+
+/*
+ * Print the dialog(3) `gauge' prompt text using libdialog.
+ */
+void
+dprompt_libprint(const char *prefix, const char *append, int overall)
+{
+ int percent = gauge_percent;
+ char buf[DPV_PPROMPT_MAX + DPV_APROMPT_MAX + DPV_DISPLAY_LIMIT * 1024];
+
+ dprompt_sprint(buf, prefix, append);
+
+ if (overall >= 0 && overall <= 100)
+ gauge_percent = percent = overall;
+ gauge = dlg_reallocate_gauge(gauge, title == NULL ? "" : title,
+ buf, dheight, dwidth, percent);
+ dlg_update_gauge(gauge, percent);
+}
+
+/*
+ * Free allocated items initialized by dprompt_init()
+ */
+void
+dprompt_free(void)
+{
+ if ((dprompt_free_mask & FM_DONE) != 0) {
+ dprompt_free_mask ^= FM_DONE;
+ free(done);
+ done = NULL;
+ }
+ if ((dprompt_free_mask & FM_FAIL) != 0) {
+ dprompt_free_mask ^= FM_FAIL;
+ free(fail);
+ fail = NULL;
+ }
+ if ((dprompt_free_mask & FM_PEND) != 0) {
+ dprompt_free_mask ^= FM_PEND;
+ free(pend);
+ pend = NULL;
+ }
+}
diff --git a/lib/libdpv/dprompt.h b/lib/libdpv/dprompt.h
new file mode 100644
index 0000000..a082364
--- /dev/null
+++ b/lib/libdpv/dprompt.h
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DPROMPT_H_
+#define _DPROMPT_H_
+
+#include <sys/cdefs.h>
+
+#include "dpv.h"
+
+/* Display characteristics */
+#define ENV_MSG_DONE "msg_done"
+#define ENV_MSG_FAIL "msg_fail"
+#define ENV_MSG_PENDING "msg_pending"
+extern int display_limit;
+extern int label_size;
+extern int pbar_size;
+
+__BEGIN_DECLS
+void dprompt_clear(void);
+void dprompt_dprint(int _fd, const char *_prefix, const char *_append,
+ int _overall);
+void dprompt_free(void);
+void dprompt_init(struct dpv_file_node *_file_list);
+void dprompt_libprint(const char *_prefix, const char *_append,
+ int _overall);
+void dprompt_recreate(struct dpv_file_node *_file_list,
+ struct dpv_file_node *_curfile, int _pct);
+int dprompt_add(const char *_format, ...);
+int dprompt_sprint(char * restrict _str, const char *_prefix,
+ const char *_append);
+__END_DECLS
+
+#endif /* !_DPROMPT_H_ */
diff --git a/lib/libdpv/dpv.3 b/lib/libdpv/dpv.3
new file mode 100644
index 0000000..8c04ac3
--- /dev/null
+++ b/lib/libdpv/dpv.3
@@ -0,0 +1,510 @@
+.\" Copyright (c) 2013-2014 Devin Teske
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (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 Oct 24, 2014
+.Dt DPV 3
+.Os
+.Sh NAME
+.Nm dpv
+.Nd dialog progress view library
+.Sh LIBRARY
+.Lb libdpv
+.Sh SYNOPSIS
+.In dpv.h
+.Ft int
+.Fo dpv
+.Fa "struct dpv_config *config, struct dpv_file_node *file_list"
+.Fc
+.Ft void
+.Fo dpv_free
+.Fa "void"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm
+library provides an interface for creating complex
+.Dq gauge
+widgets for displaying progress on various actions.
+The
+.Nm
+library can display progress with one of
+.Xr dialog 3 ,
+.Xr dialog 1 ,
+or
+.Xr Xdialog 1
+.Pq x11/xdialog from the ports tree .
+.Pp
+The
+.Fn dpv
+.Fa config
+argument contains the following properties for configuring global display
+features:
+.Bd -literal -offset indent
+struct dpv_config {
+ enum dpv_display display_type; /* Def. DPV_DISPLAY_LIBDIALOG */
+ enum dpv_output output_type; /* Default DPV_OUTPUT_NONE */
+ int debug; /* Enable debug on stderr */
+ int display_limit; /* Files/page. Default -1 */
+ int label_size; /* Label size. Default 28 */
+ int pbar_size; /* Mini-progress size */
+ int dialog_updates_per_second; /* Default 16 */
+ int status_updates_per_second; /* Default 2 */
+ uint16_t options; /* Default 0 (none) */
+ char *title; /* Widget title */
+ char *backtitle; /* Widget backtitle */
+ char *aprompt; /* Append. Default NULL */
+ char *pprompt; /* Prefix. Default NULL */
+ char *msg_done; /* Default `Done' */
+ char *msg_fail; /* Default `Fail' */
+ char *msg_pending; /* Default `Pending' */
+ char *output; /* Output format string */
+ const char *status_solo; /* dialog(3) solo-status format.
+ * Default DPV_STATUS_SOLO */
+ const char *status_many; /* dialog(3) many-status format.
+ * Default DPV_STATUS_MANY */
+
+ /*
+ * Function pointer; action to perform data transfer
+ */
+ int (*action)(struct dpv_file_node *file, int out);
+};
+
+enum dpv_display {
+ DPV_DISPLAY_LIBDIALOG = 0, /* Use dialog(3) (default) */
+ DPV_DISPLAY_STDOUT, /* Use stdout */
+ DPV_DISPLAY_DIALOG, /* Use spawned dialog(1) */
+ DPV_DISPLAY_XDIALOG, /* Use spawned Xdialog(1) */
+};
+
+enum dpv_output {
+ DPV_OUTPUT_NONE = 0, /* No output (default) */
+ DPV_OUTPUT_FILE, /* Read `output' member as file path */
+ DPV_OUTPUT_SHELL, /* Read `output' member as shell cmd */
+};
+.Ed
+.Pp
+The
+.Va options
+member of the
+.Fn dpv
+.Fa config
+argument is a mask of bit fields indicating various processing options.
+Possible flags are as follows:
+.Bl -tag -width DPV_NO_OVERRUN
+.It Dv DPV_TEST_MODE
+Enable test mode.
+In test mode, the
+.Fn action
+callback of the
+.Fa config
+argument is not called but instead simulated-data is used to drive progress.
+Appends
+.Dq [TEST MODE]
+to the status line
+.Po
+to override, set the
+.Va status_format
+member of the
+.Fn dpv
+.Fa config
+argument;
+e.g., to
+.Dv DPV_STATUS_DEFAULT
+.Pc .
+.It Dv DPV_WIDE_MODE
+Enable wide mode.
+In wide mode, the length of the
+.Va aprompt
+and
+.Va pprompt
+members of the
+.Fn dpv
+.Fa config
+argument will bump the width of the gauge widget.
+Prompts wider than the maximum width will wrap
+.Po
+unless using
+.Xr Xdialog 1 ;
+see BUGS section below
+.Pc .
+.It Dv DPV_NO_LABELS
+Disables the display of labels associated with each transfer
+.Po
+.Va label_size
+member of
+.Fn dpv
+.Fa config
+argument is ignored
+.Pc .
+.It Dv DPV_USE_COLOR
+Force the use of color even if the
+.Va display_type
+does not support color
+.Po
+.Ev USE_COLOR
+environment variable is ignored
+.Pc .
+.It Dv DPV_NO_OVERRUN
+When enabled, callbacks for the current
+.Vt dpv_file_node
+are terminated when
+.Fn action
+returns 100 or greater
+.Po
+alleviates the need to change the
+.Va status
+of the current
+.Vt dpv_file_node
+but may also cause file truncation if the stream exceeds expected length
+.Pc .
+.El
+.Pp
+The
+.Fa file_list
+argument to
+.Fn dpv
+is a pointer to a
+.Dq linked-list ,
+described as follows in
+.In dpv.h :
+.Bd -literal -offset indent
+struct dpv_file_node {
+ enum dpv_status status; /* status of read operation */
+ char *msg; /* display instead of "Done/Fail" */
+ char *name; /* name of file to read */
+ char *path; /* path to file */
+ long long length; /* expected size */
+ long long read; /* number units read (e.g., bytes) */
+ struct dpv_file_node *next;/* pointer to next (end with NULL) */
+};
+.Ed
+.Pp
+For each of the items in the
+.Fa file_list
+.Dq linked-list
+argument, the
+.Fn action
+callback member of the
+.Fn dpv
+.Fa config
+argument is called.
+The
+.Fn action
+function should perform a
+.Dq nominal
+action on the file and return.
+The return value of
+.Vt int
+represents the current progress percentage
+.Pq 0-100
+for the current file.
+.Pp
+The
+.Fn action
+callback provides two variables for each call.
+.Fa file
+provides a reference to the current
+.Vt dpv_file_node
+being processed.
+.Fa out
+provides a file descriptor where the data should go.
+.Pp
+If the
+.Va output
+member of the
+.Fn dpv
+.Fa config
+argument was set to DPV_OUTPUT_NONE
+.Pq default ; when invoking Fn dpv ,
+the
+.Fa out
+file descriptor of
+.Fn action
+will be zero and should be ignored.
+If
+.Fa output
+was set to DPV_OUTPUT_FILE,
+.Fa out
+will be an open file descriptor to a file.
+If
+.Fa output
+was set to DPV_OUTPUT_SHELL,
+.Fa out
+will be an open file descriptor to a pipe for a spawned shell program.
+When
+.Fa out
+is greater than zero, you should write any data you have read back to
+.Fa out .
+.Pp
+To abort
+.Fn dpv ,
+either from the
+.Fn action
+callback or asynchronously from a signal handler, two globals are provided via
+.In dpv.h :
+.Bd -literal -offset indent
+extern int dpv_interrupt; /* Set to TRUE in interrupt handler */
+extern int dpv_abort; /* Set to true in callback to abort */
+.Ed
+.Pp
+These globals are not automatically reset and must be manually maintained.
+Don't forget to reset these globals before subsequent invocations of
+.Fn dpv
+when making multiple calls from the same program.
+.Pp
+In addition, the
+.Va status
+member of the
+.Fn action
+.Fa file
+argument can be used to control callbacks for the current file.
+The
+.Va status
+member can be set to any of the following from
+.In dpv.h :
+.Bd -literal -offset indent
+enum dpv_status {
+ DPV_STATUS_RUNNING = 0, /* Running (default) */
+ DPV_STATUS_DONE, /* Completed */
+ DPV_STATUS_FAILED, /* Oops, something went wrong */
+};
+.Ed
+.Pp
+The default
+.Fa status
+is zero, DPV_STATUS_RUNING, which keeps the callbacks coming for the current
+.Fn file .
+Setting
+.Ql file->status
+to anything other than DPV_STATUS_RUNNING will cause
+.Fn dpv
+to loop to the next file, effecting the next callback, if any.
+.Pp
+The
+.Fn action
+callback is responsible for calculating percentages and
+.Pq recommended
+maintaining a
+.Nm
+global counter so
+.Fn dpv
+can display throughput statistics.
+Percentages are reported through the
+.Vt int
+return value of the
+.Fn action
+callback.
+Throughput statistics are calculated from the following global
+.Vt int
+in
+.In dpv.h :
+.Bd -literal -offset indent
+extern int dpv_overall_read;
+.Ed
+.Pp
+This should be set to the number of bytes that have been read for all files.
+Throughput information is displayed in the status line
+.Pq only available when using Xr dialog 3
+at the bottom of the screen.
+See DPV_DISPLAY_LIBDIALOG above.
+.Pp
+Note that
+.Va dpv_overall_read
+does not have to represent bytes.
+For example, you can change the
+.Va status_format
+to display something other than
+.Dq Li bytes
+and increment
+.Va dpv_overall_read
+accordingly
+.Pq e.g., counting lines .
+.Pp
+When
+.Fn dpv
+is processing the current file, the
+.Va length
+and
+.Va read
+members of the
+.Fn action
+.Fa file
+argument are used for calculating the display of mini progress bars
+.Po
+if enabled; see
+.Va pbar_size
+above
+.Pc .
+If the
+.Va length
+member of the current
+.Fa file
+is less than zero
+.Pq indicating an unknown file length ,
+a
+.Xr humanize_number 3
+version of the
+.Va read
+member is used instead of a traditional progress bar.
+Otherwise a progress bar is calculated as percentage read to file length.
+.Fn action
+callback must maintain these member values for mini-progress bars.
+.Pp
+The
+.Fn dpv_free
+function performs
+.Xr free 3
+on private global variables initialized by
+.Fn dpv .
+.Sh ENVIRONMENT
+The following environment variables are referenced by
+.Nm :
+.Bl -tag -width ".Ev USE_COLOR"
+.It Ev DIALOG
+Override command string used to launch
+.Xr dialog 1
+.Pq requires Dv DPV_DISPLAY_DIALOG
+or
+.Xr Xdialog 1
+.Pq requires Dv DPV_DISPLAY_XDIALOG ;
+default is either
+.Ql dialog
+.Pq for Dv DPV_DISPLAY_DIALOG
+or
+.Ql Xdialog
+.Pq for Dv DPV_DISPLAY_XDIALOG .
+.It Ev DIALOGRC
+If set and non-NULL, path to
+.Ql .dialogrc
+file.
+.It Ev HOME
+If
+.Ql Ev $DIALOGRC
+is either not set or NULL, used as a prefix to
+.Ql .dialogrc
+.Pq i.e., Ql $HOME/.dialogrc .
+.It Ev USE_COLOR
+If set and NULL, disables the use of color when using
+.Xr dialog 1
+.Pq does not apply to Xr Xdialog 1 .
+.It Ev msg_done Ev msg_fail Ev msg_pending
+Internationalization strings for overriding the default English strings
+.Ql Done ,
+.Ql Fail ,
+and
+.Ql Pending
+respectively.
+To prevent their usage, explicitly set the
+.Va msg_done ,
+.Va msg_fail ,
+and
+.Va msg_pending
+members of
+.Fn dpv
+.Fa config
+argument to default macros
+.Pq DPV_DONE_DEFAULT, DPV_FAIL_DEFAULT, and DPV_PENDING_DEFAULT
+or desired values.
+.El
+.Sh FILES
+.Bl -tag -width ".Pa $HOME/.dialogrc" -compact
+.It Pa $HOME/.dialogrc
+.El
+.Sh SEE ALSO
+.Xr dialog 1 ,
+.Xr dialog 3 ,
+.Xr Xdialog 1
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An Devin Teske Aq dteske@FreeBSD.org
+.Sh BUGS
+.Xr Xdialog 1 ,
+when given both
+.Ql Fl -title Ar title
+.Po
+see above
+.Ql Va title
+member of
+.Va struct dpv_config
+.Pc
+and
+.Ql Fl -backtitle Ar backtitle
+.Po
+see above
+.Ql Va backtitle
+member of
+.Va struct dpv_config
+.Pc ,
+displays the backtitle in place of the title and vice-versa.
+.Pp
+.Xr Xdialog 1
+does not wrap long prompt texts received after initial launch.
+This is a known issue with the
+.Ql --gauge
+widget in
+.Xr Xdialog 1 .
+Embed escaped newlines within prompt text(s) to force line breaks.
+.Pp
+.Xr dialog 1
+does not display the first character after a series of escaped escape-sequences
+(e.g., ``\\\\n'' produces ``\\'' instead of ``\\n'').
+This is a known issue with
+.Xr dialog 1
+and does not affect
+.Xr dialog 3
+or
+.Xr Xdialog 1 .
+.Pp
+If your application ignores
+.Ev USE_COLOR
+when set and NULL before calling
+.Xr dpv 3
+with color escape sequences anyway,
+.Xr dialog 3
+and
+.Xr dialog 1
+may not render properly.
+Workaround is to detect when
+.Ev USE_COLOR
+is set and NULL and either not use color escape sequences at that time or use
+.Xr unsetenv 3
+to unset
+.Ev USE_COLOR ,
+forcing interpretation of color sequences.
+This does not effect
+.Xr Xdialog 1 ,
+which renders the color escape sequences as plain text.
+See
+.Do Li
+embedded "\\Z" sequences
+.Dc
+in
+.Xr dialog 1
+for additional information.
diff --git a/lib/libdpv/dpv.c b/lib/libdpv/dpv.c
new file mode 100644
index 0000000..fd44360
--- /dev/null
+++ b/lib/libdpv/dpv.c
@@ -0,0 +1,721 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <ctype.h>
+#include <dialog.h>
+#include <err.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <string_m.h>
+#include <unistd.h>
+
+#include "dialog_util.h"
+#include "dialogrc.h"
+#include "dprompt.h"
+#include "dpv.h"
+#include "dpv_private.h"
+#include "status.h"
+#include "util.h"
+
+/* Test Mechanics (Only used when dpv_config.options |= DPV_TEST_MODE) */
+#define INCREMENT 1 /* Increment % per-pass test-mode */
+#define XDIALOG_INCREMENT 15 /* different for slower Xdialog(1) */
+static uint8_t increment = INCREMENT;
+
+/* Debugging */
+uint8_t debug = FALSE;
+
+/* Data to process */
+int dpv_interrupt = FALSE;
+int dpv_abort = FALSE;
+unsigned int dpv_nfiles = 0;
+
+/* Data processing */
+long long dpv_overall_read = 0;
+static char pathbuf[PATH_MAX];
+
+/* Extra display information */
+uint8_t no_labels = FALSE; /* dpv_config.options & DPV_NO_LABELS */
+uint8_t wide = FALSE; /* dpv_config.options & DPV_WIDE_MODE */
+char *aprompt = NULL; /* dpv_config.aprompt */
+char *msg_done = NULL; /* dpv_config.msg_done */
+char *msg_fail = NULL; /* dpv_config.msg_fail */
+char *msg_pending = NULL; /* dpv_config.msg_pending */
+char *pprompt = NULL; /* dpv_config.pprompt */
+
+/* Status-Line format for when using dialog(3) */
+static const char *status_format_custom = NULL;
+static char status_format_default[DPV_STATUS_FORMAT_MAX];
+
+/*
+ * Takes a pointer to a dpv_config structure containing layout details and
+ * pointer to initial element in a linked-list of dpv_file_node structures,
+ * each presenting a file to process. Executes the `action' function passed-in
+ * as a member to the `config' structure argument.
+ */
+int
+dpv(struct dpv_config *config, struct dpv_file_node *file_list)
+{
+ char c;
+ uint8_t keep_going;
+ uint8_t nls = FALSE; /* See dialog_prompt_nlstate() */
+ uint8_t no_overrun = FALSE;
+ uint8_t pprompt_nls = FALSE; /* See dialog_prompt_nlstate() */
+ uint8_t shrink_label_size = FALSE;
+ mode_t mask;
+ uint16_t options;
+ char *cp;
+ char *fc;
+ char *last;
+ char *name;
+ char *output;
+ const char *status_fmt;
+ const char *path_fmt;
+ enum dpv_display display_type;
+ enum dpv_output output_type;
+ enum dpv_status status;
+ int (*action)(struct dpv_file_node *file, int out);
+ int backslash;
+ int dialog_last_update = 0;
+ int dialog_old_nthfile = 0;
+ int dialog_old_seconds = -1;
+ int dialog_out = STDOUT_FILENO;
+ int dialog_update_usec = 0;
+ int dialog_updates_per_second;
+ int files_left;
+ int max_cols;
+ int nthfile = 0;
+ int output_out;
+ int overall = 0;
+ int pct;
+ int res;
+ int seconds;
+ int status_last_update = 0;
+ int status_old_nthfile = 0;
+ int status_old_seconds = -1;
+ int status_update_usec = 0;
+ int status_updates_per_second;
+ pid_t output_pid;
+ pid_t pid;
+ size_t len;
+ struct dpv_file_node *curfile;
+ struct dpv_file_node *first_file;
+ struct dpv_file_node *list_head;
+ struct timeval now;
+ struct timeval start;
+ char init_prompt[PROMPT_MAX + 1] = "";
+
+ /* Initialize globals to default values */
+ aprompt = NULL;
+ pprompt = NULL;
+ options = 0;
+ action = NULL;
+ backtitle = NULL;
+ debug = FALSE;
+ dialog_test = FALSE;
+ dialog_updates_per_second = DIALOG_UPDATES_PER_SEC;
+ display_limit = DISPLAY_LIMIT_DEFAULT;
+ display_type = DPV_DISPLAY_LIBDIALOG;
+ label_size = LABEL_SIZE_DEFAULT;
+ msg_done = NULL;
+ msg_fail = NULL;
+ msg_pending = NULL;
+ no_labels = FALSE;
+ output = NULL;
+ output_type = DPV_OUTPUT_NONE;
+ pbar_size = PBAR_SIZE_DEFAULT;
+ status_format_custom = NULL;
+ status_updates_per_second = STATUS_UPDATES_PER_SEC;
+ title = NULL;
+ wide = FALSE;
+
+ /* Process config options (overriding defaults) */
+ if (config != NULL) {
+ if (config->aprompt != NULL) {
+ if (aprompt == NULL) {
+ aprompt = malloc(DPV_APROMPT_MAX);
+ if (aprompt == NULL)
+ return (-1);
+ }
+ snprintf(aprompt, DPV_APROMPT_MAX, "%s",
+ config->aprompt);
+ }
+ if (config->pprompt != NULL) {
+ if (pprompt == NULL) {
+ pprompt = malloc(DPV_PPROMPT_MAX + 2);
+ /* +2 is for implicit "\n" appended later */
+ if (pprompt == NULL)
+ return (-1);
+ }
+ snprintf(pprompt, DPV_APROMPT_MAX, "%s",
+ config->pprompt);
+ }
+
+ options = config->options;
+ action = config->action;
+ backtitle = config->backtitle;
+ debug = config->debug;
+ dialog_test = ((options & DPV_TEST_MODE) != 0);
+ dialog_updates_per_second = config->dialog_updates_per_second;
+ display_limit = config->display_limit;
+ display_type = config->display_type;
+ label_size = config->label_size;
+ msg_done = (char *)config->msg_done;
+ msg_fail = (char *)config->msg_fail;
+ msg_pending = (char *)config->msg_pending;
+ no_labels = ((options & DPV_NO_LABELS) != 0);
+ no_overrun = ((options & DPV_NO_OVERRUN) != 0);
+ output = config->output;
+ output_type = config->output_type;
+ pbar_size = config->pbar_size;
+ status_updates_per_second = config->status_updates_per_second;
+ title = config->title;
+ wide = ((options & DPV_WIDE_MODE) != 0);
+
+ /* Enforce some minimums (pedantic) */
+ if (display_limit < -1)
+ display_limit = -1;
+ if (label_size < -1)
+ label_size = -1;
+ if (pbar_size < -1)
+ pbar_size = -1;
+
+ /* For the mini-pbar, -1 means hide, zero is invalid unless
+ * only one file is given */
+ if (pbar_size == 0) {
+ if (file_list == NULL || file_list->next == NULL)
+ pbar_size = -1;
+ else
+ pbar_size = PBAR_SIZE_DEFAULT;
+ }
+
+ /* For the label, -1 means auto-size, zero is invalid unless
+ * specifically requested through the use of options flag */
+ if (label_size == 0 && no_labels == FALSE)
+ label_size = LABEL_SIZE_DEFAULT;
+
+ /* Status update should not be zero */
+ if (status_updates_per_second == 0)
+ status_updates_per_second = STATUS_UPDATES_PER_SEC;
+ } /* config != NULL */
+
+ /* Process the type of display we've been requested to produce */
+ switch (display_type) {
+ case DPV_DISPLAY_STDOUT:
+ debug = TRUE;
+ use_color = FALSE;
+ use_dialog = FALSE;
+ use_libdialog = FALSE;
+ use_xdialog = FALSE;
+ break;
+ case DPV_DISPLAY_DIALOG:
+ use_color = TRUE;
+ use_dialog = TRUE;
+ use_libdialog = FALSE;
+ use_xdialog = FALSE;
+ break;
+ case DPV_DISPLAY_XDIALOG:
+ snprintf(dialog, PATH_MAX, XDIALOG);
+ use_color = FALSE;
+ use_dialog = FALSE;
+ use_libdialog = FALSE;
+ use_xdialog = TRUE;
+ break;
+ default:
+ use_color = TRUE;
+ use_dialog = FALSE;
+ use_libdialog = TRUE;
+ use_xdialog = FALSE;
+ break;
+ } /* display_type */
+
+ /* Enforce additional minimums that require knowing our display type */
+ if (dialog_updates_per_second == 0)
+ dialog_updates_per_second = use_xdialog ?
+ XDIALOG_UPDATES_PER_SEC : DIALOG_UPDATES_PER_SEC;
+
+ /* Allow forceful override of use_color */
+ if (config != NULL && (config->options & DPV_USE_COLOR) != 0)
+ use_color = TRUE;
+
+ /* Count the number of files in provided list of dpv_file_node's */
+ if (use_dialog && pprompt != NULL && *pprompt != '\0')
+ pprompt_nls = dialog_prompt_nlstate(pprompt);
+
+ max_cols = dialog_maxcols();
+ if (label_size == -1)
+ shrink_label_size = TRUE;
+
+ /* Process file arguments */
+ for (curfile = file_list; curfile != NULL; curfile = curfile->next) {
+ dpv_nfiles++;
+
+ /* dialog(3) only expands literal newlines */
+ if (use_libdialog) strexpandnl(curfile->name);
+
+ /* Optionally calculate label size for file */
+ if (shrink_label_size) {
+ nls = FALSE;
+ name = curfile->name;
+ if (curfile == file_list)
+ nls = pprompt_nls;
+ last = (char *)dialog_prompt_lastline(name, nls);
+ if (use_dialog) {
+ c = *last;
+ *last = '\0';
+ nls = dialog_prompt_nlstate(name);
+ *last = c;
+ }
+ len = dialog_prompt_longestline(last, nls);
+ if ((int)len > (label_size - 3)) {
+ if (label_size > 0)
+ label_size += 3;
+ label_size = len;
+ /* Room for ellipsis (unless NULL) */
+ if (label_size > 0)
+ label_size += 3;
+ }
+
+ if (max_cols > 0 && label_size > (max_cols - pbar_size
+ - 9))
+ label_size = max_cols - pbar_size - 9;
+ }
+
+ if (debug)
+ warnx("label=[%s] path=[%s] size=%lli",
+ curfile->name, curfile->path, curfile->length);
+ } /* file_list */
+
+ /* Optionally process the contents of DIALOGRC (~/.dialogrc) */
+ if (use_dialog) {
+ res = parse_dialogrc();
+ if (debug && res == 0) {
+ warnx("Successfully read `%s' config file", DIALOGRC);
+ warnx("use_shadow = %i (Boolean)", use_shadow);
+ warnx("use_colors = %i (Boolean)", use_colors);
+ warnx("gauge_color=[%s] (FBH)", gauge_color);
+ }
+ } else if (use_libdialog) {
+ init_dialog(stdin, stdout);
+ use_shadow = dialog_state.use_shadow;
+ use_colors = dialog_state.use_colors;
+ gauge_color[0] = 48 + dlg_color_table[GAUGE_ATTR].fg;
+ gauge_color[1] = 48 + dlg_color_table[GAUGE_ATTR].bg;
+ gauge_color[2] = dlg_color_table[GAUGE_ATTR].hilite ?
+ 'b' : 'B';
+ gauge_color[3] = '\0';
+ end_dialog();
+ if (debug) {
+ warnx("Finished initializing dialog(3) library");
+ warnx("use_shadow = %i (Boolean)", use_shadow);
+ warnx("use_colors = %i (Boolean)", use_colors);
+ warnx("gauge_color=[%s] (FBH)", gauge_color);
+ }
+ }
+
+ /* Enable mini progress bar automatically for stdin streams if unable
+ * to calculate progress (missing `lines:' syntax). */
+ if (dpv_nfiles <= 1 && file_list != NULL && file_list->length < 0 &&
+ !dialog_test)
+ pbar_size = PBAR_SIZE_DEFAULT;
+
+ /* If $USE_COLOR is set and non-NULL enable color; otherwise disable */
+ if ((cp = getenv(ENV_USE_COLOR)) != 0)
+ use_color = *cp != '\0' ? 1 : 0;
+
+ /* Print error and return `-1' if not given at least one name */
+ if (dpv_nfiles == 0) {
+ warnx("%s: no labels provided", __func__);
+ return (-1);
+ } else if (debug)
+ warnx("%s: %u label%s provided", __func__, dpv_nfiles,
+ dpv_nfiles == 1 ? "" : "s");
+
+ /* If only one file and pbar size is zero, default to `-1' */
+ if (dpv_nfiles <= 1 && pbar_size == 0)
+ pbar_size = -1;
+
+ /* Print some debugging information */
+ if (debug) {
+ warnx("%s: %s(%i) max rows x cols = %i x %i",
+ __func__, use_xdialog ? XDIALOG : DIALOG,
+ use_libdialog ? 3 : 1, dialog_maxrows(),
+ dialog_maxcols());
+ }
+
+ /* Xdialog(1) updates a lot slower than dialog(1) */
+ if (dialog_test && use_xdialog)
+ increment = XDIALOG_INCREMENT;
+
+ /* Always add implicit newline to pprompt (when specified) */
+ if (pprompt != NULL && *pprompt != '\0') {
+ len = strlen(pprompt);
+ /*
+ * NOTE: pprompt = malloc(PPROMPT_MAX + 2)
+ * NOTE: (see getopt(2) section above for pprompt allocation)
+ */
+ pprompt[len++] = '\\';
+ pprompt[len++] = 'n';
+ pprompt[len++] = '\0';
+ }
+
+ /* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
+ if (use_xdialog && pprompt != NULL) {
+ /* Replace `\n' with `\n\\n\n' in pprompt */
+ len = strlen(pprompt);
+ len += strcount(pprompt, "\\n") * 2;
+ if (len > DPV_PPROMPT_MAX)
+ errx(EXIT_FAILURE, "%s: Oops, pprompt buffer overflow "
+ "(%zu > %i)", __func__, len, DPV_PPROMPT_MAX);
+ if (replaceall(pprompt, "\\n", "\n\\n\n") < 0)
+ err(EXIT_FAILURE, "%s: replaceall()", __func__);
+ }
+ /* libdialog requires literal newlines */
+ else if (use_libdialog && pprompt != NULL)
+ strexpandnl(pprompt);
+
+ /* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
+ if (use_xdialog && aprompt != NULL) {
+ /* Replace `\n' with `\n\\n\n' in aprompt */
+ len = strlen(aprompt);
+ len += strcount(aprompt, "\\n") * 2;
+ if (len > DPV_APROMPT_MAX)
+ errx(EXIT_FAILURE, "%s: Oops, aprompt buffer overflow "
+ " (%zu > %i)", __func__, len, DPV_APROMPT_MAX);
+ if (replaceall(aprompt, "\\n", "\n\\n\n") < 0)
+ err(EXIT_FAILURE, "%s: replaceall()", __func__);
+ }
+ /* libdialog requires literal newlines */
+ else if (use_libdialog && aprompt != NULL)
+ strexpandnl(aprompt);
+
+ /*
+ * Warn user about an obscure dialog(1) bug (neither Xdialog(1) nor
+ * libdialog are affected) in the `--gauge' widget. If the first non-
+ * whitespace letter of "{new_prompt}" in "XXX\n{new_prompt}\nXXX\n"
+ * is a number, the number can sometimes be mistaken for a percentage
+ * to the overall progressbar. Other nasty side-effects such as the
+ * entire prompt not displaying or displaying improperly are caused by
+ * this bug too.
+ *
+ * NOTE: When we can use color, we have a work-around... prefix the
+ * output with `\Zn' (used to terminate ANSI and reset to normal).
+ */
+ if (use_dialog && !use_color) {
+ backslash = 0;
+
+ /* First, check pprompt (falls through if NULL) */
+ fc = pprompt;
+ while (fc != NULL && *fc != '\0') {
+ if (*fc == '\n') /* leading literal newline OK */
+ break;
+ if (!isspace(*fc) && *fc != '\\' && backslash == 0)
+ break;
+ else if (backslash > 0 && *fc != 'n')
+ break;
+ else if (*fc == '\\') {
+ backslash++;
+ if (backslash > 2)
+ break; /* we're safe */
+ }
+ fc++;
+ }
+ /* First non-whitespace character that dialog(1) will see */
+ if (fc != NULL && *fc >= '0' && *fc <= '9')
+ warnx("%s: WARNING! text argument to `-p' begins with "
+ "a number (not recommended)", __func__);
+ else if (fc > pprompt)
+ warnx("%s: WARNING! text argument to `-p' begins with "
+ "whitespace (not recommended)", __func__);
+
+ /*
+ * If no pprompt or pprompt is all whitespace, check the first
+ * file name provided to make sure it is alright too.
+ */
+ if ((pprompt == NULL || *fc == '\0') && file_list != NULL) {
+ first_file = file_list;
+ fc = first_file->name;
+ while (fc != NULL && *fc != '\0' && isspace(*fc))
+ fc++;
+ /* First non-whitespace char that dialog(1) will see */
+ if (fc != NULL && *fc >= '0' && *fc <= '9')
+ warnx("%s: WARNING! File name `%s' begins "
+ "with a number (use `-p text' for safety)",
+ __func__, first_file->name);
+ }
+ }
+
+ dprompt_init(file_list);
+ /* Reads: label_size pbar_size pprompt aprompt dpv_nfiles */
+ /* Inits: dheight and dwidth */
+
+ if (!debug) {
+ /* Internally create the initial `--gauge' prompt text */
+ dprompt_recreate(file_list, (struct dpv_file_node *)NULL, 0);
+
+ /* Spawn [X]dialog(1) `--gauge', returning pipe descriptor */
+ if (use_libdialog) {
+ status_printf("");
+ dprompt_libprint(pprompt, aprompt, 0);
+ } else {
+ dprompt_sprint(init_prompt, pprompt, aprompt);
+ dialog_out = dialog_spawn_gauge(init_prompt, &pid);
+ dprompt_dprint(dialog_out, pprompt, aprompt, 0);
+ }
+ } /* !debug */
+
+ /* Seed the random(3) generator */
+ if (dialog_test)
+ srandom(0xf1eeface);
+
+ /* Set default/custom status line format */
+ if (dpv_nfiles > 1) {
+ snprintf(status_format_default, DPV_STATUS_FORMAT_MAX, "%s",
+ DPV_STATUS_MANY);
+ status_format_custom = config->status_many;
+ } else {
+ snprintf(status_format_default, DPV_STATUS_FORMAT_MAX, "%s",
+ DPV_STATUS_SOLO);
+ status_format_custom = config->status_solo;
+ }
+
+ /* Add test mode identifier to default status line if enabled */
+ if (dialog_test && (strlen(status_format_default) + 12) <
+ DPV_STATUS_FORMAT_MAX)
+ strcat(status_format_default, " [TEST MODE]");
+
+ /* Verify custom status format */
+ status_fmt = fmtcheck(status_format_custom, status_format_default);
+ if (status_format_custom != NULL &&
+ status_fmt == status_format_default) {
+ warnx("WARNING! Invalid status_format configuration `%s'",
+ status_format_custom);
+ warnx("Default status_format `%s'", status_format_default);
+ }
+
+ /* Record when we started (used to prevent updating too quickly) */
+ (void)gettimeofday(&start, (struct timezone *)NULL);
+
+ /* Calculate number of microseconds in-between sub-second updates */
+ if (status_updates_per_second != 0)
+ status_update_usec = 1000000 / status_updates_per_second;
+ if (dialog_updates_per_second != 0)
+ dialog_update_usec = 1000000 / dialog_updates_per_second;
+
+ /*
+ * Process the file list [serially] (one for each argument passed)
+ */
+ files_left = dpv_nfiles;
+ list_head = file_list;
+ for (curfile = file_list; curfile != NULL; curfile = curfile->next) {
+ keep_going = TRUE;
+ output_out = -1;
+ pct = 0;
+ nthfile++;
+ files_left--;
+
+ if (dpv_interrupt)
+ break;
+ if (dialog_test)
+ pct = 0 - increment;
+
+ /* Attempt to spawn output program for this file */
+ if (!dialog_test && output != NULL) {
+ mask = umask(0022);
+ (void)umask(mask);
+
+ switch (output_type) {
+ case DPV_OUTPUT_SHELL:
+ output_out = shell_spawn_pipecmd(output,
+ curfile->name, &output_pid);
+ break;
+ case DPV_OUTPUT_FILE:
+ path_fmt = fmtcheck(output, "%s");
+ if (path_fmt == output)
+ len = snprintf(pathbuf,
+ PATH_MAX, output, curfile->name);
+ else
+ len = snprintf(pathbuf,
+ PATH_MAX, "%s", output);
+ if (len >= PATH_MAX) {
+ warnx("%s:%d:%s: pathbuf[%u] too small"
+ "to hold output argument",
+ __FILE__, __LINE__, __func__,
+ PATH_MAX);
+ return (-1);
+ }
+ if ((output_out = open(pathbuf,
+ O_CREAT|O_WRONLY, DEFFILEMODE & ~mask))
+ < 0) {
+ warn("%s", pathbuf);
+ return (-1);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ while (!dpv_interrupt && keep_going) {
+ if (dialog_test) {
+ usleep(50000);
+ pct += increment;
+ dpv_overall_read +=
+ (int)(random() / 512 / dpv_nfiles);
+ /* 512 limits fake readout to Megabytes */
+ } else if (action != NULL)
+ pct = action(curfile, output_out);
+
+ if (no_overrun || dialog_test)
+ keep_going = (pct < 100);
+ else {
+ status = curfile->status;
+ keep_going = (status == DPV_STATUS_RUNNING);
+ }
+
+ /* Get current time and calculate seconds elapsed */
+ gettimeofday(&now, (struct timezone *)NULL);
+ now.tv_sec = now.tv_sec - start.tv_sec;
+ now.tv_usec = now.tv_usec - start.tv_usec;
+ if (now.tv_usec < 0)
+ now.tv_sec--, now.tv_usec += 1000000;
+ seconds = now.tv_sec + (now.tv_usec / 1000000.0);
+
+ /* Update dialog (be it dialog(3), dialog(1), etc.) */
+ if ((dialog_updates_per_second != 0 &&
+ (
+ seconds != dialog_old_seconds ||
+ now.tv_usec - dialog_last_update >=
+ dialog_update_usec ||
+ nthfile != dialog_old_nthfile
+ )) || pct == 100
+ ) {
+ /* Calculate overall progress (rounding up) */
+ overall = (100 * nthfile - 100 + pct) /
+ dpv_nfiles;
+ if (((100 * nthfile - 100 + pct) * 10 /
+ dpv_nfiles % 100) > 50)
+ overall++;
+
+ dprompt_recreate(list_head, curfile, pct);
+
+ if (use_libdialog && !debug) {
+ /* Update dialog(3) widget */
+ dprompt_libprint(pprompt, aprompt,
+ overall);
+ } else {
+ /* stdout, dialog(1), or Xdialog(1) */
+ dprompt_dprint(dialog_out, pprompt,
+ aprompt, overall);
+ fsync(dialog_out);
+ }
+ dialog_old_seconds = seconds;
+ dialog_old_nthfile = nthfile;
+ dialog_last_update = now.tv_usec;
+ }
+
+ /* Update the status line */
+ if ((use_libdialog && !debug) &&
+ status_updates_per_second != 0 &&
+ (
+ keep_going != TRUE ||
+ seconds != status_old_seconds ||
+ now.tv_usec - status_last_update >=
+ status_update_usec ||
+ nthfile != status_old_nthfile
+ )
+ ) {
+ status_printf(status_fmt, dpv_overall_read,
+ (dpv_overall_read / (seconds == 0 ? 1 :
+ seconds) * 1.0),
+ 1, /* XXX until we add parallelism XXX */
+ files_left);
+ status_old_seconds = seconds;
+ status_old_nthfile = nthfile;
+ status_last_update = now.tv_usec;
+ }
+ }
+
+ if (!dialog_test && output_out >= 0) {
+ close(output_out);
+ waitpid(output_pid, (int *)NULL, 0);
+ }
+
+ if (dpv_abort)
+ break;
+
+ /* Advance head of list when we hit the max display lines */
+ if (display_limit > 0 && nthfile % display_limit == 0)
+ list_head = curfile->next;
+ }
+
+ if (!debug) {
+ if (use_libdialog)
+ end_dialog();
+ else {
+ close(dialog_out);
+ waitpid(pid, (int *)NULL, 0);
+ }
+ if (!dpv_interrupt)
+ printf("\n");
+ } else
+ warnx("%s: %lli lines read", __func__, dpv_overall_read);
+
+ if (dpv_interrupt || dpv_abort)
+ return (-1);
+ else
+ return (0);
+}
+
+/*
+ * Free allocated items initialized by dpv()
+ */
+void
+dpv_free(void)
+{
+ dialogrc_free();
+ dprompt_free();
+ dialog_maxsize_free();
+ if (aprompt != NULL) {
+ free(aprompt);
+ aprompt = NULL;
+ }
+ if (pprompt != NULL) {
+ free(pprompt);
+ pprompt = NULL;
+ }
+ status_free();
+}
diff --git a/lib/libdpv/dpv.h b/lib/libdpv/dpv.h
new file mode 100644
index 0000000..dbcd59b
--- /dev/null
+++ b/lib/libdpv/dpv.h
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DPV_H_
+#define _DPV_H_
+
+#include <sys/types.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+/* Data to process */
+extern long long dpv_overall_read;
+
+/* Interrupt flag */
+extern int dpv_interrupt; /* Set to TRUE in interrupt handler */
+extern int dpv_abort; /* Set to true in callback to abort */
+
+/*
+ * Display types for use with display_type member of dpv_config structure
+ */
+enum dpv_display {
+ DPV_DISPLAY_LIBDIALOG = 0, /* Display using dialog(3) (default) */
+ DPV_DISPLAY_STDOUT, /* Display on stdout */
+ DPV_DISPLAY_DIALOG, /* Display using spawned dialog(1) */
+ DPV_DISPLAY_XDIALOG, /* Display using spawned Xdialog(1) */
+};
+
+/*
+ * Output types for use with output_type member of dpv_config structure
+ */
+enum dpv_output {
+ DPV_OUTPUT_NONE = 0, /* No output (default) */
+ DPV_OUTPUT_FILE, /* Read `output' member as file path */
+ DPV_OUTPUT_SHELL, /* Read `output' member as shell cmd */
+};
+
+/*
+ * Activity types for use with status member of dpv_file_node structure.
+ * If you set a status other than DPV_STATUS_RUNNING on the current file in the
+ * action callback of dpv_config structure, you'll end callbacks for that
+ * dpv_file_node.
+ */
+enum dpv_status {
+ DPV_STATUS_RUNNING = 0, /* Running (default) */
+ DPV_STATUS_DONE, /* Completed */
+ DPV_STATUS_FAILED, /* Oops, something went wrong */
+};
+
+/*
+ * Anatomy of file option; pass an array of these as dpv() file_list argument
+ * terminated with a NULL pointer.
+ */
+struct dpv_file_node {
+ enum dpv_status status; /* status of read operation */
+ char *msg; /* display instead of "Done/Fail" */
+ char *name; /* name of file to read */
+ char *path; /* path to file */
+ long long length; /* expected size */
+ long long read; /* number units read (e.g., bytes) */
+ struct dpv_file_node *next; /* pointer to next (end with NULL) */
+};
+
+/*
+ * Anatomy of config option to pass as dpv() config argument
+ */
+struct dpv_config {
+ enum dpv_display display_type; /* Display (default TYPE_LIBDIALOG) */
+ enum dpv_output output_type; /* Output (default TYPE_NONE) */
+ int debug; /* Enable debugging output on stderr */
+ int display_limit; /* Files per `page'. Default -1 */
+ int label_size; /* Label size. Default 28 */
+ int pbar_size; /* Mini-progress size. See dpv(3) */
+ int dialog_updates_per_second; /* Progress updates/s. Default 16 */
+ int status_updates_per_second; /* dialog(3) status updates/second.
+ * Default 2 */
+ uint16_t options; /* Special options. Default 0 */
+ char *title; /* widget title */
+ char *backtitle; /* Widget backtitle */
+ char *aprompt; /* Prompt append. Default NULL */
+ char *pprompt; /* Prompt prefix. Default NULL */
+ char *msg_done; /* Progress text. Default `Done' */
+ char *msg_fail; /* Progress text. Default `Fail' */
+ char *msg_pending; /* Progress text. Default `Pending' */
+ char *output; /* Output format string; see dpv(3) */
+ const char *status_solo; /* dialog(3) solo-status format.
+ * Default DPV_STATUS_SOLO */
+ const char *status_many; /* dialog(3) many-status format.
+ * Default DPV_STATUS_MANY */
+
+ /*
+ * Function pointer; action to perform data transfer
+ */
+ int (*action)(struct dpv_file_node *file, int out);
+};
+
+/*
+ * Macros for dpv() options bitmask argument
+ */
+#define DPV_TEST_MODE 0x0001 /* Test mode (fake reading data) */
+#define DPV_WIDE_MODE 0x0002 /* prefix/append bump dialog width */
+#define DPV_NO_LABELS 0x0004 /* Hide file_node.name labels */
+#define DPV_USE_COLOR 0x0008 /* Override to force color output */
+#define DPV_NO_OVERRUN 0x0010 /* Stop transfers when they hit 100% */
+
+/*
+ * Limits (modify with extreme care)
+ */
+#define DPV_APROMPT_MAX 4096 /* Buffer size for `-a text' */
+#define DPV_DISPLAY_LIMIT 10 /* Max file progress lines */
+#define DPV_PPROMPT_MAX 4096 /* Buffer size for `-p text' */
+#define DPV_STATUS_FORMAT_MAX 80 /* Buffer size for `-u format' */
+
+/*
+ * Extra display information
+ */
+#define DPV_STATUS_SOLO "%'10lli bytes read @ %'9.1f bytes/sec."
+#define DPV_STATUS_MANY (DPV_STATUS_SOLO " [%i/%i busy/wait]")
+
+/*
+ * Strings
+ */
+#define DPV_DONE_DEFAULT "Done"
+#define DPV_FAIL_DEFAULT "Fail"
+#define DPV_PENDING_DEFAULT "Pending"
+
+__BEGIN_DECLS
+void dpv_free(void);
+int dpv(struct dpv_config *_config, struct dpv_file_node *_file_list);
+__END_DECLS
+
+#endif /* !_DPV_H_ */
diff --git a/lib/libdpv/dpv_private.h b/lib/libdpv/dpv_private.h
new file mode 100644
index 0000000..5164eb3
--- /dev/null
+++ b/lib/libdpv/dpv_private.h
@@ -0,0 +1,66 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _DPV_PRIVATE_H_
+#define _DPV_PRIVATE_H_
+
+#include <sys/types.h>
+
+/* Debugging */
+extern uint8_t debug;
+
+/* Data to process */
+extern unsigned int dpv_nfiles;
+
+/* Extra display information */
+extern uint8_t no_labels;
+extern uint8_t wide;
+extern char *msg_done, *msg_fail, *msg_pending;
+extern char *pprompt, *aprompt;
+extern const char status_format[];
+
+/* Defaults */
+#define DIALOG_UPDATES_PER_SEC 16
+#define XDIALOG_UPDATES_PER_SEC 4
+#define DISPLAY_LIMIT_DEFAULT 0 /* Auto-calculate */
+#define LABEL_SIZE_DEFAULT 28
+#define PBAR_SIZE_DEFAULT 17
+#define STATUS_UPDATES_PER_SEC 2
+
+/* states for dprompt_add_files() of dprompt.c */
+enum dprompt_state {
+ DPROMPT_NONE = 0, /* Default */
+ DPROMPT_PENDING, /* Pending */
+ DPROMPT_PBAR, /* Progress bar */
+ DPROMPT_END_STATE, /* Done/Fail */
+ DPROMPT_DETAILS, /* dpv_file_node->read */
+ DPROMPT_CUSTOM_MSG, /* dpv_file_node->msg */
+ DPROMPT_MINIMAL, /* whitespace */
+};
+
+#endif /* !_DPV_PRIVATE_H_ */
diff --git a/lib/libdpv/status.c b/lib/libdpv/status.c
new file mode 100644
index 0000000..4bf4773
--- /dev/null
+++ b/lib/libdpv/status.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <curses.h>
+#include <dialog.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "dialog_util.h"
+#include "status.h"
+
+/* static globals */
+static char *status_buf = NULL;
+static int status_bufsize = -1;
+static int status_row;
+static int status_width;
+
+/*
+ * Print a `one-liner' status message at the bottom of the screen. Messages are
+ * trimmed to fit within the console length (ANSI coloring not accounted for).
+ */
+void
+status_printf(const char *fmt, ...)
+{
+ int n, attrs;
+ chtype color = dlg_color_pair(dlg_color_table[BUTTON_ACTIVE_ATTR].fg,
+ dlg_color_table[SCREEN_ATTR].bg) | A_BOLD;
+ va_list args;
+
+ status_row = tty_maxrows() - 1;
+ status_width = tty_maxcols();
+
+ /* NULL is a special convention meaning "erase the old stuff" */
+ if (fmt == NULL) {
+ move(status_row, 0);
+ clrtoeol();
+ return;
+ }
+
+ /* Resize buffer if terminal width is greater */
+ if ((status_width + 1) > status_bufsize) {
+ status_buf = realloc(status_buf, status_width + 1);
+ if (status_buf == NULL) {
+ status_bufsize = -1;
+ return;
+ }
+ status_bufsize = status_width + 1;
+ }
+
+ /* Print the message within a space-filled buffer */
+ memset(status_buf, ' ', status_width);
+ va_start(args, fmt);
+ n = vsnprintf(status_buf, status_width + 1, fmt, args);
+ va_end(args);
+
+ /* If vsnprintf(3) produced less bytes than the maximum, change the
+ * implicitly-added NUL-terminator into a space and terminate at max */
+ if (n < status_width) {
+ status_buf[n] = ' ';
+ status_buf[status_width] = '\0';
+ }
+
+ /* Print text in screen bg, button active fg, and bold */
+ attrs = getattrs(stdscr);
+ attrset(color);
+ mvaddstr(status_row, 0, status_buf);
+ attrset(attrs);
+
+ /* Seat the cursor over the last character at absolute lower-right */
+ move(status_row, status_width - 1);
+ refresh();
+}
+
+/*
+ * Free allocated items initialized by status_printf()
+ */
+void
+status_free(void)
+{
+ if (status_buf != NULL) {
+ free(status_buf);
+ status_buf = NULL;
+ }
+}
diff --git a/lib/libdpv/status.h b/lib/libdpv/status.h
new file mode 100644
index 0000000..002f7f1
--- /dev/null
+++ b/lib/libdpv/status.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _STATUS_H_
+#define _STATUS_H_
+
+#include <sys/cdefs.h>
+
+/* dialog(3) dlg_color_table[] attributes */
+#define SCREEN_ATTR 0 /* entry used for status line bg */
+#define BUTTON_ACTIVE_ATTR 5 /* entry used for status line fg */
+
+__BEGIN_DECLS
+void status_free(void);
+void status_printf(const char *_format, ...);
+__END_DECLS
+
+#endif /* !_STATUS_H_ */
diff --git a/lib/libdpv/util.c b/lib/libdpv/util.c
new file mode 100644
index 0000000..25fc1cb
--- /dev/null
+++ b/lib/libdpv/util.c
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <limits.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "util.h"
+
+extern char **environ;
+static char cmdbuf[CMDBUFMAX] = "";
+static char shellcmd[PATH_MAX] = PATH_SHELL;
+static char *shellcmd_argv[6] = {
+ shellcmd,
+ __DECONST(char *, "-c"),
+ cmdbuf,
+ __DECONST(char *, "--"),
+ shellcmd,
+ NULL,
+};
+
+/*
+ * Spawn a sh(1) command. Writes the resulting process ID to the pid_t pointed
+ * at by `pid'. Returns a file descriptor (int) suitable for writing data to
+ * the spawned command (data written to file descriptor is seen as standard-in
+ * by the spawned sh(1) command). Returns `-1' if unable to spawn command.
+ *
+ * If cmd contains a single "%s" sequence, replace it with label if non-NULL.
+ */
+int
+shell_spawn_pipecmd(const char *cmd, const char *label, pid_t *pid)
+{
+ int error;
+ int len;
+ posix_spawn_file_actions_t action;
+#if SHELL_SPAWN_DEBUG
+ unsigned int i;
+#endif
+ int stdin_pipe[2] = { -1, -1 };
+
+ /* Populate argument array */
+ if (label != NULL && fmtcheck(cmd, "%s") == cmd)
+ len = snprintf(cmdbuf, CMDBUFMAX, cmd, label);
+ else
+ len = snprintf(cmdbuf, CMDBUFMAX, "%s", cmd);
+ if (len >= CMDBUFMAX) {
+ warnx("%s:%d:%s: cmdbuf[%u] too small to hold cmd argument",
+ __FILE__, __LINE__, __func__, CMDBUFMAX);
+ return (-1);
+ }
+
+ /* Open a pipe to communicate with [X]dialog(1) */
+ if (pipe(stdin_pipe) < 0)
+ err(EXIT_FAILURE, "%s: pipe(2)", __func__);
+
+ /* Fork sh(1) process */
+#if SHELL_SPAWN_DEBUG
+ fprintf(stderr, "%s: spawning `", __func__);
+ for (i = 0; shellcmd_argv[i] != NULL; i++) {
+ if (i == 0)
+ fprintf(stderr, "%s", shellcmd_argv[i]);
+ else if (i == 2)
+ fprintf(stderr, " '%s'", shellcmd_argv[i]);
+ else
+ fprintf(stderr, " %s", shellcmd_argv[i]);
+ }
+ fprintf(stderr, "'\n");
+#endif
+ posix_spawn_file_actions_init(&action);
+ posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
+ posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
+ error = posix_spawnp(pid, shellcmd, &action,
+ (const posix_spawnattr_t *)NULL, shellcmd_argv, environ);
+ if (error != 0)
+ err(EXIT_FAILURE, "%s: posix_spawnp(3)", __func__);
+
+ return stdin_pipe[1];
+}
diff --git a/lib/libproc/test/t2-name2map/t2-name2map.c b/lib/libdpv/util.h
index 825963d..7bb3b18 100644
--- a/lib/libproc/test/t2-name2map/t2-name2map.c
+++ b/lib/libdpv/util.h
@@ -1,46 +1,50 @@
-/*
- * Copyright (c) 2010 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Rui Paulo under sponsorship from the
- * FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
+/*-
+ * Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
*
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
*/
+#ifndef _UTIL_H_
+#define _UTIL_H_
+
#include <sys/types.h>
-#include <assert.h>
-#include <stdio.h>
-#include <libproc.h>
-
-int
-main(int argc, char *argv[])
-{
- prmap_t *map = NULL;
- struct proc_handle *phdl;
-
- proc_create("./t2-name2map", argv, NULL, NULL, &phdl);
- map = proc_name2map(phdl, "ld-elf.so.1");
- assert(map);
-}
+
+#include <paths.h>
+
+#define SHELL_SPAWN_DEBUG 0 /* Debug spawning of sh(1) commands */
+
+#ifdef _PATH_BSHELL
+#define PATH_SHELL _PATH_BSHELL
+#else
+#define PATH_SHELL "/bin/sh"
+#endif
+
+#define CMDBUFMAX 4096
+
+__BEGIN_DECLS
+int shell_spawn_pipecmd(const char *_cmd, const char *_label, pid_t *_pid);
+__END_DECLS
+
+#endif /* !_UTIL_H_ */
diff --git a/lib/libevent/Makefile b/lib/libevent/Makefile
new file mode 100644
index 0000000..d8b1e20
--- /dev/null
+++ b/lib/libevent/Makefile
@@ -0,0 +1,31 @@
+# $FreeBSD$
+
+.PATH: ${.CURDIR}/../../contrib/pf/libevent
+
+.include <src.opts.mk>
+
+LIB= event
+SHLIB_MAJOR= 1
+PRIVATELIB=
+INTERNALLIB=
+
+SRCS= buffer.c evbuffer.c event.c kqueue.c log.c poll.c select.c signal.c
+HDRS= event.h
+
+CFLAGS+= -I${.CURDIR} \
+ -DHAVE_CLOCK_GETTIME \
+ -DHAVE_FCNTL_H \
+ -DHAVE_POLL \
+ -DHAVE_SELECT \
+ -DHAVE_SETFD \
+ -DHAVE_STDARG_H \
+ -DHAVE_SYS_IOCTL_H \
+ -DHAVE_SYS_TIME_H \
+ -DHAVE_UNISTD_H \
+ -DHAVE_VASPRINTF \
+ -DHAVE_WORKING_KQUEUE \
+ -DVERSION='"1.3b"'
+
+WARNS?= 2
+
+.include <bsd.lib.mk>
diff --git a/lib/libexpat/Makefile b/lib/libexpat/Makefile
index 9b641c1..523a74e 100644
--- a/lib/libexpat/Makefile
+++ b/lib/libexpat/Makefile
@@ -16,12 +16,10 @@ CLEANFILES= bsdxml.h bsdxml_external.h
WARNS?= 2
-# OK, so it is not entirely unadultered: we ammend the COPYING
-# to point people to the right place, get rid of some VMS stuff
-# and use FreeBSD style indempotency #ifndefs. We also want to
-# point it at the new bsdxml_external.h rather than the old
-# expat_external.h file.
-#
+# OK, so it is not entirely unadulterated: we amend the COPYING to
+# point people to the right place, get rid of some VMS stuff and use
+# FreeBSD-style include guards. We also want to point it at the new
+# bsdxml_external.h rather than the old expat_external.h file.
bsdxml.h: expat.h
unifdef -U__VMS < ${.ALLSRC} | \
sed -e 's/XmlParse_INCLUDED/_BSD_XML_H_/' \
diff --git a/lib/libfetch/common.c b/lib/libfetch/common.c
index a6fc47c..eabea2b 100644
--- a/lib/libfetch/common.c
+++ b/lib/libfetch/common.c
@@ -675,10 +675,14 @@ fetch_ssl_setup_transport_layer(SSL_CTX *ctx, int verbose)
ssl_ctx_options = SSL_OP_ALL | SSL_OP_NO_TICKET;
if (getenv("SSL_ALLOW_SSL2") == NULL)
ssl_ctx_options |= SSL_OP_NO_SSLv2;
- if (getenv("SSL_NO_SSL3") != NULL)
+ if (getenv("SSL_ALLOW_SSL3") == NULL)
ssl_ctx_options |= SSL_OP_NO_SSLv3;
if (getenv("SSL_NO_TLS1") != NULL)
ssl_ctx_options |= SSL_OP_NO_TLSv1;
+ if (getenv("SSL_NO_TLS1_1") != NULL)
+ ssl_ctx_options |= SSL_OP_NO_TLSv1_1;
+ if (getenv("SSL_NO_TLS1_2") != NULL)
+ ssl_ctx_options |= SSL_OP_NO_TLSv1_2;
if (verbose)
fetch_info("SSL options: %lx", ssl_ctx_options);
SSL_CTX_set_options(ctx, ssl_ctx_options);
@@ -873,8 +877,8 @@ fetch_ssl(conn_t *conn, const struct url *URL, int verbose)
}
if (verbose) {
- fetch_info("SSL connection established using %s",
- SSL_get_cipher(conn->ssl));
+ fetch_info("%s connection established using %s",
+ SSL_get_version(conn->ssl), SSL_get_cipher(conn->ssl));
name = X509_get_subject_name(conn->ssl_cert);
str = X509_NAME_oneline(name, 0, 0);
fetch_info("Certificate subject: %s", str);
diff --git a/lib/libfetch/fetch.3 b/lib/libfetch/fetch.3
index 57ecea5..5b9f0db 100644
--- a/lib/libfetch/fetch.3
+++ b/lib/libfetch/fetch.3
@@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd July 30, 2013
+.Dd October 15, 2014
.Dt FETCH 3
.Os
.Sh NAME
@@ -438,15 +438,17 @@ input (see
.Pp
By default
.Nm libfetch
-allows SSLv3 and TLSv1 when negotiating the connecting with the remote
+allows TLSv1 and newer when negotiating the connecting with the remote
peer.
-You can change this behavior by setting the environment variable
+You can change this behavior by setting the
.Ev SSL_ALLOW_SSL2
-to allow SSLv2 (not recommended) and
-.Ev SSL_NO_SSL3
-or
-.Ev SSL_NO_TLS1
-to disable the respective methods.
+and
+.Ev SSL_ALLOW_SSL3
+environment variables to allow SSLv2 and SSLv3, respectively, and
+.Ev SSL_NO_TLS1 ,
+.Ev SSL_NO_TLS1_1 and
+.Ev SSL_NO_TLS1_2
+to disable TLS 1.0, 1.1 and 1.2 respectively.
.Sh AUTHENTICATION
Apart from setting the appropriate environment variables and
specifying the user name and password in the URL or the
@@ -646,6 +648,8 @@ Same as
for compatibility.
.It Ev SSL_ALLOW_SSL2
Allow SSL version 2 when negotiating the connection (not recommended).
+.It Ev SSL_ALLOW_SSL3
+Allow SSL version 3 when negotiating the connection (not recommended).
.It Ev SSL_CA_CERT_FILE
CA certificate bundle containing trusted CA certificates.
Default value:
@@ -660,10 +664,12 @@ PEM encoded client key in case key and client certificate
are stored separately.
.It Ev SSL_CRL_FILE
File containing certificate revocation list.
-.It Ev SSL_NO_SSL3
-Don't allow SSL version 3 when negotiating the connection.
.It Ev SSL_NO_TLS1
-Don't allow TLV version 1 when negotiating the connection.
+Do not allow TLS version 1.0 when negotiating the connection.
+.It Ev SSL_NO_TLS1_1
+Do not allow TLS version 1.1 when negotiating the connection.
+.It Ev SSL_NO_TLS1_2
+Do not allow TLS version 1.2 when negotiating the connection.
.It Ev SSL_NO_VERIFY_HOSTNAME
If set, do not verify that the hostname matches the subject of the
certificate presented by the server.
diff --git a/lib/libfigpar/Makefile b/lib/libfigpar/Makefile
new file mode 100644
index 0000000..6f01966
--- /dev/null
+++ b/lib/libfigpar/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+LIB= figpar
+SHLIB_MAJOR= 0
+INCS= figpar.h string_m.h
+MAN= figpar.3
+MLINKS= figpar.3 get_config_option.3 \
+ figpar.3 parse_config.3 \
+ figpar.3 replaceall.3 \
+ figpar.3 strcount.3 \
+ figpar.3 strexpand.3 \
+ figpar.3 strexpandnl.3 \
+ figpar.3 strtolower.3
+
+CFLAGS+= -I${.CURDIR}
+
+SRCS= figpar.c string_m.c
+
+WARNS?= 6
+
+.include <bsd.lib.mk>
diff --git a/lib/libfigpar/figpar.3 b/lib/libfigpar/figpar.3
new file mode 100644
index 0000000..549808e
--- /dev/null
+++ b/lib/libfigpar/figpar.3
@@ -0,0 +1,251 @@
+.\" Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd Oct 24, 2014
+.Dt FIGPAR 3
+.Os
+.Sh NAME
+.Nm figpar ,
+.Nm parse_config ,
+.Nm get_config_option
+.Nd configuration file parsing library
+.Sh LIBRARY
+.Lb libfigpar
+.Sh SYNOPSIS
+.In figpar.h
+.Ft int
+.Fo parse_config
+.Fa "struct fp_config options[], const char *path"
+.Fa "int \*[lp]*unknown\*[rp]\*[lp]struct fp_config *option, uint32_t line"
+.Fa "char *directive, char *value\*[rp], uint8_t processing_options"
+.Fc
+.Ft "struct fp_config *"
+.Fo get_config_option
+.Fa "struct fp_config options[], const char *directive"
+.Fc
+.In string_m.h
+.Ft int
+.Fo replaceall
+.Fa "char *source, const char *find, const char *replace"
+.Fc
+.Ft unsigned int
+.Fo strcount
+.Fa "const char *source, const char *find"
+.Fc
+.Ft void
+.Fo strexpand
+.Fa "char *source"
+.Fc
+.Ft void
+.Fo strexpandnl
+.Fa "char *source"
+.Fc
+.Ft void
+.Fo strtolower
+.Fa "char *source"
+.Fc
+.Sh DESCRIPTION
+The
+.Nm
+library provides a light-weight, portable framework for parsing configuration
+files.
+The library uses
+.Xr open 2 ,
+.Xr read 2 ,
+and
+.Xr lseek 2
+within the file pointed to by
+.Fa path
+to find directives and values which are then made available to the application.
+.Pp
+Due to the fact that configuration files may have basic syntax differences,
+the library does not attempt to impose any structure on the data but instead
+provides raw data to a set of callback functions.
+These callback functions can in-turn initiate abort through their return value,
+allowing custom syntax validation during parsing.
+.Pp
+Configuration directives, types, and callback functions are provided through
+data structures defined in
+.In figpar.h :
+.Bd -literal -offset indent
+struct fp_config {
+ enum fp_cfgtype type; /* value type */
+ const char *directive; /* keyword */
+ union fp_cfgvalue value; /* value */
+
+ /* Pointer to function used when directive is found */
+ int (*action)(struct fp_config *option, uint32_t line,
+ char *directive, char *value);
+};
+
+enum fp_cfgtype {
+ FP_TYPE_NONE = 0x0000, /* for directives with no value */
+ FP_TYPE_BOOL = 0x0001, /* boolean */
+ FP_TYPE_INT = 0x0002, /* signed 32 bit integer */
+ FP_TYPE_UINT = 0x0004, /* unsigned 32 bit integer */
+ FP_TYPE_STR = 0x0008, /* string pointer */
+ FP_TYPE_STRARRAY = 0x0010, /* string array pointer */
+ FP_TYPE_DATA1 = 0x0020, /* void data type-1 (whatever) */
+ FP_TYPE_DATA2 = 0x0040, /* void data type-2 (whatever) */
+ FP_TYPE_DATA3 = 0x0080, /* void data type-3 (whatever) */
+ FP_TYPE_RESERVED1 = 0x0100, /* reserved data type-1 (future) */
+ FP_TYPE_RESERVED2 = 0x0200, /* reserved data type-2 (future) */
+ FP_TYPE_RESERVED3 = 0x0400, /* reserved data type-3 (future) */
+};
+
+union fp_cfgvalue {
+ void *data; /* Pointer to NUL-terminated string */
+ char *str; /* Pointer to NUL-terminated string */
+ char **strarray; /* Pointer to an array of strings */
+ int32_t num; /* Signed 32-bit integer value */
+ uint32_t u_num; /* Unsigned 32-bit integer value */
+ uint32_t boolean:1; /* Boolean integer value (0 or 1) */
+};
+.Ed
+.Pp
+The
+.Fa processing_options
+argument to
+.Fn parse_config
+is a mask of bit fields which indicate various
+processing options.
+The possible flags are as follows:
+.Bl -tag -width FP_BREAK_ON_SEMICOLON
+.It Dv FP_BREAK_ON_EQUALS
+An equals sign
+.Pq Ql Li =
+is normally considered part of the directive.
+This flag enables terminating the directive at the equals sign.
+Also makes equals sign optional and transient.
+.It Dv FP_BREAK_ON_SEMICOLON
+A semicolon
+.Pq Ql Li \;
+is normally considered part of the value.
+This flag enables terminating the value at the semicolon.
+Also allows multiple statements on a single line separated by semicolon.
+.It Dv FP_CASE_SENSITIVE
+Normally directives are matched case insensitively using
+.Xr fnmatch 3 .
+This flag enables directive matching to be case sensitive.
+.It Dv FP_REQUIRE_EQUALS
+If a directive is not followed by an equals, processing is aborted.
+.It Dv FP_STRICT_EQUALS
+Equals must be part of the directive to be considered a delimiter between
+directive and value.
+.El
+.Pp
+The
+.Fa options
+struct array pointer can be NULL and every directive will invoke the
+.Fn unknown
+function argument.
+.Pp
+The directive for each fp_config item in the
+.Fn parse_config
+options argument is matched against each parsed directive using
+.Xr fnmatch 3
+until a match is found.
+If a match is found, the
+.Fn action
+function for that fp_config directive is invoked with the line number,
+directive, and value.
+Otherwise if no match, the
+.Fn unknown
+function is invoked
+.Pq with the same arguments .
+.Pp
+If either
+.Fa action
+or
+.Fa unknown
+return non-zero,
+.Fn parse_config
+aborts reading the file and returns the error value to its caller.
+.Pp
+.Fn get_config_option
+traverses the options-array and returns the option that matches via
+.Xr strcmp 3 ,
+or if no match a pointer to a static dummy struct is returned
+.Pq whose values are all zero or NULL .
+.Pp
+The use of
+.Fa "struct fp_config"
+is entirely optional as-is the use of
+.Fa "enum fp_cfgtype"
+or
+.Fa "union fp_cfgvalue" .
+For example, you could choose to pass a NULL pointer to
+.Fn parse_config
+for the first argument and then provide a simple
+.Fa unknown
+function based on
+.Xr queue 3
+that populates a singly-linked list of your own struct containing the
+.Fa directive
+and
+.Fa value .
+.Pp
+In addition, the following miscellaneous string manipulation routines are
+provided by
+.In string_m.h :
+.Bl -tag -width strexpandnl()
+.It Fn replaceall
+Replace all occurrences of
+.Fa find
+in
+.Fa source
+with
+.Fa replace .
+.It Fn strcount
+Count the number of occurrences of one string that appear in the
+.Fa source
+string.
+Return value is the total count.
+An example use would be if you need to know how large a block of memory needs
+to be for a
+.Fn replaceall
+series.
+.It Fn strexpand
+Expand escape sequences in a buffer pointed to by
+.Fa source .
+.It Fn strexpandnl
+Expand only the escaped newlines in a buffer pointed to by
+.Fa source .
+.It Fn strtolower
+Convert a string to lower case.
+.El
+.Sh SEE ALSO
+.Xr queue 3
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Fx 11.0 .
+.Sh AUTHORS
+.An Devin Teske Aq dteske@FreeBSD.org
+.Sh BUGS
+This is the first implementation of the library,
+and the interface may be subject to refinement.
diff --git a/lib/libfigpar/figpar.c b/lib/libfigpar/figpar.c
new file mode 100644
index 0000000..a97fc85
--- /dev/null
+++ b/lib/libfigpar/figpar.c
@@ -0,0 +1,469 @@
+/*-
+ * Copyright (c) 2002-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "figpar.h"
+#include "string_m.h"
+
+struct fp_config fp_dummy_config = {0, NULL, {0}, NULL};
+
+/*
+ * Search for config option (struct fp_config) in the array of config options,
+ * returning the struct whose directive matches the given parameter. If no
+ * match is found, a pointer to the static dummy array (above) is returned.
+ *
+ * This is to eliminate dependency on the index position of an item in the
+ * array, since the index position is more apt to be changed as code grows.
+ */
+struct fp_config *
+get_config_option(struct fp_config options[], const char *directive)
+{
+ uint32_t n;
+
+ /* Check arguments */
+ if (options == NULL || directive == NULL)
+ return (&fp_dummy_config);
+
+ /* Loop through the array, return the index of the first match */
+ for (n = 0; options[n].directive != NULL; n++)
+ if (strcmp(options[n].directive, directive) == 0)
+ return (&(options[n]));
+
+ /* Re-initialize the dummy variable in case it was written to */
+ fp_dummy_config.directive = NULL;
+ fp_dummy_config.type = 0;
+ fp_dummy_config.action = NULL;
+ fp_dummy_config.value.u_num = 0;
+
+ return (&fp_dummy_config);
+}
+
+/*
+ * Parse the configuration file at `path' and execute the `action' call-back
+ * functions for any directives defined by the array of config options (first
+ * argument).
+ *
+ * For unknown directives that are encountered, you can optionally pass a
+ * call-back function for the third argument to be called for unknowns.
+ *
+ * Returns zero on success; otherwise returns -1 and errno should be consulted.
+*/
+int
+parse_config(struct fp_config options[], const char *path,
+ int (*unknown)(struct fp_config *option, uint32_t line, char *directive,
+ char *value), uint16_t processing_options)
+{
+ uint8_t bequals;
+ uint8_t bsemicolon;
+ uint8_t case_sensitive;
+ uint8_t comment = 0;
+ uint8_t end;
+ uint8_t found;
+ uint8_t have_equals = 0;
+ uint8_t quote;
+ uint8_t require_equals;
+ uint8_t strict_equals;
+ char p[2];
+ char *directive;
+ char *t;
+ char *value;
+ int error;
+ int fd;
+ ssize_t r = 1;
+ uint32_t dsize;
+ uint32_t line = 1;
+ uint32_t n;
+ uint32_t vsize;
+ uint32_t x;
+ off_t charpos;
+ off_t curpos;
+ char rpath[PATH_MAX];
+
+ /* Sanity check: if no options and no unknown function, return */
+ if (options == NULL && unknown == NULL)
+ return (-1);
+
+ /* Processing options */
+ bequals = (processing_options & FP_BREAK_ON_EQUALS) == 0 ? 0 : 1;
+ bsemicolon = (processing_options & FP_BREAK_ON_SEMICOLON) == 0 ? 0 : 1;
+ case_sensitive = (processing_options & FP_CASE_SENSITIVE) == 0 ? 0 : 1;
+ require_equals = (processing_options & FP_REQUIRE_EQUALS) == 0 ? 0 : 1;
+ strict_equals = (processing_options & FP_STRICT_EQUALS) == 0 ? 0 : 1;
+
+ /* Initialize strings */
+ directive = value = 0;
+ vsize = dsize = 0;
+
+ /* Resolve the file path */
+ if (realpath(path, rpath) == 0)
+ return (-1);
+
+ /* Open the file */
+ if ((fd = open(rpath, O_RDONLY)) < 0)
+ return (-1);
+
+ /* Read the file until EOF */
+ while (r != 0) {
+ r = read(fd, p, 1);
+
+ /* skip to the beginning of a directive */
+ while (r != 0 && (isspace(*p) || *p == '#' || comment ||
+ (bsemicolon && *p == ';'))) {
+ if (*p == '#')
+ comment = 1;
+ else if (*p == '\n') {
+ comment = 0;
+ line++;
+ }
+ r = read(fd, p, 1);
+ }
+ /* Test for EOF; if EOF then no directive was found */
+ if (r == 0) {
+ close(fd);
+ return (0);
+ }
+
+ /* Get the current offset */
+ curpos = lseek(fd, 0, SEEK_CUR) - 1;
+ if (curpos == -1) {
+ close(fd);
+ return (-1);
+ }
+
+ /* Find the length of the directive */
+ for (n = 0; r != 0; n++) {
+ if (isspace(*p))
+ break;
+ if (bequals && *p == '=') {
+ have_equals = 1;
+ break;
+ }
+ if (bsemicolon && *p == ';')
+ break;
+ r = read(fd, p, 1);
+ }
+
+ /* Test for EOF, if EOF then no directive was found */
+ if (n == 0 && r == 0) {
+ close(fd);
+ return (0);
+ }
+
+ /* Go back to the beginning of the directive */
+ error = (int)lseek(fd, curpos, SEEK_SET);
+ if (error == (curpos - 1)) {
+ close(fd);
+ return (-1);
+ }
+
+ /* Allocate and read the directive into memory */
+ if (n > dsize) {
+ if ((directive = realloc(directive, n + 1)) == NULL) {
+ close(fd);
+ return (-1);
+ }
+ dsize = n;
+ }
+ r = read(fd, directive, n);
+
+ /* Advance beyond the equals sign if appropriate/desired */
+ if (bequals && *p == '=') {
+ if (lseek(fd, 1, SEEK_CUR) != -1)
+ r = read(fd, p, 1);
+ if (strict_equals && isspace(*p))
+ *p = '\n';
+ }
+
+ /* Terminate the string */
+ directive[n] = '\0';
+
+ /* Convert directive to lower case before comparison */
+ if (!case_sensitive)
+ strtolower(directive);
+
+ /* Move to what may be the start of the value */
+ if (!(bsemicolon && *p == ';') &&
+ !(strict_equals && *p == '=')) {
+ while (r != 0 && isspace(*p) && *p != '\n')
+ r = read(fd, p, 1);
+ }
+
+ /* An equals sign may have stopped us, should we eat it? */
+ if (r != 0 && bequals && *p == '=' && !strict_equals) {
+ have_equals = 1;
+ r = read(fd, p, 1);
+ while (r != 0 && isspace(*p) && *p != '\n')
+ r = read(fd, p, 1);
+ }
+
+ /* If no value, allocate a dummy value and jump to action */
+ if (r == 0 || *p == '\n' || *p == '#' ||
+ (bsemicolon && *p == ';')) {
+ /* Initialize the value if not already done */
+ if (value == NULL && (value = malloc(1)) == NULL) {
+ close(fd);
+ return (-1);
+ }
+ value[0] = '\0';
+ goto call_function;
+ }
+
+ /* Get the current offset */
+ curpos = lseek(fd, 0, SEEK_CUR) - 1;
+ if (curpos == -1) {
+ close(fd);
+ return (-1);
+ }
+
+ /* Find the end of the value */
+ quote = 0;
+ end = 0;
+ while (r != 0 && end == 0) {
+ /* Advance to the next character if we know we can */
+ if (*p != '\"' && *p != '#' && *p != '\n' &&
+ (!bsemicolon || *p != ';')) {
+ r = read(fd, p, 1);
+ continue;
+ }
+
+ /*
+ * If we get this far, we've hit an end-key
+ */
+
+ /* Get the current offset */
+ charpos = lseek(fd, 0, SEEK_CUR) - 1;
+ if (charpos == -1) {
+ close(fd);
+ return (-1);
+ }
+
+ /*
+ * Go back so we can read the character before the key
+ * to check if the character is escaped (which means we
+ * should continue).
+ */
+ error = (int)lseek(fd, -2, SEEK_CUR);
+ if (error == -3) {
+ close(fd);
+ return (-1);
+ }
+ r = read(fd, p, 1);
+
+ /*
+ * Count how many backslashes there are (an odd number
+ * means the key is escaped, even means otherwise).
+ */
+ for (n = 1; *p == '\\'; n++) {
+ /* Move back another offset to read */
+ error = (int)lseek(fd, -2, SEEK_CUR);
+ if (error == -3) {
+ close(fd);
+ return (-1);
+ }
+ r = read(fd, p, 1);
+ }
+
+ /* Move offset back to the key and read it */
+ error = (int)lseek(fd, charpos, SEEK_SET);
+ if (error == (charpos - 1)) {
+ close(fd);
+ return (-1);
+ }
+ r = read(fd, p, 1);
+
+ /*
+ * If an even number of backslashes was counted meaning
+ * key is not escaped, we should evaluate what to do.
+ */
+ if ((n & 1) == 1) {
+ switch (*p) {
+ case '\"':
+ /*
+ * Flag current sequence of characters
+ * to follow as being quoted (hashes
+ * are not considered comments).
+ */
+ quote = !quote;
+ break;
+ case '#':
+ /*
+ * If we aren't in a quoted series, we
+ * just hit an inline comment and have
+ * found the end of the value.
+ */
+ if (!quote)
+ end = 1;
+ break;
+ case '\n':
+ /*
+ * Newline characters must always be
+ * escaped, whether inside a quoted
+ * series or not, otherwise they
+ * terminate the value.
+ */
+ end = 1;
+ case ';':
+ if (!quote && bsemicolon)
+ end = 1;
+ break;
+ }
+ } else if (*p == '\n')
+ /* Escaped newline character. increment */
+ line++;
+
+ /* Advance to the next character */
+ r = read(fd, p, 1);
+ }
+
+ /* Get the current offset */
+ charpos = lseek(fd, 0, SEEK_CUR) - 1;
+ if (charpos == -1) {
+ close(fd);
+ return (-1);
+ }
+
+ /* Get the length of the value */
+ n = (uint32_t)(charpos - curpos);
+ if (r != 0) /* more to read, but don't read ending key */
+ n--;
+
+ /* Move offset back to the beginning of the value */
+ error = (int)lseek(fd, curpos, SEEK_SET);
+ if (error == (curpos - 1)) {
+ close(fd);
+ return (-1);
+ }
+
+ /* Allocate and read the value into memory */
+ if (n > vsize) {
+ if ((value = realloc(value, n + 1)) == NULL) {
+ close(fd);
+ return (-1);
+ }
+ vsize = n;
+ }
+ r = read(fd, value, n);
+
+ /* Terminate the string */
+ value[n] = '\0';
+
+ /* Cut trailing whitespace off by termination */
+ t = value + n;
+ while (isspace(*--t))
+ *t = '\0';
+
+ /* Escape the escaped quotes (replaceall is in string_m.c) */
+ x = strcount(value, "\\\""); /* in string_m.c */
+ if (x != 0 && (n + x) > vsize) {
+ if ((value = realloc(value, n + x + 1)) == NULL) {
+ close(fd);
+ return (-1);
+ }
+ vsize = n + x;
+ }
+ if (replaceall(value, "\\\"", "\\\\\"") < 0) {
+ /* Replace operation failed for some unknown reason */
+ close(fd);
+ return (-1);
+ }
+
+ /* Remove all new line characters */
+ if (replaceall(value, "\\\n", "") < 0) {
+ /* Replace operation failed for some unknown reason */
+ close(fd);
+ return (-1);
+ }
+
+ /* Resolve escape sequences */
+ strexpand(value); /* in string_m.c */
+
+call_function:
+ /* Abort if we're seeking only assignments */
+ if (require_equals && !have_equals)
+ return (-1);
+
+ found = have_equals = 0; /* reset */
+
+ /* If there are no options defined, call unknown and loop */
+ if (options == NULL && unknown != NULL) {
+ error = unknown(NULL, line, directive, value);
+ if (error != 0) {
+ close(fd);
+ return (error);
+ }
+ continue;
+ }
+
+ /* Loop through the array looking for a match for the value */
+ for (n = 0; options[n].directive != NULL; n++) {
+ error = fnmatch(options[n].directive, directive,
+ FNM_NOESCAPE);
+ if (error == 0) {
+ found = 1;
+ /* Call function for array index item */
+ if (options[n].action != NULL) {
+ error = options[n].action(
+ &options[n],
+ line, directive, value);
+ if (error != 0) {
+ close(fd);
+ return (error);
+ }
+ }
+ } else if (error != FNM_NOMATCH) {
+ /* An error has occurred */
+ close(fd);
+ return (-1);
+ }
+ }
+ if (!found && unknown != NULL) {
+ /*
+ * No match was found for the value we read from the
+ * file; call function designated for unknown values.
+ */
+ error = unknown(NULL, line, directive, value);
+ if (error != 0) {
+ close(fd);
+ return (error);
+ }
+ }
+ }
+
+ close(fd);
+ return (0);
+}
diff --git a/lib/libfigpar/figpar.h b/lib/libfigpar/figpar.h
new file mode 100644
index 0000000..16f825a
--- /dev/null
+++ b/lib/libfigpar/figpar.h
@@ -0,0 +1,99 @@
+/*-
+ * Copyright (c) 2002-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _FIGPAR_H_
+#define _FIGPAR_H_
+
+#include <sys/types.h>
+
+/*
+ * Union for storing various types of data in a single common container.
+ */
+union fp_cfgvalue {
+ void *data; /* Pointer to NUL-terminated string */
+ char *str; /* Pointer to NUL-terminated string */
+ char **strarray; /* Pointer to an array of strings */
+ int32_t num; /* Signed 32-bit integer value */
+ uint32_t u_num; /* Unsigned 32-bit integer value */
+ uint32_t boolean:1; /* Boolean integer value (0 or 1) */
+};
+
+/*
+ * Option types (based on above cfgvalue union)
+ */
+enum fp_cfgtype {
+ FP_TYPE_NONE = 0x0000, /* for directives with no value */
+ FP_TYPE_BOOL = 0x0001, /* boolean */
+ FP_TYPE_INT = 0x0002, /* signed 32 bit integer */
+ FP_TYPE_UINT = 0x0004, /* unsigned 32 bit integer */
+ FP_TYPE_STR = 0x0008, /* string pointer */
+ FP_TYPE_STRARRAY = 0x0010, /* string array pointer */
+ FP_TYPE_DATA1 = 0x0020, /* void data type-1 (whatever) */
+ FP_TYPE_DATA2 = 0x0040, /* void data type-2 (whatever) */
+ FP_TYPE_DATA3 = 0x0080, /* void data type-3 (whatever) */
+ FP_TYPE_RESERVED1 = 0x0100, /* reserved data type-1 (future) */
+ FP_TYPE_RESERVED2 = 0x0200, /* reserved data type-2 (future) */
+ FP_TYPE_RESERVED3 = 0x0400, /* reserved data type-3 (future) */
+};
+
+/*
+ * Options to parse_config() for processing_options bitmask
+ */
+#define FP_BREAK_ON_EQUALS 0x0001 /* stop reading directive at `=' */
+#define FP_BREAK_ON_SEMICOLON 0x0002 /* `;' starts a new line */
+#define FP_CASE_SENSITIVE 0x0004 /* directives are case sensitive */
+#define FP_REQUIRE_EQUALS 0x0008 /* assignment directives only */
+#define FP_STRICT_EQUALS 0x0010 /* `=' must be part of directive */
+
+/*
+ * Anatomy of a config file option
+ */
+struct fp_config {
+ enum fp_cfgtype type; /* Option value type */
+ const char *directive; /* config file keyword */
+ union fp_cfgvalue value; /* NB: set by action */
+
+ /*
+ * Function pointer; action to be taken when the directive is found
+ */
+ int (*action)(struct fp_config *option, uint32_t line, char *directive,
+ char *value);
+};
+extern struct fp_config fp_dummy_config;
+
+__BEGIN_DECLS
+int parse_config(struct fp_config _options[],
+ const char *_path,
+ int (*_unknown)(struct fp_config *_option,
+ uint32_t _line, char *_directive, char *_value),
+ uint16_t _processing_options);
+struct fp_config *get_config_option(struct fp_config _options[],
+ const char *_directive);
+__END_DECLS
+
+#endif /* _FIGPAR_H_ */
diff --git a/lib/libfigpar/string_m.c b/lib/libfigpar/string_m.c
new file mode 100644
index 0000000..d358e90
--- /dev/null
+++ b/lib/libfigpar/string_m.c
@@ -0,0 +1,309 @@
+/*-
+ * Copyright (c) 2001-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "string_m.h"
+
+/*
+ * Counts the number of occurrences of one string that appear in the source
+ * string. Return value is the total count.
+ *
+ * An example use would be if you need to know how large a block of memory
+ * needs to be for a replaceall() series.
+ */
+unsigned int
+strcount(const char *source, const char *find)
+{
+ const char *p = source;
+ size_t flen;
+ unsigned int n = 0;
+
+ /* Both parameters are required */
+ if (source == NULL || find == NULL)
+ return (0);
+
+ /* Cache the length of find element */
+ flen = strlen(find);
+ if (strlen(source) == 0 || flen == 0)
+ return (0);
+
+ /* Loop until the end of the string */
+ while (*p != '\0') {
+ if (strncmp(p, find, flen) == 0) { /* found an instance */
+ p += flen;
+ n++;
+ } else
+ p++;
+ }
+
+ return (n);
+}
+
+/*
+ * Replaces all occurrences of `find' in `source' with `replace'.
+ *
+ * You should not pass a string constant as the first parameter, it needs to be
+ * a pointer to an allocated block of memory. The block of memory that source
+ * points to should be large enough to hold the result. If the length of the
+ * replacement string is greater than the length of the find string, the result
+ * will be larger than the original source string. To allocate enough space for
+ * the result, use the function strcount() declared above to determine the
+ * number of occurrences and how much larger the block size needs to be.
+ *
+ * If source is not large enough, the application will crash. The return value
+ * is the length (in bytes) of the result.
+ *
+ * When an error occurs, -1 is returned and the global variable errno is set
+ * accordingly. Returns zero on success.
+ */
+int
+replaceall(char *source, const char *find, const char *replace)
+{
+ char *p;
+ char *t;
+ char *temp;
+ size_t flen;
+ size_t rlen;
+ size_t slen;
+ uint32_t n = 0;
+
+ errno = 0; /* reset global error number */
+
+ /* Check that we have non-null parameters */
+ if (source == NULL)
+ return (0);
+ if (find == NULL)
+ return (strlen(source));
+
+ /* Cache the length of the strings */
+ slen = strlen(source);
+ flen = strlen(find);
+ rlen = replace ? strlen(replace) : 0;
+
+ /* Cases where no replacements need to be made */
+ if (slen == 0 || flen == 0 || slen < flen)
+ return (slen);
+
+ /* If replace is longer than find, we'll need to create a temp copy */
+ if (rlen > flen) {
+ temp = malloc(slen + 1);
+ if (errno != 0) /* could not allocate memory */
+ return (-1);
+ strcpy(temp, source);
+ } else
+ temp = source;
+
+ /* Reconstruct the string with the replacements */
+ p = source; t = temp; /* position elements */
+
+ while (*t != '\0') {
+ if (strncmp(t, find, flen) == 0) {
+ /* found an occurrence */
+ for (n = 0; replace && replace[n]; n++)
+ *p++ = replace[n];
+ t += flen;
+ } else
+ *p++ = *t++; /* copy character and increment */
+ }
+
+ /* Terminate the string */
+ *p = '\0';
+
+ /* Free the temporary allocated memory */
+ if (temp != source)
+ free(temp);
+
+ /* Return the length of the completed string */
+ return (strlen(source));
+}
+
+/*
+ * Expands escape sequences in a buffer pointed to by `source'. This function
+ * steps through each character, and converts escape sequences such as "\n",
+ * "\r", "\t" and others into their respective meanings.
+ *
+ * You should not pass a string constant or literal to this function or the
+ * program will likely segmentation fault when it tries to modify the data.
+ *
+ * The string length will either shorten or stay the same depending on whether
+ * any escape sequences were converted but the amount of memory allocated does
+ * not change.
+ *
+ * Interpreted sequences are:
+ *
+ * \0NNN character with octal value NNN (0 to 3 digits)
+ * \N character with octal value N (0 thru 7)
+ * \a alert (BEL)
+ * \b backslash
+ * \f form feed
+ * \n new line
+ * \r carriage return
+ * \t horizontal tab
+ * \v vertical tab
+ * \xNN byte with hexadecimal value NN (1 to 2 digits)
+ *
+ * All other sequences are unescaped (ie. '\"' and '\#').
+ */
+void strexpand(char *source)
+{
+ uint8_t c;
+ char *chr;
+ char *pos;
+ char d[4];
+
+ /* Initialize position elements */
+ pos = chr = source;
+
+ /* Loop until we hit the end of the string */
+ while (*pos != '\0') {
+ if (*chr != '\\') {
+ *pos = *chr; /* copy character to current offset */
+ pos++;
+ chr++;
+ continue;
+ }
+
+ /* Replace the backslash with the correct character */
+ switch (*++chr) {
+ case 'a': *pos = '\a'; break; /* bell/alert (BEL) */
+ case 'b': *pos = '\b'; break; /* backspace */
+ case 'f': *pos = '\f'; break; /* form feed */
+ case 'n': *pos = '\n'; break; /* new line */
+ case 'r': *pos = '\r'; break; /* carriage return */
+ case 't': *pos = '\t'; break; /* horizontal tab */
+ case 'v': *pos = '\v'; break; /* vertical tab */
+ case 'x': /* hex value (1 to 2 digits)(\xNN) */
+ d[2] = '\0'; /* pre-terminate the string */
+
+ /* verify next two characters are hex */
+ d[0] = isxdigit(*(chr+1)) ? *++chr : '\0';
+ if (d[0] != '\0')
+ d[1] = isxdigit(*(chr+1)) ? *++chr : '\0';
+
+ /* convert the characters to decimal */
+ c = (uint8_t)strtoul(d, 0, 16);
+
+ /* assign the converted value */
+ *pos = (c != 0 || d[0] == '0') ? c : *++chr;
+ break;
+ case '0': /* octal value (0 to 3 digits)(\0NNN) */
+ d[3] = '\0'; /* pre-terminate the string */
+
+ /* verify next three characters are octal */
+ d[0] = (isdigit(*(chr+1)) && *(chr+1) < '8') ?
+ *++chr : '\0';
+ if (d[0] != '\0')
+ d[1] = (isdigit(*(chr+1)) && *(chr+1) < '8') ?
+ *++chr : '\0';
+ if (d[1] != '\0')
+ d[2] = (isdigit(*(chr+1)) && *(chr+1) < '8') ?
+ *++chr : '\0';
+
+ /* convert the characters to decimal */
+ c = (uint8_t)strtoul(d, 0, 8);
+
+ /* assign the converted value */
+ *pos = c;
+ break;
+ default: /* single octal (\0..7) or unknown sequence */
+ if (isdigit(*chr) && *chr < '8') {
+ d[0] = *chr;
+ d[1] = '\0';
+ *pos = (uint8_t)strtoul(d, 0, 8);
+ } else
+ *pos = *chr;
+ }
+
+ /* Increment to next offset, possible next escape sequence */
+ pos++;
+ chr++;
+ }
+}
+
+/*
+ * Expand only the escaped newlines in a buffer pointed to by `source'. This
+ * function steps through each character, and converts the "\n" sequence into
+ * a literal newline and the "\\n" sequence into "\n".
+ *
+ * You should not pass a string constant or literal to this function or the
+ * program will likely segmentation fault when it tries to modify the data.
+ *
+ * The string length will either shorten or stay the same depending on whether
+ * any escaped newlines were converted but the amount of memory allocated does
+ * not change.
+ */
+void strexpandnl(char *source)
+{
+ uint8_t backslash = 0;
+ char *cp1;
+ char *cp2;
+
+ /* Replace '\n' with literal in dprompt */
+ cp1 = cp2 = source;
+ while (*cp2 != '\0') {
+ *cp1 = *cp2;
+ if (*cp2 == '\\')
+ backslash++;
+ else if (*cp2 != 'n')
+ backslash = 0;
+ else if (backslash > 0) {
+ *(--cp1) = (backslash & 1) == 1 ? '\n' : 'n';
+ backslash = 0;
+ }
+ cp1++;
+ cp2++;
+ }
+ *cp1 = *cp2;
+}
+
+/*
+ * Convert a string to lower case. You should not pass a string constant to
+ * this function. Only pass pointers to allocated memory with null terminated
+ * string data.
+ */
+void
+strtolower(char *source)
+{
+ char *p = source;
+
+ if (source == NULL)
+ return;
+
+ while (*p != '\0') {
+ *p = tolower(*p);
+ p++; /* would have just used `*p++' but gcc 3.x warns */
+ }
+}
diff --git a/lib/libfigpar/string_m.h b/lib/libfigpar/string_m.h
new file mode 100644
index 0000000..18a3fcc
--- /dev/null
+++ b/lib/libfigpar/string_m.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2001-2014 Devin Teske <dteske@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _STRING_M_H_
+#define _STRING_M_H_
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+void strexpand(char *_source);
+void strexpandnl(char *_source);
+void strtolower(char *_source);
+int replaceall(char *_source, const char *_find,
+ const char *_replace);
+unsigned int strcount(const char *_source, const char *_find);
+__END_DECLS
+
+#endif /* !_STRING_M_H_ */
diff --git a/lib/libgeom/geom_getxml.c b/lib/libgeom/geom_getxml.c
index 17e0476..3fe1e72 100644
--- a/lib/libgeom/geom_getxml.c
+++ b/lib/libgeom/geom_getxml.c
@@ -31,10 +31,23 @@
#include <sys/types.h>
#include <sys/sysctl.h>
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "libgeom.h"
+/*
+ * Amount of extra space we allocate to try and anticipate the size of
+ * confxml.
+ */
+#define GEOM_GETXML_SLACK 4096
+
+/*
+ * Number of times to retry in the face of the size of confxml exceeding
+ * that of our buffer.
+ */
+#define GEOM_GETXML_RETRIES 4
+
char *
geom_getxml(void)
{
@@ -42,19 +55,33 @@ geom_getxml(void)
size_t l = 0;
int mib[3];
size_t sizep;
+ int retries;
sizep = sizeof(mib) / sizeof(*mib);
if (sysctlnametomib("kern.geom.confxml", mib, &sizep) != 0)
return (NULL);
if (sysctl(mib, sizep, NULL, &l, NULL, 0) != 0)
return (NULL);
- l += 4096;
- p = malloc(l);
- if (p == NULL)
- return (NULL);
- if (sysctl(mib, sizep, p, &l, NULL, 0) != 0) {
+ l += GEOM_GETXML_SLACK;
+
+ for (retries = 0; retries < GEOM_GETXML_RETRIES; retries++) {
+ p = malloc(l);
+ if (p == NULL)
+ return (NULL);
+ if (sysctl(mib, sizep, p, &l, NULL, 0) == 0)
+ return (reallocf(p, strlen(p) + 1));
+
free(p);
- return (NULL);
+
+ if (errno != ENOMEM)
+ return (NULL);
+
+ /*
+ * Our buffer wasn't big enough. Make it bigger and
+ * try again.
+ */
+ l *= 2;
}
- return (reallocf(p, strlen(p) + 1));
+
+ return (NULL);
}
diff --git a/lib/libgeom/geom_stats.c b/lib/libgeom/geom_stats.c
index 14f9b22..48f7160 100644
--- a/lib/libgeom/geom_stats.c
+++ b/lib/libgeom/geom_stats.c
@@ -68,7 +68,7 @@ geom_stats_resync(void)
return;
for (;;) {
p = mmap(statp, (npages + 1) * pagesize,
- PROT_READ, 0, statsfd, 0);
+ PROT_READ, MAP_SHARED, statsfd, 0);
if (p == MAP_FAILED)
break;
else
@@ -90,7 +90,7 @@ geom_stats_open(void)
return (errno);
pagesize = getpagesize();
spp = pagesize / sizeof(struct devstat);
- p = mmap(NULL, pagesize, PROT_READ, 0, statsfd, 0);
+ p = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, statsfd, 0);
if (p == MAP_FAILED) {
error = errno;
close(statsfd);
diff --git a/lib/libkvm/kvm_arm.c b/lib/libkvm/kvm_arm.c
index d221f6a..cc808e3 100644
--- a/lib/libkvm/kvm_arm.c
+++ b/lib/libkvm/kvm_arm.c
@@ -132,8 +132,10 @@ _kvm_initvtop(kvm_t *kd)
u_long kernbase, physaddr, pa;
pd_entry_t *l1pt;
Elf32_Ehdr *ehdr;
+ Elf32_Phdr *phdr;
size_t hdrsz;
char minihdr[8];
+ int found, i;
if (!kd->rawdump) {
if (pread(kd->pmfd, &minihdr, 8, 0) == 8) {
@@ -158,19 +160,33 @@ _kvm_initvtop(kvm_t *kd)
hdrsz = ehdr->e_phoff + ehdr->e_phentsize * ehdr->e_phnum;
if (_kvm_maphdrs(kd, hdrsz) == -1)
return (-1);
- nl[0].n_name = "kernbase";
+
+ phdr = (Elf32_Phdr *)((uint8_t *)ehdr + ehdr->e_phoff);
+ found = 0;
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_type == PT_DUMP_DELTA) {
+ kernbase = phdr[i].p_vaddr;
+ physaddr = phdr[i].p_paddr;
+ found = 1;
+ break;
+ }
+ }
+
nl[1].n_name = NULL;
- if (kvm_nlist(kd, nl) != 0)
- kernbase = KERNBASE;
- else
- kernbase = nl[0].n_value;
+ if (!found) {
+ nl[0].n_name = "kernbase";
+ if (kvm_nlist(kd, nl) != 0)
+ kernbase = KERNBASE;
+ else
+ kernbase = nl[0].n_value;
- nl[0].n_name = "physaddr";
- if (kvm_nlist(kd, nl) != 0) {
- _kvm_err(kd, kd->program, "couldn't get phys addr");
- return (-1);
+ nl[0].n_name = "physaddr";
+ if (kvm_nlist(kd, nl) != 0) {
+ _kvm_err(kd, kd->program, "couldn't get phys addr");
+ return (-1);
+ }
+ physaddr = nl[0].n_value;
}
- physaddr = nl[0].n_value;
nl[0].n_name = "kernel_l1pa";
if (kvm_nlist(kd, nl) != 0) {
_kvm_err(kd, kd->program, "bad namelist");
@@ -212,7 +228,7 @@ _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
struct vmstate *vm = kd->vmst;
pd_entry_t pd;
pt_entry_t pte;
- u_long pte_pa;
+ off_t pte_pa;
if (kd->vmst->minidump)
return (_kvm_minidump_kvatop(kd, va, pa));
@@ -228,7 +244,7 @@ _kvm_kvatop(kvm_t *kd, u_long va, off_t *pa)
return (_kvm_pa2off(kd, *pa, pa, L1_S_SIZE));
}
pte_pa = (pd & L1_ADDR_MASK) + l2pte_index(va) * sizeof(pte);
- _kvm_pa2off(kd, pte_pa, (off_t *)&pte_pa, L1_S_SIZE);
+ _kvm_pa2off(kd, pte_pa, &pte_pa, L1_S_SIZE);
if (lseek(kd->pmfd, pte_pa, 0) == -1) {
_kvm_syserr(kd, kd->program, "_kvm_kvatop: lseek");
goto invalid;
diff --git a/lib/libkvm/kvm_proc.c b/lib/libkvm/kvm_proc.c
index 31258d7..aed61a8 100644
--- a/lib/libkvm/kvm_proc.c
+++ b/lib/libkvm/kvm_proc.c
@@ -431,6 +431,24 @@ nopgrp:
strlcpy(kp->ki_tdname, mtd.td_name, sizeof(kp->ki_tdname));
kp->ki_pctcpu = 0;
kp->ki_rqindex = 0;
+
+ /*
+ * Note: legacy fields; wraps at NO_CPU_OLD or the
+ * old max CPU value as appropriate
+ */
+ if (mtd.td_lastcpu == NOCPU)
+ kp->ki_lastcpu_old = NOCPU_OLD;
+ else if (mtd.td_lastcpu > MAXCPU_OLD)
+ kp->ki_lastcpu_old = MAXCPU_OLD;
+ else
+ kp->ki_lastcpu_old = mtd.td_lastcpu;
+
+ if (mtd.td_oncpu == NOCPU)
+ kp->ki_oncpu_old = NOCPU_OLD;
+ else if (mtd.td_oncpu > MAXCPU_OLD)
+ kp->ki_oncpu_old = MAXCPU_OLD;
+ else
+ kp->ki_oncpu_old = mtd.td_oncpu;
} else {
kp->ki_stat = SZOMB;
}
diff --git a/lib/libmp/Makefile b/lib/libmp/Makefile
index a9001a1..5d0e7a7 100644
--- a/lib/libmp/Makefile
+++ b/lib/libmp/Makefile
@@ -1,5 +1,7 @@
# $FreeBSD$
+.include <src.opts.mk>
+
LIB= mp
SHLIB_MAJOR= 7
DPADD= ${LIBCRYPTO}
@@ -13,4 +15,8 @@ CFLAGS+= -I${.CURDIR}/../../crypto
VERSION_DEF= ${.CURDIR}/../libc/Versions.def
SYMBOL_MAPS= ${.CURDIR}/Symbol.map
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libmp/tests/Makefile b/lib/libmp/tests/Makefile
new file mode 100644
index 0000000..0f591eb
--- /dev/null
+++ b/lib/libmp/tests/Makefile
@@ -0,0 +1,10 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libmp
+
+TAP_TESTS_C+= legacy_test
+
+DPADD+= ${LIBCRYPTO} ${LIBMP}
+LDADD+= -lcrypto -lmp
+
+.include <bsd.test.mk>
diff --git a/lib/libmp/tests/legacy_test.c b/lib/libmp/tests/legacy_test.c
new file mode 100644
index 0000000..6f3f7b6
--- /dev/null
+++ b/lib/libmp/tests/legacy_test.c
@@ -0,0 +1,211 @@
+/*-
+ * Copyright (c) 2006, Simon L. Nielsen <simon@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <mp.h>
+#include <stdio.h>
+#include <string.h>
+#include <sysexits.h>
+
+MINT *c0, *c1, *c2, *c3, *c5, *c6, *c8, *c10, *c14, *c15, *c25, \
+ *c42,*c43, *c44, *c45, *t0, *t1;
+static int tnr = 0;
+
+static void
+testmcmp(const MINT *mp1, const MINT *mp2, const char *tname)
+{
+
+ if (mp_mcmp(mp1, mp2) == 0)
+ printf("ok %d - %s\n", ++tnr, tname);
+ else
+ printf("not ok - %d %s\n", ++tnr, tname);
+}
+
+static void
+testsimpel(void)
+{
+ const char str42[] = "2a";
+ MINT *t2;
+ char *s;
+
+ mp_madd(c42, c1, t0);
+ testmcmp(c43, t0, "madd0");
+ mp_madd(t0, c1, t0);
+ testmcmp(c44, t0, "madd1");
+ mp_msub(t0, c1, t0);
+ testmcmp(c43, t0, "msub0");
+ mp_msub(t0, c1, t0);
+ testmcmp(c42, t0, "msub1");
+ mp_move(c42, t0);
+ testmcmp(c42, t0, "move0");
+
+ t2 = mp_xtom(str42);
+ testmcmp(c42, t2, "xtom");
+ s = mp_mtox(t2);
+ if (strcmp(str42, s) == 0)
+ printf("ok %d - %s\n", ++tnr, "mtox0");
+ else
+ printf("not ok %d - %s\n", ++tnr, "mtox0");
+ mp_mfree(t2);
+}
+
+static void
+testgcd(void)
+{
+
+ mp_gcd(c10, c15, t0);
+ testmcmp(t0, c5, "gcd0");
+}
+
+static void
+testmsqrt(void)
+{
+
+ mp_msqrt(c25, t0, t1);
+ testmcmp(t0, c5, "msqrt0");
+ testmcmp(t1, c0, "msqrt1");
+ mp_msqrt(c42, t0, t1);
+ testmcmp(t0, c6, "msqrt2");
+ testmcmp(t1, c6, "msqrt3");
+}
+
+static void
+testdiv(void)
+{
+ short ro;
+ MINT *t2;
+
+ mp_mdiv(c42, c5, t0, t1);
+ testmcmp(t0, c8, "mdiv0");
+ testmcmp(t1, c2, "mdiv1");
+
+ mp_mdiv(c10, c8, t0, t1);
+ testmcmp(t0, c1, "mdiv2");
+ testmcmp(t1, c2, "mdiv3");
+
+ mp_sdiv(c42, 5, t0, &ro);
+ testmcmp(t0, c8, "sdiv0");
+ t2 = mp_itom(ro); // Simpler to use common testmcmp()
+ testmcmp(t2, c2, "sdiv1");
+ mp_mfree(t2);
+
+ mp_sdiv(c10, 8, t0, &ro);
+ testmcmp(t0, c1, "sdiv2");
+ t2 = mp_itom(ro); // Simpler to use common testmcmp()
+ testmcmp(t2, c2, "sdiv3");
+ mp_mfree(t2);
+}
+
+static void
+testmult(void)
+{
+
+ mp_mult(c5, c2, t0);
+ testmcmp(t0, c10, "mmult0");
+ mp_mult(c3, c14, t0);
+ testmcmp(t0, c42, "mmult1");
+}
+
+static void
+testpow(void)
+{
+
+ mp_pow(c2, c3, c10, t0);
+ testmcmp(t0, c8, "pow0");
+ mp_pow(c2, c3, c3, t0);
+ testmcmp(t0, c2, "pow1");
+ mp_rpow(c2, 3, t0);
+ testmcmp(t0, c8, "rpow0");
+}
+
+/*
+ * This program performs some very basic tests of libmp(3). It is by
+ * no means expected to perform a complete test of the library for
+ * correctness, but is meant to test the API to make sure libmp (or
+ * libcrypto) updates don't totally break the library.
+ */
+int
+main(int argc, char *argv[])
+{
+
+ printf("1..25\n");
+
+ /*
+ * Init "constants" variables - done in this somewhat
+ * cumbersome way to in theory be able to check for memory
+ * leaks.
+ */
+ c0 = mp_itom(0);
+ c1 = mp_itom(1);
+ c2 = mp_itom(2);
+ c3 = mp_itom(3);
+ c5 = mp_itom(5);
+ c6 = mp_itom(6);
+ c8 = mp_itom(8);
+ c10 = mp_itom(10);
+ c14 = mp_itom(14);
+ c15 = mp_itom(15);
+ c25 = mp_itom(25);
+ c42 = mp_itom(42);
+ c43 = mp_itom(43);
+ c44 = mp_itom(44);
+ c45 = mp_itom(45);
+
+ // Init temp variables
+ t0 = mp_itom(0);
+ t1 = mp_itom(0);
+
+ // Run tests
+ testsimpel();
+ testgcd();
+ testdiv();
+ testmult();
+ testpow();
+ testmsqrt();
+
+ // Cleanup
+ mp_mfree(c0);
+ mp_mfree(c1);
+ mp_mfree(c2);
+ mp_mfree(c3);
+ mp_mfree(c5);
+ mp_mfree(c6);
+ mp_mfree(c8);
+ mp_mfree(c10);
+ mp_mfree(c14);
+ mp_mfree(c15);
+ mp_mfree(c25);
+ mp_mfree(c42);
+ mp_mfree(c43);
+ mp_mfree(c44);
+ mp_mfree(c45);
+ mp_mfree(t0);
+ mp_mfree(t1);
+
+ return (EX_OK);
+}
diff --git a/lib/libnetbsd/netinet/in.h b/lib/libnetbsd/netinet/in.h
new file mode 100644
index 0000000..c108ae3
--- /dev/null
+++ b/lib/libnetbsd/netinet/in.h
@@ -0,0 +1,72 @@
+/* $FreeBSD$ */
+
+/*
+ * Copyright (c) 1982, 1986, 1990, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)in.h 8.3 (Berkeley) 1/3/94
+ */
+
+#ifndef _LIBNETBSD_NETINET_IN_H_
+#define _LIBNETBSD_NETINET_IN_H_
+
+#include_next <netinet/in.h>
+
+/*
+ * Local port number conventions:
+ *
+ * Ports < IPPORT_RESERVED are reserved for privileged processes (e.g. root),
+ * unless a kernel is compiled with IPNOPRIVPORTS defined.
+ *
+ * When a user does a bind(2) or connect(2) with a port number of zero,
+ * a non-conflicting local port address is chosen.
+ *
+ * The default range is IPPORT_ANONMIN to IPPORT_ANONMAX, although
+ * that is settable by sysctl(3); net.inet.ip.anonportmin and
+ * net.inet.ip.anonportmax respectively.
+ *
+ * A user may set the IPPROTO_IP option IP_PORTRANGE to change this
+ * default assignment range.
+ *
+ * The value IP_PORTRANGE_DEFAULT causes the default behavior.
+ *
+ * The value IP_PORTRANGE_HIGH is the same as IP_PORTRANGE_DEFAULT,
+ * and exists only for FreeBSD compatibility purposes.
+ *
+ * The value IP_PORTRANGE_LOW changes the range to the "low" are
+ * that is (by convention) restricted to privileged processes.
+ * This convention is based on "vouchsafe" principles only.
+ * It is only secure if you trust the remote host to restrict these ports.
+ * The range is IPPORT_RESERVEDMIN to IPPORT_RESERVEDMAX.
+ */
+
+#define IPPORT_ANONMIN 49152
+#define IPPORT_ANONMAX 65535
+#define IPPORT_RESERVEDMIN 600
+#define IPPORT_RESERVEDMAX (IPPORT_RESERVED-1)
+
+#endif
diff --git a/lib/libnetbsd/sys/cdefs.h b/lib/libnetbsd/sys/cdefs.h
index 09a7ca4..051959f 100644
--- a/lib/libnetbsd/sys/cdefs.h
+++ b/lib/libnetbsd/sys/cdefs.h
@@ -42,6 +42,28 @@
#endif
/*
+ * The __CONCAT macro is used to concatenate parts of symbol names, e.g.
+ * with "#define OLD(foo) __CONCAT(old,foo)", OLD(foo) produces oldfoo.
+ * The __CONCAT macro is a bit tricky -- make sure you don't put spaces
+ * in between its arguments. __CONCAT can also concatenate double-quoted
+ * strings produced by the __STRING macro, but this only works with ANSI C.
+ */
+
+#define ___STRING(x) __STRING(x)
+#define ___CONCAT(x,y) __CONCAT(x,y)
+
+/*
+ * The following macro is used to remove const cast-away warnings
+ * from gcc -Wcast-qual; it should be used with caution because it
+ * can hide valid errors; in particular most valid uses are in
+ * situations where the API requires it, not to cast away string
+ * constants. We don't use *intptr_t on purpose here and we are
+ * explicit about unsigned long so that we don't have additional
+ * dependencies.
+ */
+#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a))
+
+/*
* Return the number of elements in a statically-allocated array,
* __x.
*/
diff --git a/lib/libnetbsd/sys/time.h b/lib/libnetbsd/sys/time.h
new file mode 100644
index 0000000..c54be7d
--- /dev/null
+++ b/lib/libnetbsd/sys/time.h
@@ -0,0 +1,65 @@
+/* $FreeBSD$ */
+
+/*
+ * 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.
+ *
+ * @(#)time.h 8.5 (Berkeley) 5/4/95
+ */
+
+#ifndef _LIBNETBSD_SYS_TIME_H_
+#define _LIBNETBSD_SYS_TIME_H_
+
+#include_next <sys/time.h>
+
+/* Operations on timespecs. */
+#define timespecclear(tsp) (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
+#define timespecisset(tsp) ((tsp)->tv_sec || (tsp)->tv_nsec)
+#define timespeccmp(tsp, usp, cmp) \
+ (((tsp)->tv_sec == (usp)->tv_sec) ? \
+ ((tsp)->tv_nsec cmp (usp)->tv_nsec) : \
+ ((tsp)->tv_sec cmp (usp)->tv_sec))
+#define timespecadd(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec >= 1000000000L) { \
+ (vsp)->tv_sec++; \
+ (vsp)->tv_nsec -= 1000000000L; \
+ } \
+ } while (/* CONSTCOND */ 0)
+#define timespecsub(tsp, usp, vsp) \
+ do { \
+ (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \
+ (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \
+ if ((vsp)->tv_nsec < 0) { \
+ (vsp)->tv_sec--; \
+ (vsp)->tv_nsec += 1000000000L; \
+ } \
+ } while (/* CONSTCOND */ 0)
+
+#endif
diff --git a/lib/libnv/Makefile b/lib/libnv/Makefile
index 710c295..e9371bc 100644
--- a/lib/libnv/Makefile
+++ b/lib/libnv/Makefile
@@ -1,7 +1,10 @@
# $FreeBSD$
-LIB= nv
SHLIBDIR?= /lib
+
+.include <src.opts.mk>
+
+LIB= nv
SHLIB_MAJOR= 0
SRCS= dnvlist.c
@@ -146,7 +149,7 @@ MLINKS+=nv.3 nvlist_existsv.3 \
nv.3 nvlist_takev_nvlist.3 \
nv.3 nvlist_takev_descriptor.3 \
nv.3 nvlist_takev_binary.3 \
- nv.3 nvlist_freef.3 \
+ nv.3 nvlist_freev.3 \
nv.3 nvlist_freev_type.3 \
nv.3 nvlist_freev_null.3 \
nv.3 nvlist_freev_bool.3 \
@@ -158,4 +161,8 @@ MLINKS+=nv.3 nvlist_existsv.3 \
WARNS?= 6
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libnv/msgio.c b/lib/libnv/msgio.c
index 41292aa..27620a1 100644
--- a/lib/libnv/msgio.c
+++ b/lib/libnv/msgio.c
@@ -31,7 +31,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
-#include <sys/types.h>
+#include <sys/param.h>
#include <sys/socket.h>
#include <errno.h>
@@ -56,6 +56,8 @@ __FBSDID("$FreeBSD$");
#define PJDLOG_ABORT(...) abort()
#endif
+#define PKG_MAX_SIZE (MCLBYTES / CMSG_SPACE(sizeof(int)) - 1)
+
static int
msghdr_add_fd(struct cmsghdr *cmsg, int fd)
{
@@ -234,22 +236,31 @@ cred_recv(int sock, struct cmsgcred *cred)
return (0);
}
-int
-fd_send(int sock, const int *fds, size_t nfds)
+static int
+fd_package_send(int sock, const int *fds, size_t nfds)
{
struct msghdr msg;
struct cmsghdr *cmsg;
+ struct iovec iov;
unsigned int i;
int serrno, ret;
+ uint8_t dummy;
- if (nfds == 0 || fds == NULL) {
- errno = EINVAL;
- return (-1);
- }
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(fds != NULL);
+ PJDLOG_ASSERT(nfds > 0);
bzero(&msg, sizeof(msg));
- msg.msg_iov = NULL;
- msg.msg_iovlen = 0;
+
+ /*
+ * XXX: Look into cred_send function for more details.
+ */
+ dummy = 0;
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
msg.msg_control = calloc(1, msg.msg_controllen);
if (msg.msg_control == NULL)
@@ -274,22 +285,32 @@ end:
return (ret);
}
-int
-fd_recv(int sock, int *fds, size_t nfds)
+static int
+fd_package_recv(int sock, int *fds, size_t nfds)
{
struct msghdr msg;
struct cmsghdr *cmsg;
unsigned int i;
int serrno, ret;
+ struct iovec iov;
+ uint8_t dummy;
- if (nfds == 0 || fds == NULL) {
- errno = EINVAL;
- return (-1);
- }
+ PJDLOG_ASSERT(sock >= 0);
+ PJDLOG_ASSERT(nfds > 0);
+ PJDLOG_ASSERT(fds != NULL);
+ i = 0;
bzero(&msg, sizeof(msg));
- msg.msg_iov = NULL;
- msg.msg_iovlen = 0;
+ bzero(&iov, sizeof(iov));
+
+ /*
+ * XXX: Look into cred_send function for more details.
+ */
+ iov.iov_base = &dummy;
+ iov.iov_len = sizeof(dummy);
+
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
msg.msg_controllen = nfds * CMSG_SPACE(sizeof(int));
msg.msg_control = calloc(1, msg.msg_controllen);
if (msg.msg_control == NULL)
@@ -333,6 +354,64 @@ end:
}
int
+fd_recv(int sock, int *fds, size_t nfds)
+{
+ unsigned int i, step, j;
+ int ret, serrno;
+
+ if (nfds == 0 || fds == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ret = i = step = 0;
+ while (i < nfds) {
+ if (PKG_MAX_SIZE < nfds - i)
+ step = PKG_MAX_SIZE;
+ else
+ step = nfds - i;
+ ret = fd_package_recv(sock, fds + i, step);
+ if (ret != 0) {
+ /* Close all received descriptors. */
+ serrno = errno;
+ for (j = 0; j < i; j++)
+ close(fds[j]);
+ errno = serrno;
+ break;
+ }
+ i += step;
+ }
+
+ return (ret);
+}
+
+int
+fd_send(int sock, const int *fds, size_t nfds)
+{
+ unsigned int i, step;
+ int ret;
+
+ if (nfds == 0 || fds == NULL) {
+ errno = EINVAL;
+ return (-1);
+ }
+
+ ret = i = step = 0;
+ while (i < nfds) {
+ if (PKG_MAX_SIZE < nfds - i)
+ step = PKG_MAX_SIZE;
+ else
+ step = nfds - i;
+ ret = fd_package_send(sock, fds + i, step);
+ if (ret != 0)
+ break;
+ i += step;
+ }
+
+ return (ret);
+}
+
+int
buf_send(int sock, void *buf, size_t size)
{
ssize_t done;
diff --git a/lib/libnv/nv.3 b/lib/libnv/nv.3
index 63c8e8b..29ba744 100644
--- a/lib/libnv/nv.3
+++ b/lib/libnv/nv.3
@@ -28,7 +28,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 21, 2014
+.Dd September 25, 2014
.Dt NV 3
.Os
.Sh NAME
@@ -150,6 +150,8 @@
.Fn nvlist_get_descriptor "const nvlist_t *nvl" "const char *name"
.Ft "const void *"
.Fn nvlist_get_binary "const nvlist_t *nvl" "const char *name" "size_t *sizep"
+.Ft "const nvlist_t *"
+.Fn nvlist_get_parent "const nvlist_t *nvl"
.\"
.Ft bool
.Fn nvlist_take_bool "nvlist_t *nvl" "const char *name"
@@ -437,6 +439,10 @@ extension, which allows to provide default value for a missing element.
The nvlist must not be in error state.
.Pp
The
+.Fn nvlist_get_parent
+function allows to obtain the parent nvlist from the nested nvlist.
+.Pp
+The
.Fn nvlist_take_bool ,
.Fn nvlist_take_number ,
.Fn nvlist_take_string ,
diff --git a/lib/libnv/nv.h b/lib/libnv/nv.h
index e2d7030..1b55be1 100644
--- a/lib/libnv/nv.h
+++ b/lib/libnv/nv.h
@@ -83,6 +83,8 @@ nvlist_t *nvlist_xfer(int sock, nvlist_t *nvl);
const char *nvlist_next(const nvlist_t *nvl, int *typep, void **cookiep);
+const nvlist_t *nvlist_get_parent(const nvlist_t *nvl);
+
/*
* The nvlist_exists functions check if the given name (optionally of the given
* type) exists on nvlist.
diff --git a/lib/libnv/nv_impl.h b/lib/libnv/nv_impl.h
index 3206006..3ed45b3 100644
--- a/lib/libnv/nv_impl.h
+++ b/lib/libnv/nv_impl.h
@@ -39,6 +39,8 @@ struct nvpair;
typedef struct nvpair nvpair_t;
#endif
+#define NV_TYPE_NVLIST_UP 255
+
#define NV_TYPE_FIRST NV_TYPE_NULL
#define NV_TYPE_LAST NV_TYPE_BINARY
@@ -55,6 +57,8 @@ void nvlist_add_nvpair(nvlist_t *nvl, const nvpair_t *nvp);
void nvlist_move_nvpair(nvlist_t *nvl, nvpair_t *nvp);
+void nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent);
+
const nvpair_t *nvlist_get_nvpair(const nvlist_t *nvl, const char *name);
nvpair_t *nvlist_take_nvpair(nvlist_t *nvl, const char *name);
diff --git a/lib/libnv/nvlist.c b/lib/libnv/nvlist.c
index 929ba48..b495441 100644
--- a/lib/libnv/nvlist.c
+++ b/lib/libnv/nvlist.c
@@ -73,10 +73,11 @@ __FBSDID("$FreeBSD$");
#define NVLIST_MAGIC 0x6e766c /* "nvl" */
struct nvlist {
- int nvl_magic;
- int nvl_error;
- int nvl_flags;
- struct nvl_head nvl_head;
+ int nvl_magic;
+ int nvl_error;
+ int nvl_flags;
+ nvpair_t *nvl_parent;
+ struct nvl_head nvl_head;
};
#define NVLIST_ASSERT(nvl) do { \
@@ -106,6 +107,7 @@ nvlist_create(int flags)
nvl = malloc(sizeof(*nvl));
nvl->nvl_error = 0;
nvl->nvl_flags = flags;
+ nvl->nvl_parent = NULL;
TAILQ_INIT(&nvl->nvl_head);
nvl->nvl_magic = NVLIST_MAGIC;
@@ -147,6 +149,36 @@ nvlist_error(const nvlist_t *nvl)
return (nvl->nvl_error);
}
+nvpair_t *
+nvlist_get_nvpair_parent(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ return (nvl->nvl_parent);
+}
+
+const nvlist_t *
+nvlist_get_parent(const nvlist_t *nvl)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ if (nvl->nvl_parent == NULL)
+ return (NULL);
+
+ return (nvpair_nvlist(nvl->nvl_parent));
+}
+
+void
+nvlist_set_parent(nvlist_t *nvl, nvpair_t *parent)
+{
+
+ NVLIST_ASSERT(nvl);
+
+ nvl->nvl_parent = parent;
+}
+
bool
nvlist_empty(const nvlist_t *nvl)
{
@@ -301,24 +333,34 @@ nvlist_clone(const nvlist_t *nvl)
return (newnvl);
}
+static bool
+nvlist_dump_error_check(const nvlist_t *nvl, int fd, int level)
+{
+
+ if (nvlist_error(nvl) != 0) {
+ dprintf(fd, "%*serror: %d\n", level * 4, "",
+ nvlist_error(nvl));
+ return (true);
+ }
+
+ return (false);
+}
+
/*
* Dump content of nvlist.
*/
-static void
-nvlist_xdump(const nvlist_t *nvl, int fd, int level)
+void
+nvlist_dump(const nvlist_t *nvl, int fd)
{
nvpair_t *nvp;
+ int level;
- PJDLOG_ASSERT(level < 3);
-
- if (nvlist_error(nvl) != 0) {
- dprintf(fd, "%*serror: %d\n", level * 4, "",
- nvlist_error(nvl));
+ level = 0;
+ if (nvlist_dump_error_check(nvl, fd, level))
return;
- }
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
dprintf(fd, "%*s%s (%s):", level * 4, "", nvpair_name(nvp),
nvpair_type_string(nvpair_type(nvp)));
switch (nvpair_type(nvp)) {
@@ -340,8 +382,14 @@ nvlist_xdump(const nvlist_t *nvl, int fd, int level)
break;
case NV_TYPE_NVLIST:
dprintf(fd, "\n");
- nvlist_xdump(nvpair_get_nvlist(nvp), fd, level + 1);
- break;
+ nvl = nvpair_get_nvlist(nvp);
+ if (nvlist_dump_error_check(nvl, fd, level + 1)) {
+ nvl = nvlist_get_parent(nvl);
+ break;
+ }
+ level += 1;
+ nvp = nvlist_first_nvpair(nvl);
+ continue;
case NV_TYPE_DESCRIPTOR:
dprintf(fd, " %d\n", nvpair_get_descriptor(nvp));
break;
@@ -361,14 +409,15 @@ nvlist_xdump(const nvlist_t *nvl, int fd, int level)
default:
PJDLOG_ABORT("Unknown type: %d.", nvpair_type(nvp));
}
- }
-}
-void
-nvlist_dump(const nvlist_t *nvl, int fd)
-{
-
- nvlist_xdump(nvl, fd, 0);
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+ nvp = nvlist_get_nvpair_parent(nvl);
+ if (nvp == NULL)
+ return;
+ nvl = nvlist_get_parent(nvl);
+ level --;
+ }
+ }
}
void
@@ -381,41 +430,44 @@ nvlist_fdump(const nvlist_t *nvl, FILE *fp)
/*
* The function obtains size of the nvlist after nvlist_pack().
- * Additional argument 'level' allows to track how deep are we as we obtain
- * size of the NV_TYPE_NVLIST elements using recursion. We allow at most
- * three levels of recursion.
*/
-static size_t
-nvlist_xsize(const nvlist_t *nvl, int level)
+size_t
+nvlist_size(const nvlist_t *nvl)
{
const nvpair_t *nvp;
size_t size;
NVLIST_ASSERT(nvl);
PJDLOG_ASSERT(nvl->nvl_error == 0);
- PJDLOG_ASSERT(level < 3);
size = sizeof(struct nvlist_header);
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
size += nvpair_header_size();
size += strlen(nvpair_name(nvp)) + 1;
- if (nvpair_type(nvp) == NV_TYPE_NVLIST)
- size += nvlist_xsize(nvpair_get_nvlist(nvp), level + 1);
- else
+ if (nvpair_type(nvp) == NV_TYPE_NVLIST) {
+ size += sizeof(struct nvlist_header);
+ size += nvpair_header_size() + 1;
+ nvl = nvpair_get_nvlist(nvp);
+ PJDLOG_ASSERT(nvl->nvl_error == 0);
+ nvp = nvlist_first_nvpair(nvl);
+ continue;
+ } else {
size += nvpair_size(nvp);
+ }
+
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+ nvp = nvlist_get_nvpair_parent(nvl);
+ if (nvp == NULL)
+ goto out;
+ nvl = nvlist_get_parent(nvl);
+ }
}
+out:
return (size);
}
-size_t
-nvlist_size(const nvlist_t *nvl)
-{
-
- return (nvlist_xsize(nvl, 0));
-}
-
static int *
nvlist_xdescriptors(const nvlist_t *nvl, int *descs, int level)
{
@@ -541,15 +593,59 @@ nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep)
ptr = nvlist_pack_header(nvl, ptr, &left);
- for (nvp = nvlist_first_nvpair(nvl); nvp != NULL;
- nvp = nvlist_next_nvpair(nvl, nvp)) {
- ptr = nvpair_pack(nvp, ptr, fdidxp, &left);
+ nvp = nvlist_first_nvpair(nvl);
+ while (nvp != NULL) {
+ NVPAIR_ASSERT(nvp);
+
+ nvpair_init_datasize(nvp);
+ ptr = nvpair_pack_header(nvp, ptr, &left);
if (ptr == NULL) {
free(buf);
return (NULL);
}
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ ptr = nvpair_pack_null(nvp, ptr, &left);
+ break;
+ case NV_TYPE_BOOL:
+ ptr = nvpair_pack_bool(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER:
+ ptr = nvpair_pack_number(nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING:
+ ptr = nvpair_pack_string(nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST:
+ nvl = nvpair_get_nvlist(nvp);
+ nvp = nvlist_first_nvpair(nvl);
+ ptr = nvlist_pack_header(nvl, ptr, &left);
+ continue;
+ case NV_TYPE_DESCRIPTOR:
+ ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, &left);
+ break;
+ case NV_TYPE_BINARY:
+ ptr = nvpair_pack_binary(nvp, ptr, &left);
+ break;
+ default:
+ PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
+ }
+ if (ptr == NULL) {
+ free(buf);
+ return (NULL);
+ }
+ while ((nvp = nvlist_next_nvpair(nvl, nvp)) == NULL) {
+ nvp = nvlist_get_nvpair_parent(nvl);
+ if (nvp == NULL)
+ goto out;
+ ptr = nvpair_pack_nvlist_up(ptr, &left);
+ if (ptr == NULL)
+ goto out;
+ nvl = nvlist_get_parent(nvl);
+ }
}
+out:
if (sizep != NULL)
*sizep = size;
return (buf);
@@ -600,9 +696,9 @@ nvlist_check_header(struct nvlist_header *nvlhdrp)
return (true);
}
-static const unsigned char *
+const unsigned char *
nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
- int *flagsp, size_t *leftp)
+ bool *isbep, size_t *leftp)
{
struct nvlist_header nvlhdr;
@@ -629,7 +725,8 @@ nvlist_unpack_header(nvlist_t *nvl, const unsigned char *ptr, size_t nfds,
nvl->nvl_flags = (nvlhdr.nvlh_flags & NV_FLAG_PUBLIC_MASK);
ptr += sizeof(nvlhdr);
- *flagsp = (int)nvlhdr.nvlh_flags;
+ if (isbep != NULL)
+ *isbep = (((int)nvlhdr.nvlh_flags & NV_FLAG_BIG_ENDIAN) != 0);
*leftp -= sizeof(nvlhdr);
return (ptr);
@@ -642,32 +739,72 @@ nvlist_t *
nvlist_xunpack(const void *buf, size_t size, const int *fds, size_t nfds)
{
const unsigned char *ptr;
- nvlist_t *nvl;
+ nvlist_t *nvl, *retnvl, *tmpnvl;
nvpair_t *nvp;
size_t left;
- int flags;
+ bool isbe;
left = size;
ptr = buf;
- nvl = nvlist_create(0);
+ tmpnvl = NULL;
+ nvl = retnvl = nvlist_create(0);
if (nvl == NULL)
goto failed;
- ptr = nvlist_unpack_header(nvl, ptr, nfds, &flags, &left);
+ ptr = nvlist_unpack_header(nvl, ptr, nfds, &isbe, &left);
if (ptr == NULL)
goto failed;
while (left > 0) {
- ptr = nvpair_unpack(flags, ptr, &left, fds, nfds, &nvp);
+ ptr = nvpair_unpack(isbe, ptr, &left, &nvp);
+ if (ptr == NULL)
+ goto failed;
+ switch (nvpair_type(nvp)) {
+ case NV_TYPE_NULL:
+ ptr = nvpair_unpack_null(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_BOOL:
+ ptr = nvpair_unpack_bool(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NUMBER:
+ ptr = nvpair_unpack_number(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_STRING:
+ ptr = nvpair_unpack_string(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST:
+ ptr = nvpair_unpack_nvlist(isbe, nvp, ptr, &left, nfds,
+ &tmpnvl);
+ nvlist_set_parent(tmpnvl, nvp);
+ break;
+ case NV_TYPE_DESCRIPTOR:
+ ptr = nvpair_unpack_descriptor(isbe, nvp, ptr, &left,
+ fds, nfds);
+ break;
+ case NV_TYPE_BINARY:
+ ptr = nvpair_unpack_binary(isbe, nvp, ptr, &left);
+ break;
+ case NV_TYPE_NVLIST_UP:
+ if (nvl->nvl_parent == NULL)
+ goto failed;
+ nvl = nvpair_nvlist(nvl->nvl_parent);
+ continue;
+ default:
+ PJDLOG_ABORT("Invalid type (%d).", nvpair_type(nvp));
+ }
if (ptr == NULL)
goto failed;
nvlist_move_nvpair(nvl, nvp);
+ if (tmpnvl != NULL) {
+ nvl = tmpnvl;
+ tmpnvl = NULL;
+ }
}
- return (nvl);
+ return (retnvl);
failed:
- nvlist_destroy(nvl);
+ nvlist_destroy(retnvl);
return (NULL);
}
@@ -727,7 +864,7 @@ nvlist_recv(int sock)
struct nvlist_header nvlhdr;
nvlist_t *nvl, *ret;
unsigned char *buf;
- size_t nfds, size;
+ size_t nfds, size, i;
int serrno, *fds;
if (buf_recv(sock, &nvlhdr, sizeof(nvlhdr)) == -1)
@@ -760,8 +897,11 @@ nvlist_recv(int sock)
}
nvl = nvlist_xunpack(buf, size, fds, nfds);
- if (nvl == NULL)
+ if (nvl == NULL) {
+ for (i = 0; i < nfds; i++)
+ close(fds[i]);
goto out;
+ }
ret = nvl;
out:
@@ -1328,7 +1468,8 @@ nvlist_movev_nvlist(nvlist_t *nvl, nvlist_t *value, const char *namefmt,
nvpair_t *nvp;
if (nvlist_error(nvl) != 0) {
- nvlist_destroy(value);
+ if (value != NULL && nvlist_get_nvpair_parent(value) != NULL)
+ nvlist_destroy(value);
errno = nvlist_error(nvl);
return;
}
diff --git a/lib/libnv/nvlist_impl.h b/lib/libnv/nvlist_impl.h
index 43a7bb0..ef32dea 100644
--- a/lib/libnv/nvlist_impl.h
+++ b/lib/libnv/nvlist_impl.h
@@ -40,4 +40,8 @@ void *nvlist_xpack(const nvlist_t *nvl, int64_t *fdidxp, size_t *sizep);
nvlist_t *nvlist_xunpack(const void *buf, size_t size, const int *fds,
size_t nfds);
+nvpair_t *nvlist_get_nvpair_parent(const nvlist_t *nvl);
+const unsigned char *nvlist_unpack_header(nvlist_t *nvl,
+ const unsigned char *ptr, size_t nfds, bool *isbep, size_t *leftp);
+
#endif /* !_NVLIST_IMPL_H_ */
diff --git a/lib/libnv/nvpair.c b/lib/libnv/nvpair.c
index 916444f..4f0bd72 100644
--- a/lib/libnv/nvpair.c
+++ b/lib/libnv/nvpair.c
@@ -67,7 +67,7 @@ struct nvpair {
int nvp_type;
uint64_t nvp_data;
size_t nvp_datasize;
- nvlist_t *nvp_list; /* Used for sanity checks. */
+ nvlist_t *nvp_list;
TAILQ_ENTRY(nvpair) nvp_next;
};
@@ -90,7 +90,7 @@ nvpair_assert(const nvpair_t *nvp)
NVPAIR_ASSERT(nvp);
}
-const nvlist_t *
+nvlist_t *
nvpair_nvlist(const nvpair_t *nvp)
{
@@ -131,6 +131,17 @@ nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl)
nvp->nvp_list = nvl;
}
+static void
+nvpair_remove_nvlist(nvpair_t *nvp)
+{
+ nvlist_t *nvl;
+
+ /* XXX: DECONST is bad, mkay? */
+ nvl = __DECONST(nvlist_t *, nvpair_get_nvlist(nvp));
+ PJDLOG_ASSERT(nvl != NULL);
+ nvlist_set_parent(nvl, NULL);
+}
+
void
nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
{
@@ -138,6 +149,9 @@ nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl)
NVPAIR_ASSERT(nvp);
PJDLOG_ASSERT(nvp->nvp_list == nvl);
+ if (nvpair_type(nvp) == NV_TYPE_NVLIST)
+ nvpair_remove_nvlist(nvp);
+
TAILQ_REMOVE(head, nvp, nvp_next);
nvp->nvp_list = NULL;
}
@@ -201,7 +215,7 @@ nvpair_size(const nvpair_t *nvp)
return (nvp->nvp_datasize);
}
-static unsigned char *
+unsigned char *
nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
{
struct nvpair_header nvphdr;
@@ -227,7 +241,7 @@ nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
return (ptr);
}
-static unsigned char *
+unsigned char *
nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
size_t *leftp __unused)
{
@@ -238,7 +252,7 @@ nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
return (ptr);
}
-static unsigned char *
+unsigned char *
nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
{
uint8_t value;
@@ -256,7 +270,7 @@ nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
return (ptr);
}
-static unsigned char *
+unsigned char *
nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
{
uint64_t value;
@@ -274,7 +288,7 @@ nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
return (ptr);
}
-static unsigned char *
+unsigned char *
nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
{
@@ -289,37 +303,31 @@ nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
return (ptr);
}
-static unsigned char *
-nvpair_pack_nvlist(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
- size_t *leftp)
+unsigned char *
+nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp)
{
- unsigned char *data;
- size_t size;
-
- NVPAIR_ASSERT(nvp);
- PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NVLIST);
-
- if (nvp->nvp_datasize == 0)
- return (ptr);
-
- data = nvlist_xpack((const nvlist_t *)(intptr_t)nvp->nvp_data, fdidxp,
- &size);
- if (data == NULL)
- return (NULL);
-
- PJDLOG_ASSERT(size == nvp->nvp_datasize);
- PJDLOG_ASSERT(*leftp >= nvp->nvp_datasize);
+ struct nvpair_header nvphdr;
+ size_t namesize;
+ const char *name = "";
- memcpy(ptr, data, nvp->nvp_datasize);
- free(data);
+ namesize = 1;
+ nvphdr.nvph_type = NV_TYPE_NVLIST_UP;
+ nvphdr.nvph_namesize = namesize;
+ nvphdr.nvph_datasize = 0;
+ PJDLOG_ASSERT(*leftp >= sizeof(nvphdr));
+ memcpy(ptr, &nvphdr, sizeof(nvphdr));
+ ptr += sizeof(nvphdr);
+ *leftp -= sizeof(nvphdr);
- ptr += nvp->nvp_datasize;
- *leftp -= nvp->nvp_datasize;
+ PJDLOG_ASSERT(*leftp >= namesize);
+ memcpy(ptr, name, namesize);
+ ptr += namesize;
+ *leftp -= namesize;
return (ptr);
}
-static unsigned char *
+unsigned char *
nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
size_t *leftp)
{
@@ -349,7 +357,7 @@ nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
return (ptr);
}
-static unsigned char *
+unsigned char *
nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
{
@@ -364,17 +372,12 @@ nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr, size_t *leftp)
return (ptr);
}
-unsigned char *
-nvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, size_t *leftp)
+void
+nvpair_init_datasize(nvpair_t *nvp)
{
NVPAIR_ASSERT(nvp);
- /*
- * We have to update datasize for NV_TYPE_NVLIST on every pack,
- * so that proper datasize is placed into nvpair_header
- * during the nvpair_pack_header() call below.
- */
if (nvp->nvp_type == NV_TYPE_NVLIST) {
if (nvp->nvp_data == 0) {
nvp->nvp_datasize = 0;
@@ -383,42 +386,10 @@ nvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp, size_t *leftp)
nvlist_size((const nvlist_t *)(intptr_t)nvp->nvp_data);
}
}
-
- ptr = nvpair_pack_header(nvp, ptr, leftp);
- if (ptr == NULL)
- return (NULL);
-
- switch (nvp->nvp_type) {
- case NV_TYPE_NULL:
- ptr = nvpair_pack_null(nvp, ptr, leftp);
- break;
- case NV_TYPE_BOOL:
- ptr = nvpair_pack_bool(nvp, ptr, leftp);
- break;
- case NV_TYPE_NUMBER:
- ptr = nvpair_pack_number(nvp, ptr, leftp);
- break;
- case NV_TYPE_STRING:
- ptr = nvpair_pack_string(nvp, ptr, leftp);
- break;
- case NV_TYPE_NVLIST:
- ptr = nvpair_pack_nvlist(nvp, ptr, fdidxp, leftp);
- break;
- case NV_TYPE_DESCRIPTOR:
- ptr = nvpair_pack_descriptor(nvp, ptr, fdidxp, leftp);
- break;
- case NV_TYPE_BINARY:
- ptr = nvpair_pack_binary(nvp, ptr, leftp);
- break;
- default:
- PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
- }
-
- return (ptr);
}
-static const unsigned char *
-nvpair_unpack_header(int flags, nvpair_t *nvp, const unsigned char *ptr,
+const unsigned char *
+nvpair_unpack_header(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
size_t *leftp)
{
struct nvpair_header nvphdr;
@@ -434,16 +405,18 @@ nvpair_unpack_header(int flags, nvpair_t *nvp, const unsigned char *ptr,
if (nvphdr.nvph_type < NV_TYPE_FIRST)
goto failed;
#endif
- if (nvphdr.nvph_type > NV_TYPE_LAST)
+ if (nvphdr.nvph_type > NV_TYPE_LAST &&
+ nvphdr.nvph_type != NV_TYPE_NVLIST_UP) {
goto failed;
+ }
#if BYTE_ORDER == BIG_ENDIAN
- if ((flags & NV_FLAG_BIG_ENDIAN) == 0) {
+ if (!isbe) {
nvphdr.nvph_namesize = le16toh(nvphdr.nvph_namesize);
nvphdr.nvph_datasize = le64toh(nvphdr.nvph_datasize);
}
#else
- if ((flags & NV_FLAG_BIG_ENDIAN) != 0) {
+ if (isbe) {
nvphdr.nvph_namesize = be16toh(nvphdr.nvph_namesize);
nvphdr.nvph_datasize = be64toh(nvphdr.nvph_datasize);
}
@@ -477,8 +450,8 @@ failed:
return (NULL);
}
-static const unsigned char *
-nvpair_unpack_null(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
+const unsigned char *
+nvpair_unpack_null(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
size_t *leftp __unused)
{
@@ -492,8 +465,8 @@ nvpair_unpack_null(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
return (ptr);
}
-static const unsigned char *
-nvpair_unpack_bool(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
+const unsigned char *
+nvpair_unpack_bool(bool isbe __unused, nvpair_t *nvp, const unsigned char *ptr,
size_t *leftp)
{
uint8_t value;
@@ -523,9 +496,9 @@ nvpair_unpack_bool(int flags __unused, nvpair_t *nvp, const unsigned char *ptr,
return (ptr);
}
-static const unsigned char *
-nvpair_unpack_number(int flags, nvpair_t *nvp, const unsigned char *ptr,
- size_t *leftp)
+const unsigned char *
+nvpair_unpack_number(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
+ size_t *leftp)
{
PJDLOG_ASSERT(nvp->nvp_type == NV_TYPE_NUMBER);
@@ -539,7 +512,7 @@ nvpair_unpack_number(int flags, nvpair_t *nvp, const unsigned char *ptr,
return (NULL);
}
- if ((flags & NV_FLAG_BIG_ENDIAN) != 0)
+ if (isbe)
nvp->nvp_data = be64dec(ptr);
else
nvp->nvp_data = le64dec(ptr);
@@ -549,8 +522,8 @@ nvpair_unpack_number(int flags, nvpair_t *nvp, const unsigned char *ptr,
return (ptr);
}
-static const unsigned char *
-nvpair_unpack_string(int flags __unused, nvpair_t *nvp,
+const unsigned char *
+nvpair_unpack_string(bool isbe __unused, nvpair_t *nvp,
const unsigned char *ptr, size_t *leftp)
{
@@ -577,9 +550,9 @@ nvpair_unpack_string(int flags __unused, nvpair_t *nvp,
return (ptr);
}
-static const unsigned char *
-nvpair_unpack_nvlist(int flags __unused, nvpair_t *nvp,
- const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds)
+const unsigned char *
+nvpair_unpack_nvlist(bool isbe __unused, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, size_t nfds, nvlist_t **child)
{
nvlist_t *value;
@@ -590,20 +563,22 @@ nvpair_unpack_nvlist(int flags __unused, nvpair_t *nvp,
return (NULL);
}
- value = nvlist_xunpack(ptr, nvp->nvp_datasize, fds, nfds);
+ value = nvlist_create(0);
if (value == NULL)
return (NULL);
- nvp->nvp_data = (uint64_t)(uintptr_t)value;
+ ptr = nvlist_unpack_header(value, ptr, nfds, NULL, leftp);
+ if (ptr == NULL)
+ return (NULL);
- ptr += nvp->nvp_datasize;
- *leftp -= nvp->nvp_datasize;
+ nvp->nvp_data = (uint64_t)(uintptr_t)value;
+ *child = value;
return (ptr);
}
-static const unsigned char *
-nvpair_unpack_descriptor(int flags, nvpair_t *nvp, const unsigned char *ptr,
+const unsigned char *
+nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp, const unsigned char *ptr,
size_t *leftp, const int *fds, size_t nfds)
{
int64_t idx;
@@ -619,7 +594,7 @@ nvpair_unpack_descriptor(int flags, nvpair_t *nvp, const unsigned char *ptr,
return (NULL);
}
- if ((flags & NV_FLAG_BIG_ENDIAN) != 0)
+ if (isbe)
idx = be64dec(ptr);
else
idx = le64dec(ptr);
@@ -642,8 +617,8 @@ nvpair_unpack_descriptor(int flags, nvpair_t *nvp, const unsigned char *ptr,
return (ptr);
}
-static const unsigned char *
-nvpair_unpack_binary(int flags __unused, nvpair_t *nvp,
+const unsigned char *
+nvpair_unpack_binary(bool isbe __unused, nvpair_t *nvp,
const unsigned char *ptr, size_t *leftp)
{
void *value;
@@ -669,8 +644,8 @@ nvpair_unpack_binary(int flags __unused, nvpair_t *nvp,
}
const unsigned char *
-nvpair_unpack(int flags, const unsigned char *ptr, size_t *leftp,
- const int *fds, size_t nfds, nvpair_t **nvpp)
+nvpair_unpack(bool isbe, const unsigned char *ptr, size_t *leftp,
+ nvpair_t **nvpp)
{
nvpair_t *nvp, *tmp;
@@ -679,47 +654,17 @@ nvpair_unpack(int flags, const unsigned char *ptr, size_t *leftp,
return (NULL);
nvp->nvp_name = (char *)(nvp + 1);
- ptr = nvpair_unpack_header(flags, nvp, ptr, leftp);
+ ptr = nvpair_unpack_header(isbe, nvp, ptr, leftp);
if (ptr == NULL)
goto failed;
tmp = realloc(nvp, sizeof(*nvp) + strlen(nvp->nvp_name) + 1);
if (tmp == NULL)
goto failed;
nvp = tmp;
+
/* Update nvp_name after realloc(). */
nvp->nvp_name = (char *)(nvp + 1);
-
- switch (nvp->nvp_type) {
- case NV_TYPE_NULL:
- ptr = nvpair_unpack_null(flags, nvp, ptr, leftp);
- break;
- case NV_TYPE_BOOL:
- ptr = nvpair_unpack_bool(flags, nvp, ptr, leftp);
- break;
- case NV_TYPE_NUMBER:
- ptr = nvpair_unpack_number(flags, nvp, ptr, leftp);
- break;
- case NV_TYPE_STRING:
- ptr = nvpair_unpack_string(flags, nvp, ptr, leftp);
- break;
- case NV_TYPE_NVLIST:
- ptr = nvpair_unpack_nvlist(flags, nvp, ptr, leftp, fds,
- nfds);
- break;
- case NV_TYPE_DESCRIPTOR:
- ptr = nvpair_unpack_descriptor(flags, nvp, ptr, leftp, fds,
- nfds);
- break;
- case NV_TYPE_BINARY:
- ptr = nvpair_unpack_binary(flags, nvp, ptr, leftp);
- break;
- default:
- PJDLOG_ABORT("Invalid type (%d).", nvp->nvp_type);
- }
-
- if (ptr == NULL)
- goto failed;
-
+ nvp->nvp_data = 0x00;
nvp->nvp_magic = NVPAIR_MAGIC;
*nvpp = nvp;
return (ptr);
@@ -1018,6 +963,8 @@ nvpair_createv_nvlist(const nvlist_t *value, const char *namefmt,
namefmt, nameap);
if (nvp == NULL)
nvlist_destroy(nvl);
+ else
+ nvlist_set_parent(nvl, nvp);
return (nvp);
}
@@ -1172,7 +1119,7 @@ nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
{
nvpair_t *nvp;
- if (value == NULL) {
+ if (value == NULL || nvlist_get_nvpair_parent(value) != NULL) {
errno = EINVAL;
return (NULL);
}
@@ -1181,6 +1128,8 @@ nvpair_movev_nvlist(nvlist_t *value, const char *namefmt, va_list nameap)
namefmt, nameap);
if (nvp == NULL)
nvlist_destroy(value);
+ else
+ nvlist_set_parent(value, nvp);
return (nvp);
}
diff --git a/lib/libnv/nvpair_impl.h b/lib/libnv/nvpair_impl.h
index aa4046c..a72000b 100644
--- a/lib/libnv/nvpair_impl.h
+++ b/lib/libnv/nvpair_impl.h
@@ -41,18 +41,52 @@
TAILQ_HEAD(nvl_head, nvpair);
void nvpair_assert(const nvpair_t *nvp);
-const nvlist_t *nvpair_nvlist(const nvpair_t *nvp);
+nvlist_t *nvpair_nvlist(const nvpair_t *nvp);
nvpair_t *nvpair_next(const nvpair_t *nvp);
nvpair_t *nvpair_prev(const nvpair_t *nvp);
void nvpair_insert(struct nvl_head *head, nvpair_t *nvp, nvlist_t *nvl);
void nvpair_remove(struct nvl_head *head, nvpair_t *nvp, const nvlist_t *nvl);
size_t nvpair_header_size(void);
size_t nvpair_size(const nvpair_t *nvp);
-unsigned char *nvpair_pack(nvpair_t *nvp, unsigned char *ptr, int64_t *fdidxp,
- size_t *leftp);
-const unsigned char *nvpair_unpack(int flags, const unsigned char *ptr,
- size_t *leftp, const int *fds, size_t nfds, nvpair_t **nvpp);
+const unsigned char *nvpair_unpack(bool isbe, const unsigned char *ptr,
+ size_t *leftp, nvpair_t **nvpp);
void nvpair_free_structure(nvpair_t *nvp);
+void nvpair_init_datasize(nvpair_t *nvp);
const char *nvpair_type_string(int type);
+/* Pack functions. */
+unsigned char *nvpair_pack_header(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_null(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_bool(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_number(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_string(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_descriptor(const nvpair_t *nvp, unsigned char *ptr,
+ int64_t *fdidxp, size_t *leftp);
+unsigned char *nvpair_pack_binary(const nvpair_t *nvp, unsigned char *ptr,
+ size_t *leftp);
+unsigned char *nvpair_pack_nvlist_up(unsigned char *ptr, size_t *leftp);
+
+/* Unpack data functions. */
+const unsigned char *nvpair_unpack_header(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_null(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_bool(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_number(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_string(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+const unsigned char *nvpair_unpack_nvlist(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, size_t nvlist, nvlist_t **child);
+const unsigned char *nvpair_unpack_descriptor(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp, const int *fds, size_t nfds);
+const unsigned char *nvpair_unpack_binary(bool isbe, nvpair_t *nvp,
+ const unsigned char *ptr, size_t *leftp);
+
#endif /* !_NVPAIR_IMPL_H_ */
diff --git a/lib/libnv/tests/Makefile b/lib/libnv/tests/Makefile
new file mode 100644
index 0000000..df10549
--- /dev/null
+++ b/lib/libnv/tests/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libnv
+
+TAP_TESTS_C+= nvlist_add_test
+TAP_TESTS_C+= nvlist_exists_test
+TAP_TESTS_C+= nvlist_free_test
+TAP_TESTS_C+= nvlist_get_test
+TAP_TESTS_C+= nvlist_move_test
+TAP_TESTS_C+= nvlist_send_recv_test
+
+DPADD+= ${LIBNV}
+LDADD+= -lnv
+
+WARNS?= 6
+
+.include <bsd.test.mk>
diff --git a/lib/libnv/tests/nvlist_add_test.c b/lib/libnv/tests/nvlist_add_test.c
new file mode 100644
index 0000000..06bcc63
--- /dev/null
+++ b/lib/libnv/tests/nvlist_add_test.c
@@ -0,0 +1,196 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+
+ printf("1..94\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ nvlist_add_null(nvl, "nvlist/null");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/true"));
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/false"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/0"));
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/0"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/1"));
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/1"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/-1"));
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/-1"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/", "%s", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/x"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/x", "%s", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/x"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+ nvlist_add_stringf(nvl, "nvlist/stringf/666Xabc", "%d%c%s", 666, 'X', "abc");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/0"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/1"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/-1"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/x"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/stringf/666Xabc"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_exists_null(cnvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(cnvl, "nvlist/bool/true"));
+ CHECK(nvlist_exists_bool(cnvl, "nvlist/bool/false"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/0"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/1"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/-1"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/UINT64_MAX"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/INT64_MIN"));
+ CHECK(nvlist_exists_number(cnvl, "nvlist/number/INT64_MAX"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/x"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/stringf/666Xabc"));
+ CHECK(nvlist_exists_descriptor(cnvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_exists_test.c b/lib/libnv/tests/nvlist_exists_test.c
new file mode 100644
index 0000000..cb595d7
--- /dev/null
+++ b/lib/libnv/tests/nvlist_exists_test.c
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ nvlist_t *nvl;
+
+ printf("1..232\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/null"));
+ nvlist_add_null(nvl, "nvlist/null");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/null"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/bool"));
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/bool"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/number"));
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/number"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/string"));
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/string"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/nvlist"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/descriptor"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/descriptor"));
+
+ CHECK(!nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/binary"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_null(nvl, "nvlist/null");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_bool(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_number(nvl, "nvlist/number");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_string(nvl, "nvlist/string");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_nvlist(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_descriptor(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_binary(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists(nvl, "nvlist/binary"));
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_free_test.c b/lib/libnv/tests/nvlist_free_test.c
new file mode 100644
index 0000000..4417a44
--- /dev/null
+++ b/lib/libnv/tests/nvlist_free_test.c
@@ -0,0 +1,221 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ nvlist_t *nvl;
+
+ printf("1..114\n");
+
+ nvl = nvlist_create(0);
+
+ nvlist_add_null(nvl, "nvlist/null");
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_null(nvl, "nvlist/null");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_bool(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_number(nvl, "nvlist/number");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_string(nvl, "nvlist/string");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_nvlist(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_descriptor(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free_binary(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_add_null(nvl, "nvlist/null");
+ nvlist_add_bool(nvl, "nvlist/bool", true);
+ nvlist_add_number(nvl, "nvlist/number", 0);
+ nvlist_add_string(nvl, "nvlist/string", "test");
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ nvlist_add_descriptor(nvl, "nvlist/descriptor", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary", "test", 4);
+
+ CHECK(nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/null");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/bool");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/number");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/string");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/nvlist");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/descriptor");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ nvlist_free(nvl, "nvlist/binary");
+ CHECK(!nvlist_exists_null(nvl, "nvlist/null"));
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool"));
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number"));
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string"));
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor"));
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary"));
+
+ CHECK(nvlist_empty(nvl));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_get_test.c b/lib/libnv/tests/nvlist_get_test.c
new file mode 100644
index 0000000..b4468db
--- /dev/null
+++ b/lib/libnv/tests/nvlist_get_test.c
@@ -0,0 +1,182 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+ size_t size;
+
+ printf("1..83\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/true"));
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/true") == true);
+
+ CHECK(!nvlist_exists_bool(nvl, "nvlist/bool/false"));
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/false") == false);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/0"));
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/0") == 0);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/1"));
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/1") == 1);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/-1"));
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int)nvlist_get_number(nvl, "nvlist/number/-1") == -1);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/UINT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MIN"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+
+ CHECK(!nvlist_exists_number(nvl, "nvlist/number/INT64_MAX"));
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/"), "") == 0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/x"), "x") == 0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ CHECK(!nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO")));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+ CHECK(nvlist_error(nvl) == 0);
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_get_bool(cnvl, "nvlist/bool/true") == true);
+ CHECK(nvlist_get_bool(cnvl, "nvlist/bool/false") == false);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/1") == 1);
+ CHECK((int)nvlist_get_number(cnvl, "nvlist/number/-1") == -1);
+ CHECK(nvlist_get_number(cnvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+ CHECK((int64_t)nvlist_get_number(cnvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+ CHECK((int64_t)nvlist_get_number(cnvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/"), "") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/x"), "x") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+ /* TODO */
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/true") == true);
+ CHECK(nvlist_get_bool(nvl, "nvlist/bool/false") == false);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/1") == 1);
+ CHECK((int)nvlist_get_number(nvl, "nvlist/number/-1") == -1);
+ CHECK(nvlist_get_number(nvl, "nvlist/number/UINT64_MAX") == UINT64_MAX);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MIN") == INT64_MIN);
+ CHECK((int64_t)nvlist_get_number(nvl, "nvlist/number/INT64_MAX") == INT64_MAX);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/"), "") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/x"), "x") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"), "abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO")));
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/x", &size), "x", 1) == 0);
+ CHECK(size == 1);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_move_test.c b/lib/libnv/tests/nvlist_move_test.c
new file mode 100644
index 0000000..760399d
--- /dev/null
+++ b/lib/libnv/tests/nvlist_move_test.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+int
+main(void)
+{
+ const nvlist_t *cnvl;
+ nvlist_t *nvl;
+ void *ptr;
+ size_t size;
+ int fd;
+
+ printf("1..52\n");
+
+ nvl = nvlist_create(0);
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/"));
+ ptr = strdup("");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(ptr == nvlist_get_string(nvl, "nvlist/string/"));
+
+ CHECK(!nvlist_exists_string(nvl, "nvlist/string/x"));
+ ptr = strdup("x");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/x", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(ptr == nvlist_get_string(nvl, "nvlist/string/x"));
+
+ CHECK(!nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ ptr = strdup("abcdefghijklmnopqrstuvwxyz");
+ CHECK(ptr != NULL);
+ nvlist_move_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz",
+ ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr ==
+ nvlist_get_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_descriptor(nvl,
+ "nvlist/descriptor/STDERR_FILENO"));
+ fd = dup(STDERR_FILENO);
+ CHECK(fd >= 0);
+ nvlist_move_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", fd);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(fd ==
+ nvlist_get_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+
+ CHECK(!nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ ptr = malloc(1);
+ CHECK(ptr != NULL);
+ memcpy(ptr, "x", 1);
+ nvlist_move_binary(nvl, "nvlist/binary/x", ptr, 1);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(ptr == nvlist_get_binary(nvl, "nvlist/binary/x", NULL));
+ CHECK(ptr == nvlist_get_binary(nvl, "nvlist/binary/x", &size));
+ CHECK(size == 1);
+
+ CHECK(!nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ ptr = malloc(sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr != NULL);
+ memcpy(ptr, "abcdefghijklmnopqrstuvwxyz",
+ sizeof("abcdefghijklmnopqrstuvwxyz"));
+ nvlist_move_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz",
+ ptr, sizeof("abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(ptr == nvlist_get_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz", NULL));
+ CHECK(ptr == nvlist_get_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz", &size));
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ CHECK(!nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ ptr = nvlist_clone(nvl);
+ CHECK(ptr != NULL);
+ nvlist_move_nvlist(nvl, "nvlist/nvlist", ptr);
+ CHECK(nvlist_error(nvl) == 0);
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+ CHECK(ptr == nvlist_get_nvlist(nvl, "nvlist/nvlist"));
+
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(nvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(nvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(nvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(nvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_nvlist(nvl, "nvlist/nvlist"));
+
+ cnvl = nvlist_get_nvlist(nvl, "nvlist/nvlist");
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/"));
+ CHECK(nvlist_exists_string(cnvl, "nvlist/string/x"));
+ CHECK(nvlist_exists_string(cnvl,
+ "nvlist/string/abcdefghijklmnopqrstuvwxyz"));
+ CHECK(nvlist_exists_descriptor(cnvl,
+ "nvlist/descriptor/STDERR_FILENO"));
+ CHECK(nvlist_exists_binary(cnvl, "nvlist/binary/x"));
+ CHECK(nvlist_exists_binary(cnvl,
+ "nvlist/binary/abcdefghijklmnopqrstuvwxyz"));
+
+ nvlist_destroy(nvl);
+
+ return (0);
+}
diff --git a/lib/libnv/tests/nvlist_send_recv_test.c b/lib/libnv/tests/nvlist_send_recv_test.c
new file mode 100644
index 0000000..c751bf7
--- /dev/null
+++ b/lib/libnv/tests/nvlist_send_recv_test.c
@@ -0,0 +1,325 @@
+/*-
+ * Copyright (c) 2013 The FreeBSD Foundation
+ * All rights reserved.
+ *
+ * This software was developed by Pawel Jakub Dawidek under sponsorship from
+ * the FreeBSD Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <nv.h>
+
+static int ntest = 1;
+
+#define CHECK(expr) do { \
+ if ((expr)) \
+ printf("ok # %d %s:%u\n", ntest, __FILE__, __LINE__); \
+ else \
+ printf("not ok # %d %s:%u\n", ntest, __FILE__, __LINE__);\
+ ntest++; \
+} while (0)
+
+#define fd_is_valid(fd) (fcntl((fd), F_GETFL) != -1 || errno != EBADF)
+
+static void
+child(int sock)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+
+ nvlist_add_bool(nvl, "nvlist/bool/true", true);
+ nvlist_add_bool(nvl, "nvlist/bool/false", false);
+ nvlist_add_number(nvl, "nvlist/number/0", 0);
+ nvlist_add_number(nvl, "nvlist/number/1", 1);
+ nvlist_add_number(nvl, "nvlist/number/-1", -1);
+ nvlist_add_number(nvl, "nvlist/number/UINT64_MAX", UINT64_MAX);
+ nvlist_add_number(nvl, "nvlist/number/INT64_MIN", INT64_MIN);
+ nvlist_add_number(nvl, "nvlist/number/INT64_MAX", INT64_MAX);
+ nvlist_add_string(nvl, "nvlist/string/", "");
+ nvlist_add_string(nvl, "nvlist/string/x", "x");
+ nvlist_add_string(nvl, "nvlist/string/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz");
+ nvlist_add_descriptor(nvl, "nvlist/descriptor/STDERR_FILENO", STDERR_FILENO);
+ nvlist_add_binary(nvl, "nvlist/binary/x", "x", 1);
+ nvlist_add_binary(nvl, "nvlist/binary/abcdefghijklmnopqrstuvwxyz", "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz"));
+ nvlist_add_nvlist(nvl, "nvlist/nvlist", nvl);
+
+ nvlist_send(sock, nvl);
+
+ nvlist_destroy(nvl);
+}
+
+static void
+parent(int sock)
+{
+ nvlist_t *nvl;
+ const nvlist_t *cnvl;
+ const char *name, *cname;
+ void *cookie, *ccookie;
+ int type, ctype;
+ size_t size;
+
+ nvl = nvlist_recv(sock);
+ CHECK(nvlist_error(nvl) == 0);
+ if (nvlist_error(nvl) != 0)
+ err(1, "nvlist_recv() failed");
+
+ cookie = NULL;
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BOOL);
+ CHECK(strcmp(name, "nvlist/bool/true") == 0);
+ CHECK(nvlist_get_bool(nvl, name) == true);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BOOL);
+ CHECK(strcmp(name, "nvlist/bool/false") == 0);
+ CHECK(nvlist_get_bool(nvl, name) == false);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(nvl, name) == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/1") == 0);
+ CHECK(nvlist_get_number(nvl, name) == 1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/-1") == 0);
+ CHECK((int)nvlist_get_number(nvl, name) == -1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/UINT64_MAX") == 0);
+ CHECK(nvlist_get_number(nvl, name) == UINT64_MAX);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/INT64_MIN") == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MIN);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NUMBER);
+ CHECK(strcmp(name, "nvlist/number/INT64_MAX") == 0);
+ CHECK((int64_t)nvlist_get_number(nvl, name) == INT64_MAX);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/x") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "x") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_STRING);
+ CHECK(strcmp(name, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(strcmp(nvlist_get_string(nvl, name), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_DESCRIPTOR);
+ CHECK(strcmp(name, "nvlist/descriptor/STDERR_FILENO") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(nvl, name)));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BINARY);
+ CHECK(strcmp(name, "nvlist/binary/x") == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_BINARY);
+ CHECK(strcmp(name, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(nvl, name, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name != NULL);
+ CHECK(type == NV_TYPE_NVLIST);
+ CHECK(strcmp(name, "nvlist/nvlist") == 0);
+ cnvl = nvlist_get_nvlist(nvl, name);
+
+ ccookie = NULL;
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BOOL);
+ CHECK(strcmp(cname, "nvlist/bool/true") == 0);
+ CHECK(nvlist_get_bool(cnvl, cname) == true);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BOOL);
+ CHECK(strcmp(cname, "nvlist/bool/false") == 0);
+ CHECK(nvlist_get_bool(cnvl, cname) == false);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/0") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/1") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == 1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/-1") == 0);
+ CHECK((int)nvlist_get_number(cnvl, cname) == -1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/UINT64_MAX") == 0);
+ CHECK(nvlist_get_number(cnvl, cname) == UINT64_MAX);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/INT64_MIN") == 0);
+ CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MIN);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_NUMBER);
+ CHECK(strcmp(cname, "nvlist/number/INT64_MAX") == 0);
+ CHECK((int64_t)nvlist_get_number(cnvl, cname) == INT64_MAX);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/x") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "x") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_STRING);
+ CHECK(strcmp(cname, "nvlist/string/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(strcmp(nvlist_get_string(cnvl, cname), "abcdefghijklmnopqrstuvwxyz") == 0);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_DESCRIPTOR);
+ CHECK(strcmp(cname, "nvlist/descriptor/STDERR_FILENO") == 0);
+ CHECK(fd_is_valid(nvlist_get_descriptor(cnvl, cname)));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BINARY);
+ CHECK(strcmp(cname, "nvlist/binary/x") == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "x", 1) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "x", 1) == 0);
+ CHECK(size == 1);
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname != NULL);
+ CHECK(ctype == NV_TYPE_BINARY);
+ CHECK(strcmp(cname, "nvlist/binary/abcdefghijklmnopqrstuvwxyz") == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, NULL), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(memcmp(nvlist_get_binary(cnvl, cname, &size), "abcdefghijklmnopqrstuvwxyz", sizeof("abcdefghijklmnopqrstuvwxyz")) == 0);
+ CHECK(size == sizeof("abcdefghijklmnopqrstuvwxyz"));
+
+ cname = nvlist_next(cnvl, &ctype, &ccookie);
+ CHECK(cname == NULL);
+
+ name = nvlist_next(nvl, &type, &cookie);
+ CHECK(name == NULL);
+}
+
+int
+main(void)
+{
+ int status, socks[2];
+ pid_t pid;
+
+ printf("1..126\n");
+ fflush(stdout);
+
+ if (socketpair(PF_UNIX, SOCK_STREAM, 0, socks) < 0)
+ err(1, "socketpair() failed");
+ pid = fork();
+ switch (pid) {
+ case -1:
+ /* Failure. */
+ err(1, "unable to fork");
+ case 0:
+ /* Child. */
+ close(socks[0]);
+ child(socks[1]);
+ return (0);
+ default:
+ /* Parent. */
+ close(socks[1]);
+ parent(socks[0]);
+ break;
+ }
+
+ if (waitpid(pid, &status, 0) < 0)
+ err(1, "waitpid() failed");
+
+ return (0);
+}
diff --git a/lib/libohash/Makefile b/lib/libohash/Makefile
new file mode 100644
index 0000000..198093e
--- /dev/null
+++ b/lib/libohash/Makefile
@@ -0,0 +1,9 @@
+# $FreeBSD$
+
+LIB= ohash
+SRCS= ohash.c
+INTERNALLIB=
+
+WARNS= 3
+
+.include <bsd.lib.mk>
diff --git a/lib/libohash/ohash.c b/lib/libohash/ohash.c
new file mode 100644
index 0000000..3a0f5dd
--- /dev/null
+++ b/lib/libohash/ohash.c
@@ -0,0 +1,330 @@
+/* $OpenBSD: src/lib/libutil/ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
+
+/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include "ohash.h"
+
+struct _ohash_record {
+ uint32_t hv;
+ const char *p;
+};
+
+#define DELETED ((const char *)h)
+#define NONE (h->size)
+
+/* Don't bother changing the hash table if the change is small enough. */
+#define MINSIZE (1UL << 4)
+#define MINDELETED 4
+
+static void ohash_resize(struct ohash *);
+
+
+/* This handles the common case of variable length keys, where the
+ * key is stored at the end of the record.
+ */
+void *
+ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
+{
+ char *p;
+
+ if (!*end)
+ *end = start + strlen(start);
+ p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
+ if (p) {
+ memcpy(p+i->key_offset, start, *end-start);
+ p[i->key_offset + (*end - start)] = '\0';
+ }
+ return (void *)p;
+}
+
+/* hash_delete only frees the hash structure. Use hash_first/hash_next
+ * to free entries as well. */
+void
+ohash_delete(struct ohash *h)
+{
+ (h->info.free)(h->t, h->info.data);
+#ifndef NDEBUG
+ h->t = NULL;
+#endif
+}
+
+static void
+ohash_resize(struct ohash *h)
+{
+ struct _ohash_record *n;
+ size_t ns;
+ unsigned int j;
+ unsigned int i, incr;
+
+ if (4 * h->deleted < h->total) {
+ if (h->size >= (UINT_MAX >> 1U))
+ ns = UINT_MAX;
+ else
+ ns = h->size << 1U;
+ } else if (3 * h->deleted > 2 * h->total)
+ ns = h->size >> 1U;
+ else
+ ns = h->size;
+ if (ns < MINSIZE)
+ ns = MINSIZE;
+#ifdef STATS_HASH
+ STAT_HASH_EXPAND++;
+ STAT_HASH_SIZE += ns - h->size;
+#endif
+
+ n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
+ if (!n)
+ return;
+
+ for (j = 0; j < h->size; j++) {
+ if (h->t[j].p != NULL && h->t[j].p != DELETED) {
+ i = h->t[j].hv % ns;
+ incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
+ while (n[i].p != NULL) {
+ i += incr;
+ if (i >= ns)
+ i -= ns;
+ }
+ n[i].hv = h->t[j].hv;
+ n[i].p = h->t[j].p;
+ }
+ }
+ (h->info.free)(h->t, h->info.data);
+ h->t = n;
+ h->size = ns;
+ h->total -= h->deleted;
+ h->deleted = 0;
+}
+
+void *
+ohash_remove(struct ohash *h, unsigned int i)
+{
+ void *result = (void *)h->t[i].p;
+
+ if (result == NULL || result == DELETED)
+ return NULL;
+
+#ifdef STATS_HASH
+ STAT_HASH_ENTRIES--;
+#endif
+ h->t[i].p = DELETED;
+ h->deleted++;
+ if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
+ ohash_resize(h);
+ return result;
+}
+
+void *
+ohash_find(struct ohash *h, unsigned int i)
+{
+ if (h->t[i].p == DELETED)
+ return NULL;
+ else
+ return (void *)h->t[i].p;
+}
+
+void *
+ohash_insert(struct ohash *h, unsigned int i, void *p)
+{
+#ifdef STATS_HASH
+ STAT_HASH_ENTRIES++;
+#endif
+ if (h->t[i].p == DELETED) {
+ h->deleted--;
+ h->t[i].p = p;
+ } else {
+ h->t[i].p = p;
+ /* Arbitrary resize boundary. Tweak if not efficient enough. */
+ if (++h->total * 4 > h->size * 3)
+ ohash_resize(h);
+ }
+ return p;
+}
+
+unsigned int
+ohash_entries(struct ohash *h)
+{
+ return h->total - h->deleted;
+}
+
+void *
+ohash_first(struct ohash *h, unsigned int *pos)
+{
+ *pos = 0;
+ return ohash_next(h, pos);
+}
+
+void *
+ohash_next(struct ohash *h, unsigned int *pos)
+{
+ for (; *pos < h->size; (*pos)++)
+ if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
+ return (void *)h->t[(*pos)++].p;
+ return NULL;
+}
+
+void
+ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
+{
+ h->size = 1UL << size;
+ if (h->size < MINSIZE)
+ h->size = MINSIZE;
+#ifdef STATS_HASH
+ STAT_HASH_CREATION++;
+ STAT_HASH_SIZE += h->size;
+#endif
+ /* Copy info so that caller may free it. */
+ h->info.key_offset = info->key_offset;
+ h->info.calloc = info->calloc;
+ h->info.free = info->free;
+ h->info.alloc = info->alloc;
+ h->info.data = info->data;
+ h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
+ h->info.data);
+ h->total = h->deleted = 0;
+}
+
+uint32_t
+ohash_interval(const char *s, const char **e)
+{
+ uint32_t k;
+
+ if (!*e)
+ *e = s + strlen(s);
+ if (s == *e)
+ k = 0;
+ else
+ k = *s++;
+ while (s != *e)
+ k = ((k << 2) | (k >> 30)) ^ *s++;
+ return k;
+}
+
+unsigned int
+ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
+ uint32_t hv)
+{
+ unsigned int i, incr;
+ unsigned int empty;
+
+#ifdef STATS_HASH
+ STAT_HASH_LOOKUP++;
+#endif
+ empty = NONE;
+ i = hv % h->size;
+ incr = ((hv % (h->size-2)) & ~1) + 1;
+ while (h->t[i].p != NULL) {
+#ifdef STATS_HASH
+ STAT_HASH_LENGTH++;
+#endif
+ if (h->t[i].p == DELETED) {
+ if (empty == NONE)
+ empty = i;
+ } else if (h->t[i].hv == hv &&
+ strncmp(h->t[i].p+h->info.key_offset, start,
+ end - start) == 0 &&
+ (h->t[i].p+h->info.key_offset)[end-start] == '\0') {
+ if (empty != NONE) {
+ h->t[empty].hv = hv;
+ h->t[empty].p = h->t[i].p;
+ h->t[i].p = DELETED;
+ return empty;
+ } else {
+#ifdef STATS_HASH
+ STAT_HASH_POSITIVE++;
+#endif
+ return i;
+ }
+ }
+ i += incr;
+ if (i >= h->size)
+ i -= h->size;
+ }
+
+ /* Found an empty position. */
+ if (empty != NONE)
+ i = empty;
+ h->t[i].hv = hv;
+ return i;
+}
+
+unsigned int
+ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
+{
+ unsigned int i, incr;
+ unsigned int empty;
+
+#ifdef STATS_HASH
+ STAT_HASH_LOOKUP++;
+#endif
+ empty = NONE;
+ i = hv % h->size;
+ incr = ((hv % (h->size-2)) & ~1) + 1;
+ while (h->t[i].p != NULL) {
+#ifdef STATS_HASH
+ STAT_HASH_LENGTH++;
+#endif
+ if (h->t[i].p == DELETED) {
+ if (empty == NONE)
+ empty = i;
+ } else if (h->t[i].hv == hv &&
+ memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
+ if (empty != NONE) {
+ h->t[empty].hv = hv;
+ h->t[empty].p = h->t[i].p;
+ h->t[i].p = DELETED;
+ return empty;
+ } else {
+#ifdef STATS_HASH
+ STAT_HASH_POSITIVE++;
+#endif
+ } return i;
+ }
+ i += incr;
+ if (i >= h->size)
+ i -= h->size;
+ }
+
+ /* Found an empty position. */
+ if (empty != NONE)
+ i = empty;
+ h->t[i].hv = hv;
+ return i;
+}
+
+unsigned int
+ohash_qlookup(struct ohash *h, const char *s)
+{
+ const char *e = NULL;
+ return ohash_qlookupi(h, s, &e);
+}
+
+unsigned int
+ohash_qlookupi(struct ohash *h, const char *s, const char **e)
+{
+ uint32_t hv;
+
+ hv = ohash_interval(s, e);
+ return ohash_lookup_interval(h, s, *e, hv);
+}
diff --git a/lib/libohash/ohash.h b/lib/libohash/ohash.h
new file mode 100644
index 0000000..03de431
--- /dev/null
+++ b/lib/libohash/ohash.h
@@ -0,0 +1,75 @@
+/* $OpenBSD: src/lib/libutil/ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */
+
+/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef OHASH_H
+#define OHASH_H
+
+/* Open hashing support.
+ * Open hashing was chosen because it is much lighter than other hash
+ * techniques, and more efficient in most cases.
+ */
+
+/* user-visible data structure */
+struct ohash_info {
+ ptrdiff_t key_offset;
+ void *data; /* user data */
+ void *(*calloc)(size_t, size_t, void *);
+ void (*free)(void *, void *);
+ void *(*alloc)(size_t, void *);
+};
+
+struct _ohash_record;
+
+/* private structure. It's there just so you can do a sizeof */
+struct ohash {
+ struct _ohash_record *t;
+ struct ohash_info info;
+ unsigned int size;
+ unsigned int total;
+ unsigned int deleted;
+};
+
+/* For this to be tweakable, we use small primitives, and leave part of the
+ * logic to the client application. e.g., hashing is left to the client
+ * application. We also provide a simple table entry lookup that yields
+ * a hashing table index (opaque) to be used in find/insert/remove.
+ * The keys are stored at a known position in the client data.
+ */
+__BEGIN_DECLS
+void ohash_init(struct ohash *, unsigned, struct ohash_info *);
+void ohash_delete(struct ohash *);
+
+unsigned int ohash_lookup_interval(struct ohash *, const char *,
+ const char *, uint32_t);
+unsigned int ohash_lookup_memory(struct ohash *, const char *,
+ size_t, uint32_t);
+void *ohash_find(struct ohash *, unsigned int);
+void *ohash_remove(struct ohash *, unsigned int);
+void *ohash_insert(struct ohash *, unsigned int, void *);
+void *ohash_first(struct ohash *, unsigned int *);
+void *ohash_next(struct ohash *, unsigned int *);
+unsigned int ohash_entries(struct ohash *);
+
+void *ohash_create_entry(struct ohash_info *, const char *, const char **);
+uint32_t ohash_interval(const char *, const char **);
+
+unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
+unsigned int ohash_qlookup(struct ohash *, const char *);
+__END_DECLS
+#endif
diff --git a/lib/libohash/ohash_init.3 b/lib/libohash/ohash_init.3
new file mode 100644
index 0000000..184c4e3
--- /dev/null
+++ b/lib/libohash/ohash_init.3
@@ -0,0 +1,273 @@
+.\" $OpenBSD: ohash_init.3,v 1.2 2014/05/13 14:01:41 jmc Exp $
+.\" Copyright (c) 1999 Marc Espie <espie@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd May 12, 2014
+.Dt OHASH_INIT 3
+.Os
+.Sh NAME
+.Nm ohash_init ,
+.Nm ohash_delete ,
+.Nm ohash_lookup_interval ,
+.Nm ohash_lookup_memory ,
+.Nm ohash_find ,
+.Nm ohash_remove ,
+.Nm ohash_insert ,
+.Nm ohash_first ,
+.Nm ohash_next ,
+.Nm ohash_entries
+.Nd light-weight open hashing
+.Sh SYNOPSIS
+.In stdint.h
+.In stddef.h
+.In ohash.h
+.Ft void
+.Fn ohash_init "struct ohash *h" "unsigned int size" "struct ohash_info *info"
+.Ft void
+.Fn ohash_delete "struct ohash *h"
+.Ft "unsigned int"
+.Fn ohash_lookup_interval "struct ohash *h" "const char *start" "const char *end" "uint32_t hv"
+.Ft "unsigned int"
+.Fn ohash_lookup_memory "struct ohash *h" "const char *k" "size_t s" "uint32_t hv"
+.Ft void *
+.Fn ohash_find "struct ohash *h" "unsigned int i"
+.Ft void *
+.Fn ohash_remove "struct ohash *h" "unsigned int i"
+.Ft void *
+.Fn ohash_insert "struct ohash *h" "unsigned int i" "void *p"
+.Ft void *
+.Fn ohash_first "struct ohash *h" "unsigned int *i"
+.Ft void *
+.Fn ohash_next "struct ohash *h" "unsigned int *i"
+.Ft "unsigned int"
+.Fn ohash_entries "struct ohash *h"
+.Sh DESCRIPTION
+These functions have been designed as a fast, extensible alternative to
+the usual hash table functions.
+They provide storage and retrieval of records indexed by keys,
+where a key is a contiguous sequence of bytes at a fixed position in
+each record.
+Keys can either be NUL-terminated strings or fixed-size memory areas.
+All functions take a pointer to an ohash structure as the
+.Fa h
+function argument.
+Storage for this structure should be provided by user code.
+.Pp
+.Fn ohash_init
+initializes the table to store roughly 2 to the power
+.Fa size
+elements.
+.Fa info
+is a pointer to a
+.Fa struct ohash_info .
+.Bd -literal -offset indent
+struct ohash_info {
+ ptrdiff_t key_offset;
+ void *data; /* user data */
+ void *(*calloc)(size_t, size_t, void *);
+ void (*free)(void *, void *);
+ void *(*alloc)(size_t, void *);
+};
+.Ed
+.Pp
+The
+.Va offset
+field holds the position of the key in each record;
+the
+.Va calloc
+and
+.Va free
+fields are pointers to
+.Xr calloc 3
+and
+.Xr free 3 Ns -like
+functions, used for managing the table internal storage;
+the
+.Va alloc
+field is only used by the utility function
+.Xr ohash_create_entry 3 .
+.Pp
+Each of these functions are called similarly to their standard counterpart,
+but with an extra
+.Ft void *
+parameter corresponding to the content of the field
+.Fa data ,
+which can be used to communicate specific information to the functions.
+.Pp
+.Fn ohash_init
+stores a copy of those fields internally, so
+.Fa info
+can be reclaimed after initialization.
+.Pp
+.Fn ohash_delete
+frees storage internal to
+.Fa h .
+Elements themselves should be freed by the user first, using for instance
+.Fn ohash_first
+and
+.Fn ohash_next .
+.Pp
+.Fn ohash_lookup_interval
+and
+.Fn ohash_lookup_memory
+are the basic look-up element functions.
+The hashing function result is provided by the user as
+.Fa hv .
+These return a
+.Qq slot
+in the ohash table
+.Fa h ,
+to be used with
+.Fn ohash_find ,
+.Fn ohash_insert ,
+or
+.Fn ohash_remove .
+This slot is only valid up to the next call to
+.Fn ohash_insert
+or
+.Fn ohash_remove .
+.Pp
+.Fn ohash_lookup_interval
+handles string-like keys.
+.Fn ohash_lookup_interval
+assumes the key is the interval between
+.Fa start
+and
+.Fa end ,
+exclusive,
+though the actual elements stored in the table should only contain
+NUL-terminated keys.
+.Pp
+.Fn ohash_lookup_memory
+assumes the key is the memory area starting at
+.Fa k
+of size
+.Fa s .
+All bytes are significant in key comparison.
+.Pp
+.Fn ohash_find
+retrieves an element from a slot
+.Fa i
+returned by the
+.Fn ohash_lookup*
+functions.
+It returns
+.Dv NULL
+if the slot is empty.
+.Pp
+.Fn ohash_insert
+inserts a new element
+.Fa p
+at slot
+.Fa i .
+Slot
+.Fa i
+must be empty and element
+.Fa p
+must have a key corresponding to the
+.Fn ohash_lookup*
+call.
+.Pp
+.Fn ohash_remove
+removes the element at slot
+.Fa i .
+It returns the removed element, for user code to dispose of, or
+.Dv NULL
+if the slot was empty.
+.Pp
+.Fn ohash_first
+and
+.Fn ohash_next
+can be used to access all elements in an ohash table, like this:
+.Bd -literal -offset indent
+for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i))
+ do_something_with(n);
+.Ed
+.Pp
+.Fa i
+points to an auxiliary unsigned integer used to record the current position
+in the ohash table.
+Those functions are safe to use even while entries are added to/removed
+from the table, but in such a case they don't guarantee that new entries
+will be returned.
+As a special case, they can safely be used to free elements in the table.
+.Pp
+.Fn ohash_entries
+returns the number of elements in the hash table.
+.Sh STORAGE HANDLING
+Only
+.Fn ohash_init ,
+.Fn ohash_insert ,
+.Fn ohash_remove
+and
+.Fn ohash_delete
+may call the user-supplied memory functions:
+.Bd -literal -offset indent
+p = (*info->calloc)(n, sizeof_record, info->data);
+/* copy data from old to p */
+(*info->free)(old, info->data);
+.Ed
+.Pp
+It is the responsibility of the user memory allocation code to verify
+that those calls did not fail.
+.Pp
+If memory allocation fails,
+.Fn ohash_init
+returns a useless hash table.
+.Fn ohash_insert
+and
+.Fn ohash_remove
+still perform the requested operation, but the returned table should be
+considered read-only.
+It can still be accessed by
+.Fn ohash_lookup* ,
+.Fn ohash_find ,
+.Fn ohash_first
+and
+.Fn ohash_next
+to dump relevant information to disk before aborting.
+.Sh THREAD SAFETY
+The open hashing functions are not thread-safe by design.
+In particular, in a threaded environment, there is no guarantee that a
+.Qq slot
+will not move between a
+.Fn ohash_lookup*
+and a
+.Fn ohash_find ,
+.Fn ohash_insert
+or
+.Fn ohash_remove
+call.
+.Pp
+Multi-threaded applications should explicitly protect ohash table access.
+.Sh SEE ALSO
+.Xr hcreate 3 ,
+.Xr ohash_interval 3
+.Rs
+.%A Donald E. Knuth
+.%B The Art of Computer Programming
+.%V Vol. 3
+.%P pp 506-550
+.%D 1973
+.Re
+.Sh STANDARDS
+Those functions are completely non-standard and should be avoided in
+portable programs.
+.Sh HISTORY
+Those functions were designed and written for
+.Ox
+.Xr make 1
+by Marc Espie in 1999.
diff --git a/lib/libohash/ohash_interval.3 b/lib/libohash/ohash_interval.3
new file mode 100644
index 0000000..3809c34
--- /dev/null
+++ b/lib/libohash/ohash_interval.3
@@ -0,0 +1,95 @@
+.\" $OpenBSD: ohash_interval.3,v 1.1 2014/05/12 19:09:00 espie Exp $
+.\" Copyright (c) 2001 Marc Espie <espie@openbsd.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd June 5, 2013
+.Dt OHASH_INTERVAL 3
+.Os
+.Sh NAME
+.Nm ohash_interval ,
+.Nm ohash_create_entry ,
+.Nm ohash_qlookup ,
+.Nm ohash_qlookupi
+.Nd helper functions for open hashing
+.Sh SYNOPSIS
+.In stdint.h
+.In stddef.h
+.In ohash.h
+.Ft uint32_t
+.Fn ohash_interval "const char *start" "const char **pend"
+.Ft "void *"
+.Fn ohash_create_entry "struct ohash_info *info" "const char *start" "const char **pend"
+.Ft "unsigned int"
+.Fn ohash_qlookupi "struct ohash *h" "const char *start" "const char **pend"
+.Ft "unsigned int"
+.Fn ohash_qlookup "struct ohash *h" "const char *start"
+.Sh DESCRIPTION
+These functions are commonly used to simplify open hashing usage, and use
+similar conventions.
+They operate indifferently on NUL-terminated strings
+.Po
+by setting
+.Fa *pend
+=
+.Dv NULL
+.Pc
+or memory ranges
+.Po
+delimited by
+.Fa start
+and
+.Fa *pend
+.Pc .
+For NUL-terminated strings, as a side effect, those functions
+set
+.Fa *pend
+to the terminating NUL byte.
+.Pp
+.Fn ohash_interval
+is a simple hashing function that yields good results on common data sets.
+.Pp
+.Fn ohash_create_entry
+can be used to create a new record with a given key.
+In that case,
+the alloc field of
+.Fa info
+should point to a
+.Xr malloc 3 Ns -like
+function to allocate the storage:
+.Bd -literal -offset indent
+p = (*info->alloc)(sz, info->data);
+.Ed
+.Pp
+.Fn ohash_qlookupi
+is a wrapper function that simply calls
+.Fn ohash_interval
+and
+.Fn ohash_lookup_interval .
+.Pp
+.Fn ohash_qlookup
+is a variation on
+.Fn ohash_qlookupi
+designed for NUL-terminated strings.
+.Sh SEE ALSO
+.Xr ohash_init 3
+.Sh STANDARDS
+Those functions are completely non-standard and should be avoided in
+portable programs.
+.Sh HISTORY
+Those functions were designed and written for
+.Ox
+.Xr make 1
+by Marc Espie in 1999.
diff --git a/lib/libopie/Makefile b/lib/libopie/Makefile
index 647bfee..e47e16d 100644
--- a/lib/libopie/Makefile
+++ b/lib/libopie/Makefile
@@ -4,7 +4,7 @@
#
OPIE_DIST?= ${.CURDIR}/../../contrib/opie
DIST_DIR= ${OPIE_DIST}/${.CURDIR:T}
-SHLIB_MAJOR= 7
+SHLIB_MAJOR= 8
KEYFILE?= \"/etc/opiekeys\"
diff --git a/lib/libpam/libpam/Makefile b/lib/libpam/libpam/Makefile
index a654cf7..7a425e0 100644
--- a/lib/libpam/libpam/Makefile
+++ b/lib/libpam/libpam/Makefile
@@ -66,6 +66,7 @@ SRCS= openpam_asprintf.c \
openpam_straddch.c \
openpam_strlcat.c \
openpam_strlcpy.c \
+ openpam_strlset.c \
openpam_subst.c \
openpam_ttyconv.c \
openpam_vasprintf.c \
@@ -175,4 +176,8 @@ ADD_HEADERS= security/pam_mod_misc.h
INCS= ${HEADERS} ${ADD_HEADERS}
INCSDIR= ${INCLUDEDIR}/security
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libpam/libpam/tests/Makefile b/lib/libpam/libpam/tests/Makefile
new file mode 100644
index 0000000..2ad64e2
--- /dev/null
+++ b/lib/libpam/libpam/tests/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+OPENPAM = ${.CURDIR}/../../../../contrib/openpam
+.PATH: ${OPENPAM}/t
+
+TESTSDIR = ${TESTSBASE}/lib/libpam
+
+COMMONSRC = t_file.c t_main.c
+.for test in t_openpam_ctype t_openpam_readlinev t_openpam_readword
+TAP_TESTS_C += ${test}
+SRCS.${test} = ${test}.c ${COMMONSRC}
+.endfor
+CFLAGS +=-I${OPENPAM}/include -I${OPENPAM}/lib/libpam -I${OPENPAM}/t
+WARNS ?= 6
+
+DPADD = ${LIBPAM}
+LDADD = ${MINUSLPAM}
+
+.include <bsd.test.mk>
diff --git a/lib/libpam/modules/pam_login_access/pam_login_access.c b/lib/libpam/modules/pam_login_access/pam_login_access.c
index 945d5eb..fe16662 100644
--- a/lib/libpam/modules/pam_login_access/pam_login_access.c
+++ b/lib/libpam/modules/pam_login_access/pam_login_access.c
@@ -79,20 +79,27 @@ pam_sm_acct_mgmt(pam_handle_t *pamh, int flags __unused,
gethostname(hostname, sizeof hostname);
- if (rhost == NULL || *(const char *)rhost == '\0') {
+ if (rhost != NULL && *(const char *)rhost != '\0') {
+ PAM_LOG("Checking login.access for user %s from host %s",
+ (const char *)user, (const char *)rhost);
+ if (login_access(user, rhost) != 0)
+ return (PAM_SUCCESS);
+ PAM_VERBOSE_ERROR("%s is not allowed to log in from %s",
+ (const char *)user, (const char *)rhost);
+ } else if (tty != NULL && *(const char *)tty != '\0') {
PAM_LOG("Checking login.access for user %s on tty %s",
(const char *)user, (const char *)tty);
if (login_access(user, tty) != 0)
return (PAM_SUCCESS);
PAM_VERBOSE_ERROR("%s is not allowed to log in on %s",
- user, tty);
+ (const char *)user, (const char *)tty);
} else {
- PAM_LOG("Checking login.access for user %s from host %s",
- (const char *)user, (const char *)rhost);
- if (login_access(user, rhost) != 0)
+ PAM_LOG("Checking login.access for user %s",
+ (const char *)user);
+ if (login_access(user, "***unknown***") != 0)
return (PAM_SUCCESS);
- PAM_VERBOSE_ERROR("%s is not allowed to log in from %s",
- user, rhost);
+ PAM_VERBOSE_ERROR("%s is not allowed to log in",
+ (const char *)user);
}
return (PAM_AUTH_ERR);
diff --git a/lib/libpam/modules/pam_opie/pam_opie.c b/lib/libpam/modules/pam_opie/pam_opie.c
index bfb875f..9625373 100644
--- a/lib/libpam/modules/pam_opie/pam_opie.c
+++ b/lib/libpam/modules/pam_opie/pam_opie.c
@@ -62,7 +62,7 @@ pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
struct passwd *pwd;
int retval, i;
const char *(promptstr[]) = { "%s\nPassword: ", "%s\nPassword [echo on]: "};
- char challenge[OPIE_CHALLENGE_MAX];
+ char challenge[OPIE_CHALLENGE_MAX + 1];
char principal[OPIE_PRINCIPAL_MAX];
const char *user;
char *response;
diff --git a/lib/libpam/modules/pam_ssh/Makefile b/lib/libpam/modules/pam_ssh/Makefile
index 886610a..5643f32 100644
--- a/lib/libpam/modules/pam_ssh/Makefile
+++ b/lib/libpam/modules/pam_ssh/Makefile
@@ -14,7 +14,7 @@ WARNS?= 3
CFLAGS+= -I${SSHDIR} -include ssh_namespace.h
DPADD= ${LIBSSH} ${LIBCRYPTO} ${LIBCRYPT}
-LDADD= -lssh -lcrypto -lcrypt
+LDADD= ${LDSSH} -lcrypto -lcrypt
USEPRIVATELIB= ssh
.include <bsd.lib.mk>
diff --git a/lib/libpcap/Makefile b/lib/libpcap/Makefile
index 8cae1f1..11d7f73 100644
--- a/lib/libpcap/Makefile
+++ b/lib/libpcap/Makefile
@@ -7,6 +7,7 @@ SHLIBDIR?= /lib
LIB= pcap
SRCS= grammar.y tokdefs.h version.h pcap-bpf.c \
+ pcap-netmap.c \
pcap.c pcap-common.c inet.c fad-getad.c gencode.c optimize.c nametoaddr.c \
etherent.c savefile.c bpf_filter.c bpf_image.c bpf_dump.c \
scanner.l sf-pcap.c sf-pcap-ng.c version.c
diff --git a/lib/libpcap/config.h b/lib/libpcap/config.h
index 79cb3d2..60cb448 100644
--- a/lib/libpcap/config.h
+++ b/lib/libpcap/config.h
@@ -271,6 +271,9 @@
/* target host supports USB sniffing */
/* #undef PCAP_SUPPORT_USB */
+/* target host supports netmap */
+#define PCAP_SUPPORT_NETMAP 1
+
/* include ACN support */
/* #undef SITA */
diff --git a/lib/libpcap/pcap-netmap.c b/lib/libpcap/pcap-netmap.c
new file mode 100644
index 0000000..309cf63
--- /dev/null
+++ b/lib/libpcap/pcap-netmap.c
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2014 Luigi Rizzo. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS''AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <poll.h>
+#include <ctype.h>
+#include <errno.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define NETMAP_WITH_LIBS
+#include <net/netmap_user.h>
+
+#include "pcap-int.h"
+
+/*
+ * $FreeBSD$
+ *
+ * This code is meant to build also on other versions of libpcap.
+ *
+ * older libpcap miss p->priv, use p->md.device instead (and allocate).
+ * Also opt.timeout was in md.timeout before.
+ * Use #define PCAP_IF_UP to discriminate
+ */
+#ifdef PCAP_IF_UP
+#define NM_PRIV(p) ((struct pcap_netmap *)(p->priv))
+#define the_timeout opt.timeout
+#else
+#define HAVE_NO_PRIV
+#define NM_PRIV(p) ((struct pcap_netmap *)(p->md.device))
+#define SET_PRIV(p, x) p->md.device = (void *)x
+#define the_timeout md.timeout
+#endif
+
+#if defined (linux)
+/* On FreeBSD we use IFF_PPROMISC which is in ifr_flagshigh.
+ * remap to IFF_PROMISC on linux
+ */
+#define IFF_PPROMISC IFF_PROMISC
+#endif /* linux */
+
+struct pcap_netmap {
+ struct nm_desc *d; /* pointer returned by nm_open() */
+ pcap_handler cb; /* callback and argument */
+ u_char *cb_arg;
+ int must_clear_promisc; /* flag */
+ uint64_t rx_pkts; /* # of pkts received before the filter */
+};
+
+
+static int
+pcap_netmap_stats(pcap_t *p, struct pcap_stat *ps)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+
+ ps->ps_recv = pn->rx_pkts;
+ ps->ps_drop = 0;
+ ps->ps_ifdrop = 0;
+ return 0;
+}
+
+
+static void
+pcap_netmap_filter(u_char *arg, struct pcap_pkthdr *h, const u_char *buf)
+{
+ pcap_t *p = (pcap_t *)arg;
+ struct pcap_netmap *pn = NM_PRIV(p);
+ const struct bpf_insn *pc = p->fcode.bf_insns;
+
+ ++pn->rx_pkts;
+ if (pc == NULL || bpf_filter(pc, buf, h->len, h->caplen))
+ pn->cb(pn->cb_arg, h, buf);
+}
+
+
+static int
+pcap_netmap_dispatch(pcap_t *p, int cnt, pcap_handler cb, u_char *user)
+{
+ int ret;
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = pn->d;
+ struct pollfd pfd = { .fd = p->fd, .events = POLLIN, .revents = 0 };
+
+ pn->cb = cb;
+ pn->cb_arg = user;
+
+ for (;;) {
+ if (p->break_loop) {
+ p->break_loop = 0;
+ return PCAP_ERROR_BREAK;
+ }
+ /* nm_dispatch won't run forever */
+
+ ret = nm_dispatch((void *)d, cnt, (void *)pcap_netmap_filter, (void *)p);
+ if (ret != 0)
+ break;
+ errno = 0;
+ ret = poll(&pfd, 1, p->the_timeout);
+ }
+ return ret;
+}
+
+
+/* XXX need to check the NIOCTXSYNC/poll */
+static int
+pcap_netmap_inject(pcap_t *p, const void *buf, size_t size)
+{
+ struct nm_desc *d = NM_PRIV(p)->d;
+
+ return nm_inject(d, buf, size);
+}
+
+
+static int
+pcap_netmap_ioctl(pcap_t *p, u_long what, uint32_t *if_flags)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = pn->d;
+ struct ifreq ifr;
+ int error, fd = d->fd;
+
+#ifdef linux
+ fd = socket(AF_INET, SOCK_DGRAM, 0);
+ if (fd < 0) {
+ fprintf(stderr, "Error: cannot get device control socket.\n");
+ return -1;
+ }
+#endif /* linux */
+ bzero(&ifr, sizeof(ifr));
+ strncpy(ifr.ifr_name, d->req.nr_name, sizeof(ifr.ifr_name));
+ switch (what) {
+ case SIOCSIFFLAGS:
+ ifr.ifr_flags = *if_flags;
+#ifdef __FreeBSD__
+ ifr.ifr_flagshigh = *if_flags >> 16;
+#endif /* __FreeBSD__ */
+ break;
+ }
+ error = ioctl(fd, what, &ifr);
+ if (!error) {
+ switch (what) {
+ case SIOCGIFFLAGS:
+ *if_flags = ifr.ifr_flags;
+#ifdef __FreeBSD__
+ *if_flags |= (ifr.ifr_flagshigh << 16);
+#endif /* __FreeBSD__ */
+ }
+ }
+#ifdef linux
+ close(fd);
+#endif /* linux */
+ return error ? -1 : 0;
+}
+
+
+static void
+pcap_netmap_close(pcap_t *p)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = pn->d;
+ uint32_t if_flags = 0;
+
+ if (pn->must_clear_promisc) {
+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
+ if (if_flags & IFF_PPROMISC) {
+ if_flags &= ~IFF_PPROMISC;
+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
+ }
+ }
+ nm_close(d);
+#ifdef HAVE_NO_PRIV
+ free(pn);
+ SET_PRIV(p, NULL); // unnecessary
+#endif
+ pcap_cleanup_live_common(p);
+}
+
+
+static int
+pcap_netmap_activate(pcap_t *p)
+{
+ struct pcap_netmap *pn = NM_PRIV(p);
+ struct nm_desc *d = nm_open(p->opt.source, NULL, 0, NULL);
+ uint32_t if_flags = 0;
+
+ if (d == NULL) {
+ snprintf(p->errbuf, PCAP_ERRBUF_SIZE,
+ "netmap open: cannot access %s: %s\n",
+ p->opt.source, pcap_strerror(errno));
+#ifdef HAVE_NO_PRIV
+ free(pn);
+ SET_PRIV(p, NULL); // unnecessary
+#endif
+ pcap_cleanup_live_common(p);
+ return (PCAP_ERROR);
+ }
+ if (0)
+ fprintf(stderr, "%s device %s priv %p fd %d ports %d..%d\n",
+ __FUNCTION__, p->opt.source, d, d->fd,
+ d->first_rx_ring, d->last_rx_ring);
+ pn->d = d;
+ p->fd = d->fd;
+ if (p->opt.promisc && !(d->req.nr_ringid & NETMAP_SW_RING)) {
+ pcap_netmap_ioctl(p, SIOCGIFFLAGS, &if_flags); /* fetch flags */
+ if (!(if_flags & IFF_PPROMISC)) {
+ pn->must_clear_promisc = 1;
+ if_flags |= IFF_PPROMISC;
+ pcap_netmap_ioctl(p, SIOCSIFFLAGS, &if_flags);
+ }
+ }
+ p->linktype = DLT_EN10MB;
+ p->selectable_fd = p->fd;
+ p->read_op = pcap_netmap_dispatch;
+ p->inject_op = pcap_netmap_inject,
+ p->setfilter_op = install_bpf_program;
+ p->setdirection_op = NULL;
+ p->set_datalink_op = NULL;
+ p->getnonblock_op = pcap_getnonblock_fd;
+ p->setnonblock_op = pcap_setnonblock_fd;
+ p->stats_op = pcap_netmap_stats;
+ p->cleanup_op = pcap_netmap_close;
+
+ return (0);
+}
+
+
+pcap_t *
+pcap_netmap_create(const char *device, char *ebuf, int *is_ours)
+{
+ pcap_t *p;
+
+ *is_ours = (!strncmp(device, "netmap:", 7) || !strncmp(device, "vale", 4));
+ if (! *is_ours)
+ return NULL;
+#ifdef HAVE_NO_PRIV
+ {
+ void *pn = calloc(1, sizeof(struct pcap_netmap));
+ if (pn == NULL)
+ return NULL;
+ p = pcap_create_common(device, ebuf);
+ if (p == NULL) {
+ free(pn);
+ return NULL;
+ }
+ SET_PRIV(p, pn);
+ }
+#else
+ p = pcap_create_common(device, ebuf, sizeof (struct pcap_netmap));
+ if (p == NULL)
+ return (NULL);
+#endif
+ p->activate_op = pcap_netmap_activate;
+ return (p);
+}
diff --git a/lib/libproc/Makefile b/lib/libproc/Makefile
index 5e5babf..bfb9492 100644
--- a/lib/libproc/Makefile
+++ b/lib/libproc/Makefile
@@ -27,8 +27,23 @@ LDADD+= -lsupc++
DPADD+= ${LIBSTDCPLUSPLUS}
.endif
-SHLIB_MAJOR= 2
+.if ${MK_CDDL} != "no"
+LDADD+= -lctf
+DPADD+= ${LIBCTF}
+IGNORE_PRAGMA= YES
+CFLAGS+= -I${.CURDIR}/../../cddl/contrib/opensolaris/lib/libctf/common \
+ -I${.CURDIR}/../../sys/cddl/contrib/opensolaris/uts/common \
+ -I${.CURDIR}/../../sys/cddl/compat/opensolaris
+.else
+CFLAGS+= -DNO_CTF
+.endif
+
+SHLIB_MAJOR= 3
MAN=
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libproc/libproc.h b/lib/libproc/libproc.h
index be77e4b..5d81c2b 100644
--- a/lib/libproc/libproc.h
+++ b/lib/libproc/libproc.h
@@ -37,6 +37,7 @@
#include <rtld_db.h>
#include <limits.h>
+struct ctf_file;
struct proc_handle;
typedef void (*proc_child_func)(void *);
@@ -67,6 +68,11 @@ typedef struct prmap {
#define MA_NOCOREDUMP 0x20
} prmap_t;
+typedef struct prsyminfo {
+ u_int prs_lmid; /* Map id. */
+ u_int prs_id; /* Symbol id. */
+} prsyminfo_t;
+
typedef int proc_map_f(void *, const prmap_t *, const char *);
typedef int proc_sym_f(void *, const GElf_Sym *, const char *);
@@ -125,7 +131,9 @@ int proc_create(const char *, char * const *, proc_child_func *, void *,
struct proc_handle **);
int proc_detach(struct proc_handle *, int);
int proc_getflags(struct proc_handle *);
-int proc_name2sym(struct proc_handle *, const char *, const char *, GElf_Sym *);
+int proc_name2sym(struct proc_handle *, const char *, const char *,
+ GElf_Sym *, prsyminfo_t *);
+struct ctf_file *proc_name2ctf(struct proc_handle *, const char *);
int proc_setflags(struct proc_handle *, int);
int proc_state(struct proc_handle *);
pid_t proc_getpid(struct proc_handle *);
@@ -133,8 +141,7 @@ int proc_wstatus(struct proc_handle *);
int proc_getwstat(struct proc_handle *);
char * proc_signame(int, char *, size_t);
int proc_read(struct proc_handle *, void *, size_t, size_t);
-const lwpstatus_t *
- proc_getlwpstatus(struct proc_handle *);
+const lwpstatus_t *proc_getlwpstatus(struct proc_handle *);
void proc_free(struct proc_handle *);
rd_agent_t *proc_rdagent(struct proc_handle *);
void proc_updatesyms(struct proc_handle *);
diff --git a/lib/libproc/proc_sym.c b/lib/libproc/proc_sym.c
index 4d60043..766ff73 100644
--- a/lib/libproc/proc_sym.c
+++ b/lib/libproc/proc_sym.c
@@ -26,26 +26,37 @@
* LIABILITY, OR TORT (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$
*/
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
#include <sys/types.h>
+#ifndef NO_CTF
+#include <sys/ctf.h>
+#include <sys/ctf_api.h>
+#endif
#include <sys/user.h>
#include <assert.h>
#include <err.h>
-#include <stdio.h>
+#include <fcntl.h>
#include <libgen.h>
-#include <string.h>
+#include <stdio.h>
#include <stdlib.h>
-#include <fcntl.h>
#include <string.h>
#include <unistd.h>
+#ifndef NO_CTF
+#include <libctf.h>
+#endif
#include <libutil.h>
#include "_libproc.h"
+#ifdef NO_CTF
+typedef struct ctf_file ctf_file_t;
+#endif
+
#ifndef NO_CXA_DEMANGLE
extern char *__cxa_demangle(const char *, char *, size_t *, int *);
#endif /* NO_CXA_DEMANGLE */
@@ -57,21 +68,15 @@ demangle(const char *symbol, char *buf, size_t len)
{
#ifndef NO_CXA_DEMANGLE
char *dembuf;
- size_t demlen;
if (symbol[0] == '_' && symbol[1] == 'Z' && symbol[2]) {
- dembuf = malloc(len);
- if (!dembuf)
- goto fail;
- demlen = len;
- dembuf = __cxa_demangle(symbol, dembuf, &demlen, NULL);
+ dembuf = __cxa_demangle(symbol, NULL, NULL, NULL);
if (!dembuf)
goto fail;
strlcpy(buf, dembuf, len);
free(dembuf);
+ return;
}
-
- return;
fail:
#endif /* NO_CXA_DEMANGLE */
strlcpy(buf, symbol, len);
@@ -127,10 +132,12 @@ proc_obj2map(struct proc_handle *p, const char *objname)
break;
}
}
- if (rdl == NULL && strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
- rdl = p->rdexec;
- else
- return (NULL);
+ if (rdl == NULL) {
+ if (strcmp(objname, "a.out") == 0 && p->rdexec != NULL)
+ rdl = p->rdexec;
+ else
+ return (NULL);
+ }
if ((map = malloc(sizeof(*map))) == NULL)
return (NULL);
@@ -232,22 +239,56 @@ proc_addr2map(struct proc_handle *p, uintptr_t addr)
return (NULL);
}
+/*
+ * Look up the symbol at addr, returning a copy of the symbol and its name.
+ */
+static int
+lookup_addr(Elf *e, Elf_Scn *scn, u_long stridx, uintptr_t off, uintptr_t addr,
+ const char **name, GElf_Sym *symcopy)
+{
+ GElf_Sym sym;
+ Elf_Data *data;
+ const char *s;
+ uint64_t rsym;
+ int i;
+
+ if ((data = elf_getdata(scn, NULL)) == NULL) {
+ DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
+ return (1);
+ }
+ for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
+ rsym = off + sym.st_value;
+ if (addr >= rsym && addr < rsym + sym.st_size) {
+ s = elf_strptr(e, stridx, sym.st_name);
+ if (s != NULL) {
+ *name = s;
+ memcpy(symcopy, &sym, sizeof(*symcopy));
+ /*
+ * DTrace expects the st_value to contain
+ * only the address relative to the start of
+ * the function.
+ */
+ symcopy->st_value = rsym;
+ return (0);
+ }
+ }
+ }
+ return (1);
+}
+
int
proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
size_t namesz, GElf_Sym *symcopy)
{
+ GElf_Ehdr ehdr;
+ GElf_Shdr shdr;
Elf *e;
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
- Elf_Data *data;
- GElf_Shdr shdr;
- GElf_Sym sym;
- GElf_Ehdr ehdr;
- int fd, error = -1;
- size_t i;
- uint64_t rsym;
prmap_t *map;
- char *s;
- unsigned long symtabstridx = 0, dynsymstridx = 0;
+ const char *s;
+ uintptr_t off;
+ u_long symtabstridx = 0, dynsymstridx = 0;
+ int fd, error = -1;
if ((map = proc_addr2map(p, addr)) == NULL)
return (-1);
@@ -263,6 +304,7 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
DPRINTFX("ERROR: gelf_getehdr() failed: %s", elf_errmsg(-1));
goto err2;
}
+
/*
* Find the index of the STRTAB and SYMTAB sections to locate
* symbol names.
@@ -279,80 +321,25 @@ proc_addr2sym(struct proc_handle *p, uintptr_t addr, char *name,
dynsymscn = scn;
dynsymstridx = shdr.sh_link;
break;
- default:
- break;
- }
- }
- /*
- * Iterate over the Dynamic Symbols table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
- */
- if ((data = elf_getdata(dynsymscn, NULL)) == NULL) {
- DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
- goto symtab;
- }
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- /*
- * Calculate the address mapped to the virtual memory
- * by rtld.
- */
- if (ehdr.e_type != ET_EXEC)
- rsym = map->pr_vaddr + sym.st_value;
- else
- rsym = sym.st_value;
- if (addr >= rsym && addr < rsym + sym.st_size) {
- s = elf_strptr(e, dynsymstridx, sym.st_name);
- if (s) {
- demangle(s, name, namesz);
- memcpy(symcopy, &sym, sizeof(sym));
- /*
- * DTrace expects the st_value to contain
- * only the address relative to the start of
- * the function.
- */
- symcopy->st_value = rsym;
- error = 0;
- goto out;
- }
}
}
-symtab:
+
+ off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
+
/*
- * Iterate over the Symbols Table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
+ * First look up the symbol in the dynsymtab, and fall back to the
+ * symtab if the lookup fails.
*/
- if ((data = elf_getdata(symtabscn, NULL)) == NULL) {
- DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
- goto err2;
- }
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- /*
- * Calculate the address mapped to the virtual memory
- * by rtld.
- */
- if (ehdr.e_type != ET_EXEC)
- rsym = map->pr_vaddr + sym.st_value;
- else
- rsym = sym.st_value;
- if (addr >= rsym && addr < rsym + sym.st_size) {
- s = elf_strptr(e, symtabstridx, sym.st_name);
- if (s) {
- demangle(s, name, namesz);
- memcpy(symcopy, &sym, sizeof(sym));
- /*
- * DTrace expects the st_value to contain
- * only the address relative to the start of
- * the function.
- */
- symcopy->st_value = rsym;
- error = 0;
- goto out;
- }
- }
- }
+ error = lookup_addr(e, dynsymscn, dynsymstridx, off, addr, &s, symcopy);
+ if (error == 0)
+ goto out;
+
+ error = lookup_addr(e, symtabscn, symtabstridx, off, addr, &s, symcopy);
+ if (error == 0)
+ goto out;
+
out:
+ demangle(s, name, namesz);
err2:
elf_end(e);
err1:
@@ -367,7 +354,7 @@ proc_name2map(struct proc_handle *p, const char *name)
{
size_t i;
int cnt;
- prmap_t *map;
+ prmap_t *map = NULL;
char tmppath[MAXPATHLEN];
struct kinfo_vmentry *kves, *kve;
rd_loadobj_t *rdl;
@@ -386,47 +373,68 @@ proc_name2map(struct proc_handle *p, const char *name)
basename_r(kve->kve_path, tmppath);
if (strcmp(tmppath, name) == 0) {
map = proc_addr2map(p, kve->kve_start);
- free(kves);
- return (map);
+ break;
}
}
free(kves);
- return (NULL);
- }
- if ((name == NULL || strcmp(name, "a.out") == 0) &&
- p->rdexec != NULL) {
+ } else
+ for (i = 0; i < p->nobjs; i++) {
+ rdl = &p->rdobjs[i];
+ basename_r(rdl->rdl_path, tmppath);
+ if (strcmp(tmppath, name) == 0) {
+ if ((map = malloc(sizeof(*map))) == NULL)
+ return (NULL);
+ proc_rdl2prmap(rdl, map);
+ break;
+ }
+ }
+
+ if (map == NULL && strcmp(name, "a.out") == 0 && p->rdexec != NULL)
map = proc_addr2map(p, p->rdexec->rdl_saddr);
- return (map);
+
+ return (map);
+}
+
+/*
+ * Look up the symbol with the given name and return a copy of it.
+ */
+static int
+lookup_name(Elf *e, Elf_Scn *scn, u_long stridx, const char *symbol,
+ GElf_Sym *symcopy, prsyminfo_t *si)
+{
+ GElf_Sym sym;
+ Elf_Data *data;
+ char *s;
+ int i;
+
+ if ((data = elf_getdata(scn, NULL)) == NULL) {
+ DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
+ return (1);
}
- for (i = 0; i < p->nobjs; i++) {
- rdl = &p->rdobjs[i];
- basename_r(rdl->rdl_path, tmppath);
- if (strcmp(tmppath, name) == 0) {
- if ((map = malloc(sizeof(*map))) == NULL)
- return (NULL);
- proc_rdl2prmap(rdl, map);
- return (map);
+ for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
+ s = elf_strptr(e, stridx, sym.st_name);
+ if (s != NULL && strcmp(s, symbol) == 0) {
+ memcpy(symcopy, &sym, sizeof(*symcopy));
+ if (si != NULL)
+ si->prs_id = i;
+ return (0);
}
}
-
- return (NULL);
+ return (1);
}
int
proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
- GElf_Sym *symcopy)
+ GElf_Sym *symcopy, prsyminfo_t *si)
{
Elf *e;
Elf_Scn *scn, *dynsymscn = NULL, *symtabscn = NULL;
- Elf_Data *data;
GElf_Shdr shdr;
- GElf_Sym sym;
GElf_Ehdr ehdr;
- int fd, error = -1;
- size_t i;
prmap_t *map;
- char *s;
- unsigned long symtabstridx = 0, dynsymstridx = 0;
+ uintptr_t off;
+ u_long symtabstridx = 0, dynsymstridx = 0;
+ int fd, error = -1;
if ((map = proc_name2map(p, object)) == NULL) {
DPRINTFX("ERROR: couldn't find object %s", object);
@@ -460,46 +468,25 @@ proc_name2sym(struct proc_handle *p, const char *object, const char *symbol,
dynsymscn = scn;
dynsymstridx = shdr.sh_link;
break;
- default:
- break;
- }
- }
- /*
- * Iterate over the Dynamic Symbols table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
- */
- if ((data = elf_getdata(dynsymscn, NULL))) {
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- s = elf_strptr(e, dynsymstridx, sym.st_name);
- if (s && strcmp(s, symbol) == 0) {
- memcpy(symcopy, &sym, sizeof(sym));
- if (ehdr.e_type != ET_EXEC)
- symcopy->st_value += map->pr_vaddr;
- error = 0;
- goto out;
- }
}
}
+
/*
- * Iterate over the Symbols Table to find the symbol.
- * Then look up the string name in STRTAB (.dynstr)
+ * First look up the symbol in the dynsymtab, and fall back to the
+ * symtab if the lookup fails.
*/
- if ((data = elf_getdata(symtabscn, NULL))) {
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
- s = elf_strptr(e, symtabstridx, sym.st_name);
- if (s && strcmp(s, symbol) == 0) {
- memcpy(symcopy, &sym, sizeof(sym));
- if (ehdr.e_type != ET_EXEC)
- symcopy->st_value += map->pr_vaddr;
- error = 0;
- goto out;
- }
- }
- }
+ error = lookup_name(e, dynsymscn, dynsymstridx, symbol, symcopy, si);
+ if (error == 0)
+ goto out;
+
+ error = lookup_name(e, symtabscn, symtabstridx, symbol, symcopy, si);
+ if (error == 0)
+ goto out;
+
out:
- DPRINTFX("found addr 0x%lx for %s", symcopy->st_value, symbol);
+ off = ehdr.e_type == ET_EXEC ? 0 : map->pr_vaddr;
+ symcopy->st_value += off;
+
err2:
elf_end(e);
err1:
@@ -510,6 +497,23 @@ err0:
return (error);
}
+ctf_file_t *
+proc_name2ctf(struct proc_handle *p, const char *name)
+{
+#ifndef NO_CTF
+ prmap_t *map;
+ int error;
+
+ if ((map = proc_name2map(p, name)) == NULL)
+ return (NULL);
+
+ return (ctf_open(map->pr_mapname, &error));
+#else
+ (void)p;
+ (void)name;
+ return (NULL);
+#endif
+}
int
proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
@@ -547,7 +551,7 @@ proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
scn = NULL;
while ((scn = elf_nextscn(e, scn)) != NULL) {
gelf_getshdr(scn, &shdr);
- if (which == PR_SYMTAB &&
+ if (which == PR_SYMTAB &&
shdr.sh_type == SHT_SYMTAB) {
foundscn = scn;
break;
@@ -564,8 +568,7 @@ proc_iter_symbyaddr(struct proc_handle *p, const char *object, int which,
DPRINTFX("ERROR: elf_getdata() failed: %s", elf_errmsg(-1));
goto err2;
}
- i = 0;
- while (gelf_getsym(data, i++, &sym) != NULL) {
+ for (i = 0; gelf_getsym(data, i, &sym) != NULL; i++) {
if (GELF_ST_BIND(sym.st_info) == STB_LOCAL &&
(mask & BIND_LOCAL) == 0)
continue;
diff --git a/lib/libproc/test/Makefile b/lib/libproc/test/Makefile
deleted file mode 100644
index e4d33f8..0000000
--- a/lib/libproc/test/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-# $FreeBSD$
-
-SUBDIR= t1-bkpt t2-name2map t3-name2sym
-
-.include <bsd.subdir.mk>
diff --git a/lib/libproc/test/t1-bkpt/Makefile b/lib/libproc/test/t1-bkpt/Makefile
deleted file mode 100644
index eb5b37f..0000000
--- a/lib/libproc/test/t1-bkpt/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $FreeBSD$
-
-PROG= t1-bkpt
-
-SRCS= t1-bkpt.c
-
-LDADD= -lproc -lelf -lrtld_db -lutil
-DPADD= ${LIBPROC} ${LIBELF}
-
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/lib/libproc/test/t2-name2map/Makefile b/lib/libproc/test/t2-name2map/Makefile
deleted file mode 100644
index 9002acc..0000000
--- a/lib/libproc/test/t2-name2map/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $FreeBSD$
-
-PROG= t2-name2map
-
-SRCS= t2-name2map.c
-
-LDADD= -lproc -lelf -lrtld_db -lutil
-DPADD= ${LIBPROC} ${LIBELF}
-
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/lib/libproc/test/t3-name2sym/Makefile b/lib/libproc/test/t3-name2sym/Makefile
deleted file mode 100644
index 68e23c6..0000000
--- a/lib/libproc/test/t3-name2sym/Makefile
+++ /dev/null
@@ -1,12 +0,0 @@
-# $FreeBSD$
-
-PROG= t3-name2sym
-
-SRCS= t3-name2sym.c
-
-LDADD= -lproc -lelf -lrtld_db -lutil
-DPADD= ${LIBPROC} ${LIBELF}
-
-MAN=
-
-.include <bsd.prog.mk>
diff --git a/lib/libproc/tests/Makefile b/lib/libproc/tests/Makefile
new file mode 100644
index 0000000..1f98467
--- /dev/null
+++ b/lib/libproc/tests/Makefile
@@ -0,0 +1,21 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libproc
+
+ATF_TESTS_C+= proc_test
+
+PROGS= target_prog
+SRCS_target_prog= target_prog.c
+BINDIR_target_prog= ${TESTSDIR}
+
+LDADD+= -lelf -lproc -lrtld_db -lutil
+DPADD+= ${LIBELF} ${LIBPROC} ${LIBRTLD_DB} ${LIBUTIL}
+
+# Ensure that symbols aren't stripped from the test program, as they're needed
+# for testing symbol lookup.
+STRIP=
+
+MAN=
+WARNS?= 6
+
+.include <bsd.test.mk>
diff --git a/lib/libproc/tests/proc_test.c b/lib/libproc/tests/proc_test.c
new file mode 100644
index 0000000..0242b5b
--- /dev/null
+++ b/lib/libproc/tests/proc_test.c
@@ -0,0 +1,349 @@
+/*-
+ * Copyright (c) 2014 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <libgen.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <atf-c.h>
+#include <libelf.h>
+#include <libproc.h>
+
+static const char *aout_object = "a.out";
+static const char *ldelf_object = "ld-elf.so.1";
+static const char *target_prog_file = "target_prog";
+
+/*
+ * Run the test program. If the sig parameter is set to true, the test program
+ * will deliver SIGUSR1 to itself during execution.
+ */
+static struct proc_handle *
+start_prog(const struct atf_tc *tc, bool sig)
+{
+ char *argv[3];
+ struct proc_handle *phdl;
+ int error;
+
+ asprintf(&argv[0], "%s/%s", atf_tc_get_config_var(tc, "srcdir"),
+ target_prog_file);
+ ATF_REQUIRE(argv[0] != NULL);
+
+ if (sig) {
+ argv[1] = strdup("-s");
+ argv[2] = NULL;
+ } else {
+ argv[1] = NULL;
+ }
+
+ error = proc_create(argv[0], argv, NULL, NULL, &phdl);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to run '%s'", target_prog_file);
+ ATF_REQUIRE(phdl != NULL);
+
+ free(argv[0]);
+ free(argv[1]);
+
+ return (phdl);
+}
+
+static void
+set_bkpt(struct proc_handle *phdl, uintptr_t addr, u_long *saved)
+{
+ int error;
+
+ error = proc_bkptset(phdl, addr, saved);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to set breakpoint at 0x%jx",
+ (uintmax_t)addr);
+}
+
+static void
+remove_bkpt(struct proc_handle *phdl, uintptr_t addr, u_long val)
+{
+ int error;
+
+ error = proc_bkptdel(phdl, addr, val);
+ ATF_REQUIRE_EQ_MSG(error, 0,
+ "failed to delete breakpoint at 0x%jx", (uintmax_t)addr);
+
+ error = proc_regset(phdl, REG_PC, addr);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to reset program counter");
+}
+
+/*
+ * Wait for the specified process to hit a breakpoint at the specified symbol.
+ */
+static void
+verify_bkpt(struct proc_handle *phdl, GElf_Sym *sym, const char *symname,
+ const char *mapname)
+{
+ char mapbname[MAXPATHLEN], *name;
+ GElf_Sym tsym;
+ prmap_t *map;
+ size_t namesz;
+ u_long addr;
+ int error, state;
+
+ state = proc_wstatus(phdl);
+ ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has state %d", state);
+
+ /* Get the program counter and decrement it. */
+ error = proc_regget(phdl, REG_PC, &addr);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to obtain PC for '%s'",
+ target_prog_file);
+ proc_bkptregadj(&addr);
+
+ /*
+ * Make sure the PC matches the expected value obtained from the symbol
+ * definition we looked up earlier.
+ */
+ ATF_CHECK_EQ_MSG(addr, sym->st_value,
+ "program counter 0x%lx doesn't match expected value 0x%jx",
+ addr, (uintmax_t)sym->st_value);
+
+ /*
+ * Ensure we can look up the r_debug_state symbol using its starting
+ * address and that the resulting symbol matches the one we found using
+ * a name lookup.
+ */
+ namesz = strlen(symname) + 1;
+ name = malloc(namesz);
+ ATF_REQUIRE(name != NULL);
+
+ error = proc_addr2sym(phdl, addr, name, namesz, &tsym);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up symbol at 0x%lx", addr);
+ ATF_REQUIRE_EQ(memcmp(sym, &tsym, sizeof(*sym)), 0);
+ ATF_REQUIRE_EQ(strcmp(symname, name), 0);
+ free(name);
+
+ map = proc_addr2map(phdl, addr);
+ ATF_REQUIRE_MSG(map != NULL, "failed to look up map for address 0x%lx",
+ addr);
+ basename_r(map->pr_mapname, mapbname);
+ ATF_REQUIRE_EQ_MSG(strcmp(mapname, mapbname), 0,
+ "expected map name '%s' doesn't match '%s'", mapname, mapbname);
+}
+
+ATF_TC(map_alias_obj2map);
+ATF_TC_HEAD(map_alias_obj2map, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Callers are supposed to be able to use \"a.out\" as an alias for "
+ "the program executable. Make sure that proc_obj2map() handles "
+ "this properly.");
+}
+ATF_TC_BODY(map_alias_obj2map, tc)
+{
+ struct proc_handle *phdl;
+ prmap_t *map1, *map2;
+
+ phdl = start_prog(tc, false);
+
+ /* Initialize the rtld_db handle. */
+ (void)proc_rdagent(phdl);
+
+ /* Ensure that "target_prog" and "a.out" return the same map. */
+ map1 = proc_obj2map(phdl, target_prog_file);
+ ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'",
+ target_prog_file);
+ map2 = proc_obj2map(phdl, aout_object);
+ ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'",
+ aout_object);
+ ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(map_alias_name2map);
+ATF_TC_HEAD(map_alias_name2map, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Callers are supposed to be able to use \"a.out\" as an alias for "
+ "the program executable. Make sure that proc_name2map() handles "
+ "this properly.");
+}
+ATF_TC_BODY(map_alias_name2map, tc)
+{
+ struct proc_handle *phdl;
+ prmap_t *map1, *map2;
+
+ phdl = start_prog(tc, false);
+
+ /* Initialize the rtld_db handle. */
+ (void)proc_rdagent(phdl);
+
+ /* Ensure that "target_prog" and "a.out" return the same map. */
+ map1 = proc_name2map(phdl, target_prog_file);
+ ATF_REQUIRE_MSG(map1 != NULL, "failed to look up map for '%s'",
+ target_prog_file);
+ map2 = proc_name2map(phdl, aout_object);
+ ATF_REQUIRE_MSG(map2 != NULL, "failed to look up map for '%s'",
+ aout_object);
+ ATF_CHECK_EQ(strcmp(map1->pr_mapname, map2->pr_mapname), 0);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(map_alias_name2sym);
+ATF_TC_HEAD(map_alias_name2sym, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Callers are supposed to be able to use \"a.out\" as an alias for "
+ "the program executable. Make sure that proc_name2sym() handles "
+ "this properly.");
+}
+ATF_TC_BODY(map_alias_name2sym, tc)
+{
+ GElf_Sym sym1, sym2;
+ prsyminfo_t si1, si2;
+ struct proc_handle *phdl;
+ int error;
+
+ phdl = start_prog(tc, false);
+
+ /* Initialize the rtld_db handle. */
+ (void)proc_rdagent(phdl);
+
+ /*
+ * Make sure that "target_prog:main" and "a.out:main" return the same
+ * symbol.
+ */
+ error = proc_name2sym(phdl, target_prog_file, "main", &sym1, &si1);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
+ target_prog_file);
+ error = proc_name2sym(phdl, aout_object, "main", &sym2, &si2);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main' via %s",
+ aout_object);
+
+ ATF_CHECK_EQ(memcmp(&sym1, &sym2, sizeof(sym1)), 0);
+ ATF_CHECK_EQ(si1.prs_id, si2.prs_id);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(symbol_lookup);
+ATF_TC_HEAD(symbol_lookup, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Look up a couple of well-known symbols in the test program, place "
+ "breakpoints on them, and verify that we hit the breakpoints. Also "
+ "make sure that we can use the breakpoint address to look up the "
+ "corresponding symbol.");
+}
+ATF_TC_BODY(symbol_lookup, tc)
+{
+ GElf_Sym main_sym, r_debug_state_sym;
+ struct proc_handle *phdl;
+ u_long saved;
+ int error;
+
+ phdl = start_prog(tc, false);
+
+ error = proc_name2sym(phdl, target_prog_file, "main", &main_sym, NULL);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'main'");
+
+ error = proc_name2sym(phdl, ldelf_object, "r_debug_state",
+ &r_debug_state_sym, NULL);
+ ATF_REQUIRE_EQ_MSG(error, 0, "failed to look up 'r_debug_state'");
+
+ set_bkpt(phdl, r_debug_state_sym.st_value, &saved);
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+ verify_bkpt(phdl, &r_debug_state_sym, "r_debug_state", ldelf_object);
+ remove_bkpt(phdl, r_debug_state_sym.st_value, saved);
+
+ set_bkpt(phdl, main_sym.st_value, &saved);
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+ verify_bkpt(phdl, &main_sym, "main", target_prog_file);
+ remove_bkpt(phdl, main_sym.st_value, saved);
+
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ proc_free(phdl);
+}
+
+ATF_TC(signal_forward);
+ATF_TC_HEAD(signal_forward, tc)
+{
+ atf_tc_set_md_var(tc, "descr",
+ "Run the test program in a mode which causes it to send a signal "
+ "to itself. Make sure that we intercept the signal and that "
+ "proc_continue() forwards it to the process.");
+}
+ATF_TC_BODY(signal_forward, tc)
+{
+ struct proc_handle *phdl;
+ int state, status;
+
+ phdl = start_prog(tc, true);
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ /* The process should have been interrupted by a signal. */
+ state = proc_wstatus(phdl);
+ ATF_REQUIRE_EQ_MSG(state, PS_STOP, "process has unexpected state %d",
+ state);
+
+ /* Continue execution and allow the signal to be delivered. */
+ ATF_CHECK_EQ_MSG(proc_continue(phdl), 0, "failed to resume execution");
+
+ /*
+ * Make sure the process exited with status 0. If it didn't receive the
+ * SIGUSR1 that it sent to itself, it'll exit with a non-zero exit
+ * status, causing the test to fail.
+ */
+ state = proc_wstatus(phdl);
+ ATF_REQUIRE_EQ_MSG(state, PS_UNDEAD, "process has unexpected state %d",
+ state);
+
+ status = proc_getwstat(phdl);
+ ATF_REQUIRE(status >= 0);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+ proc_free(phdl);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+
+ ATF_TP_ADD_TC(tp, map_alias_obj2map);
+ ATF_TP_ADD_TC(tp, map_alias_name2map);
+ ATF_TP_ADD_TC(tp, map_alias_name2sym);
+ ATF_TP_ADD_TC(tp, symbol_lookup);
+ ATF_TP_ADD_TC(tp, signal_forward);
+
+ return (atf_no_error());
+}
diff --git a/lib/libproc/test/t1-bkpt/t1-bkpt.c b/lib/libproc/tests/target_prog.c
index 1cd4d17..1edf0de 100644
--- a/lib/libproc/test/t1-bkpt/t1-bkpt.c
+++ b/lib/libproc/tests/target_prog.c
@@ -1,71 +1,59 @@
-/*
- * Copyright (c) 2010 The FreeBSD Foundation
- * All rights reserved.
- *
- * This software was developed by Rui Paulo under sponsorship from the
- * FreeBSD Foundation.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
+/*-
+ * Copyright (c) 2014 Mark Johnston <markj@FreeBSD.org>
+ * All rights reserved.
*
- * $FreeBSD$
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
*/
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <assert.h>
-#include <stdio.h>
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <err.h>
+#include <signal.h>
+#include <stdlib.h>
#include <string.h>
-#include <libproc.h>
+#include <unistd.h>
-int __noinline
-t1_bkpt_t()
-{
- printf("TEST OK\n");
-}
+static volatile sig_atomic_t saw;
-int
-t1_bkpt_d()
+static void
+usr1(int sig __unused)
{
- struct proc_handle *phdl;
- char *targv[] = { "t1-bkpt-t", NULL};
- unsigned long saved;
- proc_create("./t1-bkpt", targv, NULL, NULL, &phdl);
- assert(proc_bkptset(phdl, (uintptr_t)t1_bkpt_t, &saved) == 0);
- proc_continue(phdl);
- assert(proc_wstatus(phdl) == PS_STOP);
- proc_bkptexec(phdl, saved);
- proc_continue(phdl);
- proc_wstatus(phdl);
- proc_free(phdl);
+ saw = 1;
}
-
int
main(int argc, char **argv)
{
- if (!strcmp(argv[0], "t1-bkpt-t"))
- t1_bkpt_t();
- else
- t1_bkpt_d();
-}
+ if (argc == 1)
+ return (EXIT_SUCCESS);
+ if (argc == 2 && strcmp(argv[1], "-s") == 0) {
+ if (signal(SIGUSR1, usr1) == SIG_ERR)
+ err(1, "signal");
+ if (kill(getpid(), SIGUSR1) != 0)
+ err(1, "kill");
+ return (saw == 1 ? EXIT_SUCCESS : EXIT_FAILURE);
+ }
+ return (EXIT_FAILURE);
+}
diff --git a/lib/librt/Makefile b/lib/librt/Makefile
index f624cf7..bd6ec07 100644
--- a/lib/librt/Makefile
+++ b/lib/librt/Makefile
@@ -1,5 +1,7 @@
# $FreeBSD$
+.include <src.opts.mk>
+
LIB=rt
SHLIB_MAJOR= 1
CFLAGS+=-I${.CURDIR}/../libc/include -I${.CURDIR}
@@ -18,4 +20,6 @@ PRECIOUSLIB=
VERSION_MAP= ${.CURDIR}/Version.map
+.include <bsd.arch.inc.mk>
+
.include <bsd.lib.mk>
diff --git a/lib/librt/Makefile.amd64 b/lib/librt/Makefile.amd64
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/librt/Makefile.amd64
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/librt/Makefile.i386 b/lib/librt/Makefile.i386
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/librt/Makefile.i386
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/librt/tests/Makefile b/lib/librt/tests/Makefile
new file mode 100644
index 0000000..224f52e
--- /dev/null
+++ b/lib/librt/tests/Makefile
@@ -0,0 +1,17 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/librt
+
+TESTSDIR= ${TESTSBASE}/lib/librt
+
+DPADD+= ${LIBRT}
+LDADD+= -lrt
+
+NETBSD_ATF_TESTS_C= sched_test
+NETBSD_ATF_TESTS_C+= sem_test
+
+.include <netbsd-tests.test.mk>
+
+.include <bsd.test.mk>
diff --git a/lib/librtld_db/rtld_db.c b/lib/librtld_db/rtld_db.c
index 2d1f6e6..cd4377e 100644
--- a/lib/librtld_db/rtld_db.c
+++ b/lib/librtld_db/rtld_db.c
@@ -237,14 +237,14 @@ rd_reset(rd_agent_t *rdap)
GElf_Sym sym;
if (proc_name2sym(rdap->rda_php, "ld-elf.so.1", "r_debug_state",
- &sym) < 0)
+ &sym, NULL) < 0)
return (RD_ERR);
DPRINTF("found r_debug_state at 0x%lx\n", (unsigned long)sym.st_value);
rdap->rda_preinit_addr = sym.st_value;
rdap->rda_dlactivity_addr = sym.st_value;
if (proc_name2sym(rdap->rda_php, "ld-elf.so.1", "_r_debug_postinit",
- &sym) < 0)
+ &sym, NULL) < 0)
return (RD_ERR);
DPRINTF("found _r_debug_postinit at 0x%lx\n",
(unsigned long)sym.st_value);
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile
index 72b201e..e57407f 100644
--- a/lib/libstand/Makefile
+++ b/lib/libstand/Makefile
@@ -64,9 +64,6 @@ SRCS+= bcmp.c bcopy.c bzero.c ffs.c memccpy.c memchr.c memcmp.c memcpy.c \
.if ${MACHINE_CPUARCH} == "arm"
.PATH: ${.CURDIR}/../libc/arm/gen
-.if ${MK_ARM_EABI} == "no"
-SRCS+= divsi3.S
-.else
# Compiler support functions
.PATH: ${.CURDIR}/../../contrib/compiler-rt/lib/
# __clzsi2 and ctzsi2 for various builtin functions
@@ -78,7 +75,6 @@ SRCS+= udivmoddi4.c udivmodsi4.c udivdi3.c udivsi3.c umoddi3.c umodsi3.c
.PATH: ${.CURDIR}/../../contrib/compiler-rt/lib/arm/
SRCS+= aeabi_idivmod.S aeabi_ldivmod.S aeabi_uidivmod.S aeabi_uldivmod.S
SRCS+= aeabi_memcmp.S aeabi_memcpy.S aeabi_memmove.S aeabi_memset.S
-.endif
.endif
.if ${MACHINE_CPUARCH} == "powerpc"
@@ -161,6 +157,7 @@ SRCS+= bootp.c rarp.c bootparam.c
SRCS+= ufs.c nfs.c cd9660.c tftp.c gzipfs.c bzipfs.c
SRCS+= dosfs.c ext2fs.c
SRCS+= splitfs.c
+SRCS+= pkgfs.c
.if ${MK_NAND} != "no"
SRCS+= nandfs.c
.endif
diff --git a/lib/libstand/open.c b/lib/libstand/open.c
index 49dc660..0d90433 100644
--- a/lib/libstand/open.c
+++ b/lib/libstand/open.c
@@ -65,6 +65,8 @@ __FBSDID("$FreeBSD$");
#include "stand.h"
+struct fs_ops *exclusive_file_system;
+
struct open_file files[SOPEN_MAX];
static int
@@ -89,6 +91,7 @@ o_rainit(struct open_file *f)
int
open(const char *fname, int mode)
{
+ struct fs_ops *fs;
struct open_file *f;
int fd, i, error, besterror;
const char *file;
@@ -105,6 +108,15 @@ open(const char *fname, int mode)
f->f_offset = 0;
f->f_devdata = NULL;
file = (char *)0;
+
+ if (exclusive_file_system != NULL) {
+ fs = exclusive_file_system;
+ error = (fs->fo_open)(fname, f);
+ if (error == 0)
+ goto ok;
+ goto fail;
+ }
+
error = devopen(f, fname, &file);
if (error ||
(((f->f_flags & F_NODEV) == 0) && f->f_dev == (struct devsw *)0))
@@ -120,20 +132,17 @@ open(const char *fname, int mode)
/* pass file name to the different filesystem open routines */
besterror = ENOENT;
for (i = 0; file_system[i] != NULL; i++) {
-
- error = ((*file_system[i]).fo_open)(file, f);
- if (error == 0) {
-
- f->f_ops = file_system[i];
- o_rainit(f);
- return (fd);
- }
+ fs = file_system[i];
+ error = (fs->fo_open)(file, f);
+ if (error == 0)
+ goto ok;
if (error != EINVAL)
besterror = error;
}
error = besterror;
- if ((f->f_flags & F_NODEV) == 0)
+ fail:
+ if ((f->f_flags & F_NODEV) == 0 && f->f_dev != NULL)
f->f_dev->dv_close(f);
if (error)
devclose(f);
@@ -142,4 +151,9 @@ open(const char *fname, int mode)
f->f_flags = 0;
errno = error;
return (-1);
+
+ ok:
+ f->f_ops = fs;
+ o_rainit(f);
+ return (fd);
}
diff --git a/lib/libstand/pkgfs.c b/lib/libstand/pkgfs.c
new file mode 100644
index 0000000..fda7f60
--- /dev/null
+++ b/lib/libstand/pkgfs.c
@@ -0,0 +1,791 @@
+/*-
+ * Copyright (c) 2007-2014, Juniper Networks, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+#include <sys/stat.h>
+#include <sys/stdint.h>
+#include <string.h>
+#include <zlib.h>
+
+#ifdef PKGFS_DEBUG
+#define DBG(x) printf x
+#else
+#define DBG(x)
+#endif
+
+static int pkg_open(const char *, struct open_file *);
+static int pkg_close(struct open_file *);
+static int pkg_read(struct open_file *, void *, size_t, size_t *);
+static off_t pkg_seek(struct open_file *, off_t, int);
+static int pkg_stat(struct open_file *, struct stat *);
+static int pkg_readdir(struct open_file *, struct dirent *);
+
+struct fs_ops pkgfs_fsops = {
+ "pkg",
+ pkg_open,
+ pkg_close,
+ pkg_read,
+ null_write,
+ pkg_seek,
+ pkg_stat,
+ pkg_readdir
+};
+
+#define PKG_BUFSIZE 512
+#define PKG_MAXCACHESZ 4096
+
+#define PKG_FILEEXT ".tgz"
+
+/*
+ * Layout of POSIX 'ustar' header.
+ */
+struct ustar_hdr {
+ char ut_name[100];
+ char ut_mode[8];
+ char ut_uid[8];
+ char ut_gid[8];
+ char ut_size[12];
+ char ut_mtime[12];
+ char ut_checksum[8];
+ char ut_typeflag[1];
+ char ut_linkname[100];
+ char ut_magic[6]; /* For POSIX: "ustar\0" */
+ char ut_version[2]; /* For POSIX: "00" */
+ char ut_uname[32];
+ char ut_gname[32];
+ char ut_rdevmajor[8];
+ char ut_rdevminor[8];
+ union {
+ struct {
+ char prefix[155];
+ } posix;
+ struct {
+ char atime[12];
+ char ctime[12];
+ char offset[12];
+ char longnames[4];
+ char unused[1];
+ struct gnu_sparse {
+ char offset[12];
+ char numbytes[12];
+ } sparse[4];
+ char isextended[1];
+ char realsize[12];
+ } gnu;
+ } u;
+ u_char __padding[12];
+};
+
+struct package;
+
+struct tarfile
+{
+ struct package *tf_pkg;
+ struct tarfile *tf_next;
+ struct ustar_hdr tf_hdr;
+ off_t tf_ofs;
+ off_t tf_size;
+ off_t tf_fp;
+ size_t tf_cachesz;
+ void *tf_cache;
+};
+
+struct package
+{
+ struct package *pkg_chain;
+ int pkg_fd;
+ off_t pkg_ofs;
+ z_stream pkg_zs;
+ struct tarfile *pkg_first;
+ struct tarfile *pkg_last;
+ u_char pkg_buf[PKG_BUFSIZE];
+};
+
+static struct package *package = NULL;
+
+static int new_package(int, struct package **);
+
+void
+pkgfs_cleanup(void)
+{
+ struct package *chain;
+ struct tarfile *tf, *tfn;
+
+ while (package != NULL) {
+ inflateEnd(&package->pkg_zs);
+ close(package->pkg_fd);
+
+ tf = package->pkg_first;
+ while (tf != NULL) {
+ tfn = tf->tf_next;
+ if (tf->tf_cachesz > 0)
+ free(tf->tf_cache);
+ free(tf);
+ tf = tfn;
+ }
+
+ chain = package->pkg_chain;
+ free(package);
+ package = chain;
+ }
+}
+
+int
+pkgfs_init(const char *pkgname, struct fs_ops *proto)
+{
+ struct package *pkg;
+ int error, fd;
+
+ if (proto != &pkgfs_fsops)
+ pkgfs_cleanup();
+
+ exclusive_file_system = proto;
+
+ fd = open(pkgname, O_RDONLY);
+
+ exclusive_file_system = NULL;
+
+ if (fd == -1)
+ return (errno);
+
+ error = new_package(fd, &pkg);
+ if (error) {
+ close(fd);
+ return (error);
+ }
+
+ if (pkg == NULL)
+ return (EDOOFUS);
+
+ pkg->pkg_chain = package;
+ package = pkg;
+ exclusive_file_system = &pkgfs_fsops;
+ return (0);
+}
+
+static int get_mode(struct tarfile *);
+static int get_zipped(struct package *, void *, size_t);
+static int new_package(int, struct package **);
+static struct tarfile *scan_tarfile(struct package *, struct tarfile *);
+
+static int
+pkg_open(const char *fn, struct open_file *f)
+{
+ struct tarfile *tf;
+
+ if (fn == NULL || f == NULL)
+ return (EINVAL);
+
+ if (package == NULL)
+ return (ENXIO);
+
+ /*
+ * We can only read from a package, so reject request to open
+ * for write-only or read-write.
+ */
+ if (f->f_flags != F_READ)
+ return (EPERM);
+
+ /*
+ * Scan the file headers for the named file. We stop scanning
+ * at the first filename that has the .pkg extension. This is
+ * a package within a package. We assume we have all the files
+ * we need up-front and without having to dig within nested
+ * packages.
+ *
+ * Note that we preserve streaming properties as much as possible.
+ */
+ while (*fn == '/')
+ fn++;
+
+ /*
+ * Allow opening of the root directory for use by readdir()
+ * to support listing files in the package.
+ */
+ if (*fn == '\0') {
+ f->f_fsdata = NULL;
+ return (0);
+ }
+
+ tf = scan_tarfile(package, NULL);
+ while (tf != NULL) {
+ if (strcmp(fn, tf->tf_hdr.ut_name) == 0) {
+ f->f_fsdata = tf;
+ tf->tf_fp = 0; /* Reset the file pointer. */
+ return (0);
+ }
+ tf = scan_tarfile(package, tf);
+ }
+ return (errno);
+}
+
+static int
+pkg_close(struct open_file *f)
+{
+ struct tarfile *tf;
+
+ tf = (struct tarfile *)f->f_fsdata;
+ if (tf == NULL)
+ return (0);
+
+ /*
+ * Free up the cache if we read all of the file.
+ */
+ if (tf->tf_fp == tf->tf_size && tf->tf_cachesz > 0) {
+ free(tf->tf_cache);
+ tf->tf_cachesz = 0;
+ }
+ return (0);
+}
+
+static int
+pkg_read(struct open_file *f, void *buf, size_t size, size_t *res)
+{
+ struct tarfile *tf;
+ char *p;
+ off_t fp;
+ size_t sz;
+
+ tf = (struct tarfile *)f->f_fsdata;
+ if (tf == NULL) {
+ if (res != NULL)
+ *res = size;
+ return (EBADF);
+ }
+
+ fp = tf->tf_fp;
+ p = buf;
+ sz = 0;
+ while (size > 0) {
+ sz = tf->tf_size - fp;
+ if (fp < tf->tf_cachesz && tf->tf_cachesz < tf->tf_size)
+ sz = tf->tf_cachesz - fp;
+ if (size < sz)
+ sz = size;
+ if (sz == 0)
+ break;
+
+ if (fp < tf->tf_cachesz) {
+ /* Satisfy the request from cache. */
+ memcpy(p, tf->tf_cache + fp, sz);
+ fp += sz;
+ p += sz;
+ size -= sz;
+ continue;
+ }
+
+ if (get_zipped(tf->tf_pkg, p, sz) == -1) {
+ sz = -1;
+ break;
+ }
+
+ fp += sz;
+ p += sz;
+ size -= sz;
+
+ if (tf->tf_cachesz != 0)
+ continue;
+
+ tf->tf_cachesz = (sz <= PKG_MAXCACHESZ) ? sz : PKG_MAXCACHESZ;
+ tf->tf_cache = malloc(tf->tf_cachesz);
+ if (tf->tf_cache != NULL)
+ memcpy(tf->tf_cache, buf, tf->tf_cachesz);
+ else
+ tf->tf_cachesz = 0;
+ }
+
+ tf->tf_fp = fp;
+ if (res != NULL)
+ *res = size;
+ return ((sz == -1) ? errno : 0);
+}
+
+static off_t
+pkg_seek(struct open_file *f, off_t ofs, int whence)
+{
+ char buf[512];
+ struct tarfile *tf;
+ off_t delta;
+ size_t sz, res;
+ int error;
+
+ tf = (struct tarfile *)f->f_fsdata;
+ if (tf == NULL) {
+ errno = EBADF;
+ return (-1);
+ }
+
+ switch (whence) {
+ case SEEK_SET:
+ delta = ofs - tf->tf_fp;
+ break;
+ case SEEK_CUR:
+ delta = ofs;
+ break;
+ case SEEK_END:
+ delta = tf->tf_size - tf->tf_fp + ofs;
+ break;
+ default:
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (delta < 0) {
+ DBG(("%s: negative file seek (%jd)\n", __func__,
+ (intmax_t)delta));
+ errno = ESPIPE;
+ return (-1);
+ }
+
+ while (delta > 0 && tf->tf_fp < tf->tf_size) {
+ sz = (delta > sizeof(buf)) ? sizeof(buf) : delta;
+ error = pkg_read(f, buf, sz, &res);
+ if (error != 0) {
+ errno = error;
+ return (-1);
+ }
+ delta -= sz - res;
+ }
+
+ return (tf->tf_fp);
+}
+
+static int
+pkg_stat(struct open_file *f, struct stat *sb)
+{
+ struct tarfile *tf;
+
+ tf = (struct tarfile *)f->f_fsdata;
+ if (tf == NULL)
+ return (EBADF);
+ memset(sb, 0, sizeof(*sb));
+ sb->st_mode = get_mode(tf);
+ sb->st_size = tf->tf_size;
+ sb->st_blocks = (tf->tf_size + 511) / 512;
+ return (0);
+}
+
+static int
+pkg_readdir(struct open_file *f, struct dirent *d)
+{
+ struct tarfile *tf;
+
+ tf = (struct tarfile *)f->f_fsdata;
+ if (tf != NULL)
+ return (EBADF);
+
+ tf = scan_tarfile(package, NULL);
+ if (tf == NULL)
+ return (ENOENT);
+
+ d->d_fileno = 0;
+ d->d_reclen = sizeof(*d);
+ d->d_type = DT_REG;
+ memcpy(d->d_name, tf->tf_hdr.ut_name, sizeof(d->d_name));
+ return (0);
+}
+
+/*
+ * Low-level support functions.
+ */
+
+static int
+get_byte(struct package *pkg, off_t *op)
+{
+ int c;
+
+ if (pkg->pkg_zs.avail_in == 0) {
+ c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE);
+ if (c <= 0)
+ return (-1);
+ pkg->pkg_zs.avail_in = c;
+ pkg->pkg_zs.next_in = pkg->pkg_buf;
+ }
+
+ c = *pkg->pkg_zs.next_in;
+ pkg->pkg_zs.next_in++;
+ pkg->pkg_zs.avail_in--;
+ (*op)++;
+ return (c);
+}
+
+static int
+get_zipped(struct package *pkg, void *buf, size_t bufsz)
+{
+ int c;
+
+ pkg->pkg_zs.next_out = buf;
+ pkg->pkg_zs.avail_out = bufsz;
+
+ while (pkg->pkg_zs.avail_out) {
+ if (pkg->pkg_zs.avail_in == 0) {
+ c = read(pkg->pkg_fd, pkg->pkg_buf, PKG_BUFSIZE);
+ if (c <= 0) {
+ errno = EIO;
+ return (-1);
+ }
+ pkg->pkg_zs.avail_in = c;
+ pkg->pkg_zs.next_in = pkg->pkg_buf;
+ }
+
+ c = inflate(&pkg->pkg_zs, Z_SYNC_FLUSH);
+ if (c != Z_OK && c != Z_STREAM_END) {
+ errno = EIO;
+ return (-1);
+ }
+ }
+
+ pkg->pkg_ofs += bufsz;
+ return (0);
+}
+
+static int
+cache_data(struct tarfile *tf)
+{
+ struct package *pkg;
+ size_t sz;
+
+ if (tf == NULL) {
+ DBG(("%s: no file to cache data for?\n", __func__));
+ errno = EINVAL;
+ return (-1);
+ }
+
+ pkg = tf->tf_pkg;
+ if (pkg == NULL) {
+ DBG(("%s: no package associated with file?\n", __func__));
+ errno = EINVAL;
+ return (-1);
+ }
+
+ if (tf->tf_ofs != pkg->pkg_ofs) {
+ DBG(("%s: caching after partial read of file %s?\n",
+ __func__, tf->tf_hdr.ut_name));
+ errno = EINVAL;
+ return (-1);
+ }
+
+ /* We don't cache everything... */
+ if (tf->tf_size > PKG_MAXCACHESZ) {
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ /* All files are padded to a multiple of 512 bytes. */
+ sz = (tf->tf_size + 0x1ff) & ~0x1ff;
+
+ tf->tf_cache = malloc(sz);
+ if (tf->tf_cache == NULL) {
+ DBG(("%s: could not allocate %d bytes\n", __func__, (int)sz));
+ errno = ENOMEM;
+ return (-1);
+ }
+
+ tf->tf_cachesz = sz;
+ return (get_zipped(pkg, tf->tf_cache, sz));
+}
+
+/*
+ * Note that this implementation does not (and should not!) obey
+ * locale settings; you cannot simply substitute strtol here, since
+ * it does obey locale.
+ */
+static off_t
+pkg_atol8(const char *p, unsigned char_cnt)
+{
+ int64_t l, limit, last_digit_limit;
+ int digit, sign, base;
+
+ base = 8;
+ limit = INT64_MAX / base;
+ last_digit_limit = INT64_MAX % base;
+
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (*p == '-') {
+ sign = -1;
+ p++;
+ } else
+ sign = 1;
+
+ l = 0;
+ digit = *p - '0';
+ while (digit >= 0 && digit < base && char_cnt-- > 0) {
+ if (l>limit || (l == limit && digit > last_digit_limit)) {
+ l = UINT64_MAX; /* Truncate on overflow. */
+ break;
+ }
+ l = (l * base) + digit;
+ digit = *++p - '0';
+ }
+ return (sign < 0) ? -l : l;
+}
+
+/*
+ * Parse a base-256 integer. This is just a straight signed binary
+ * value in big-endian order, except that the high-order bit is
+ * ignored. Remember that "int64_t" may or may not be exactly 64
+ * bits; the implementation here tries to avoid making any assumptions
+ * about the actual size of an int64_t. It does assume we're using
+ * twos-complement arithmetic, though.
+ */
+static int64_t
+pkg_atol256(const char *_p, unsigned char_cnt)
+{
+ int64_t l, upper_limit, lower_limit;
+ const unsigned char *p = (const unsigned char *)_p;
+
+ upper_limit = INT64_MAX / 256;
+ lower_limit = INT64_MIN / 256;
+
+ /* Pad with 1 or 0 bits, depending on sign. */
+ if ((0x40 & *p) == 0x40)
+ l = (int64_t)-1;
+ else
+ l = 0;
+ l = (l << 6) | (0x3f & *p++);
+ while (--char_cnt > 0) {
+ if (l > upper_limit) {
+ l = INT64_MAX; /* Truncate on overflow */
+ break;
+ } else if (l < lower_limit) {
+ l = INT64_MIN;
+ break;
+ }
+ l = (l << 8) | (0xff & (int64_t)*p++);
+ }
+ return (l);
+}
+
+static off_t
+pkg_atol(const char *p, unsigned char_cnt)
+{
+ /*
+ * Technically, GNU pkg considers a field to be in base-256
+ * only if the first byte is 0xff or 0x80.
+ */
+ if (*p & 0x80)
+ return (pkg_atol256(p, char_cnt));
+ return (pkg_atol8(p, char_cnt));
+}
+
+static int
+get_mode(struct tarfile *tf)
+{
+ return (pkg_atol(tf->tf_hdr.ut_mode, sizeof(tf->tf_hdr.ut_mode)));
+}
+
+/* GZip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+static int
+new_package(int fd, struct package **pp)
+{
+ struct package *pkg;
+ off_t ofs;
+ int flags, i, error;
+
+ pkg = malloc(sizeof(*pkg));
+ if (pkg == NULL)
+ return (ENOMEM);
+
+ bzero(pkg, sizeof(*pkg));
+ pkg->pkg_fd = fd;
+
+ /*
+ * Parse the header.
+ */
+ error = EFTYPE;
+ ofs = 0;
+
+ /* Check megic. */
+ if (get_byte(pkg, &ofs) != 0x1f || get_byte(pkg, &ofs) != 0x8b)
+ goto fail;
+ /* Check method. */
+ if (get_byte(pkg, &ofs) != Z_DEFLATED)
+ goto fail;
+ /* Check flags. */
+ flags = get_byte(pkg, &ofs);
+ if (flags & RESERVED)
+ goto fail;
+
+ /* Skip time, xflags and OS code. */
+ for (i = 0; i < 6; i++) {
+ if (get_byte(pkg, &ofs) == -1)
+ goto fail;
+ }
+
+ /* Skip extra field. */
+ if (flags & EXTRA_FIELD) {
+ i = (get_byte(pkg, &ofs) & 0xff) |
+ ((get_byte(pkg, &ofs) << 8) & 0xff);
+ while (i-- > 0) {
+ if (get_byte(pkg, &ofs) == -1)
+ goto fail;
+ }
+ }
+
+ /* Skip original file name. */
+ if (flags & ORIG_NAME) {
+ do {
+ i = get_byte(pkg, &ofs);
+ } while (i != 0 && i != -1);
+ if (i == -1)
+ goto fail;
+ }
+
+ /* Print the comment if it's there. */
+ if (flags & COMMENT) {
+ while (1) {
+ i = get_byte(pkg, &ofs);
+ if (i == -1)
+ goto fail;
+ if (i == 0)
+ break;
+ putchar(i);
+ }
+ }
+
+ /* Skip the CRC. */
+ if (flags & HEAD_CRC) {
+ if (get_byte(pkg, &ofs) == -1)
+ goto fail;
+ if (get_byte(pkg, &ofs) == -1)
+ goto fail;
+ }
+
+ /*
+ * Done parsing the ZIP header. Spkgt the inflation engine.
+ */
+ error = inflateInit2(&pkg->pkg_zs, -15);
+ if (error != Z_OK)
+ goto fail;
+
+ *pp = pkg;
+ return (0);
+
+ fail:
+ free(pkg);
+ return (error);
+}
+
+static struct tarfile *
+scan_tarfile(struct package *pkg, struct tarfile *last)
+{
+ char buf[512];
+ struct tarfile *cur;
+ off_t ofs;
+ size_t sz;
+
+ cur = (last != NULL) ? last->tf_next : pkg->pkg_first;
+ if (cur == NULL) {
+ ofs = (last != NULL) ? last->tf_ofs + last->tf_size :
+ pkg->pkg_ofs;
+ ofs = (ofs + 0x1ff) & ~0x1ff;
+
+ /* Check if we've reached EOF. */
+ if (ofs < pkg->pkg_ofs) {
+ errno = ENOSPC;
+ return (NULL);
+ }
+
+ if (ofs != pkg->pkg_ofs) {
+ if (last != NULL && pkg->pkg_ofs == last->tf_ofs) {
+ if (cache_data(last) == -1)
+ return (NULL);
+ } else {
+ sz = ofs - pkg->pkg_ofs;
+ while (sz != 0) {
+ if (sz > sizeof(buf))
+ sz = sizeof(buf);
+ if (get_zipped(pkg, buf, sz) == -1)
+ return (NULL);
+ sz = ofs - pkg->pkg_ofs;
+ }
+ }
+ }
+
+ cur = malloc(sizeof(*cur));
+ if (cur == NULL)
+ return (NULL);
+ memset(cur, 0, sizeof(*cur));
+ cur->tf_pkg = pkg;
+
+ while (1) {
+ if (get_zipped(pkg, &cur->tf_hdr,
+ sizeof(cur->tf_hdr)) == -1) {
+ free(cur);
+ return (NULL);
+ }
+
+ /*
+ * There are always 2 empty blocks appended to
+ * a PKG. It marks the end of the archive.
+ */
+ if (strncmp(cur->tf_hdr.ut_magic, "ustar", 5) != 0) {
+ free(cur);
+ errno = ENOSPC;
+ return (NULL);
+ }
+
+ cur->tf_ofs = pkg->pkg_ofs;
+ cur->tf_size = pkg_atol(cur->tf_hdr.ut_size,
+ sizeof(cur->tf_hdr.ut_size));
+
+ if (cur->tf_hdr.ut_name[0] != '+')
+ break;
+
+ /*
+ * Skip package meta-files.
+ */
+ ofs = cur->tf_ofs + cur->tf_size;
+ ofs = (ofs + 0x1ff) & ~0x1ff;
+ while (pkg->pkg_ofs < ofs) {
+ if (get_zipped(pkg, buf, sizeof(buf)) == -1) {
+ free(cur);
+ return (NULL);
+ }
+ }
+ }
+
+ if (last != NULL)
+ last->tf_next = cur;
+ else
+ pkg->pkg_first = cur;
+ pkg->pkg_last = cur;
+ }
+
+ return (cur);
+}
diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h
index 2808722..bcd146a 100644
--- a/lib/libstand/stand.h
+++ b/lib/libstand/stand.h
@@ -124,6 +124,7 @@ extern struct fs_ops bzipfs_fsops;
extern struct fs_ops dosfs_fsops;
extern struct fs_ops ext2fs_fsops;
extern struct fs_ops splitfs_fsops;
+extern struct fs_ops pkgfs_fsops;
/* where values for lseek(2) */
#define SEEK_SET 0 /* set file offset to offset */
@@ -364,6 +365,7 @@ extern int devopen(struct open_file *, const char *, const char **);
extern int devclose(struct open_file *f);
extern void panic(const char *, ...) __dead2 __printflike(1, 2);
extern struct fs_ops *file_system[];
+extern struct fs_ops *exclusive_file_system;
extern struct devsw *devsw[];
/*
diff --git a/lib/libstdthreads/threads.h b/lib/libstdthreads/threads.h
index aba9ca1..6f322a5 100644
--- a/lib/libstdthreads/threads.h
+++ b/lib/libstdthreads/threads.h
@@ -79,15 +79,24 @@ int cnd_broadcast(cnd_t *);
void cnd_destroy(cnd_t *);
int cnd_init(cnd_t *);
int cnd_signal(cnd_t *);
-int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict,
- const struct timespec *__restrict);
-int cnd_wait(cnd_t *, mtx_t *);
-void mtx_destroy(mtx_t *);
-int mtx_init(mtx_t *, int);
-int mtx_lock(mtx_t *);
-int mtx_timedlock(mtx_t *__restrict, const struct timespec *__restrict);
-int mtx_trylock(mtx_t *);
-int mtx_unlock(mtx_t *);
+int cnd_timedwait(cnd_t *__restrict, mtx_t *__restrict __mtx,
+ const struct timespec *__restrict)
+ __requires_exclusive(*__mtx);
+int cnd_wait(cnd_t *, mtx_t *__mtx)
+ __requires_exclusive(*__mtx);
+void mtx_destroy(mtx_t *__mtx)
+ __requires_unlocked(*__mtx);
+int mtx_init(mtx_t *__mtx, int)
+ __requires_unlocked(*__mtx);
+int mtx_lock(mtx_t *__mtx)
+ __locks_exclusive(*__mtx);
+int mtx_timedlock(mtx_t *__restrict __mtx,
+ const struct timespec *__restrict)
+ __trylocks_exclusive(thrd_success, *__mtx);
+int mtx_trylock(mtx_t *__mtx)
+ __trylocks_exclusive(thrd_success, *__mtx);
+int mtx_unlock(mtx_t *__mtx)
+ __unlocks(*__mtx);
int thrd_create(thrd_t *, thrd_start_t, void *);
thrd_t thrd_current(void);
int thrd_detach(thrd_t);
diff --git a/lib/libthr/Makefile b/lib/libthr/Makefile
index cfcc41e..5cbd0aa 100644
--- a/lib/libthr/Makefile
+++ b/lib/libthr/Makefile
@@ -64,4 +64,6 @@ SYMLINKS+=lib${LIB}_p.a ${LIBDIR}/libpthread_p.a
CFLAGS+=-DSYSCALL_COMPAT
.endif
+.include <bsd.arch.inc.mk>
+
.include <bsd.lib.mk>
diff --git a/lib/libthr/Makefile.amd64 b/lib/libthr/Makefile.amd64
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/libthr/Makefile.amd64
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/libthr/Makefile.i386 b/lib/libthr/Makefile.i386
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/libthr/Makefile.i386
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/libthr/libthr.3 b/lib/libthr/libthr.3
index bfbebec..4b636ce 100644
--- a/lib/libthr/libthr.3
+++ b/lib/libthr/libthr.3
@@ -1,6 +1,11 @@
.\" Copyright (c) 2005 Robert N. M. Watson
+.\" Copyright (c) 2014 The FreeBSD Foundation, Inc.
.\" All rights reserved.
.\"
+.\" Part of this documentation was written by
+.\" Konstantin Belousov <kib@FreeBSD.org> under sponsorship
+.\" from the FreeBSD Foundation.
+.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
@@ -24,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd October 19, 2007
+.Dd September 26, 2014
.Dt LIBTHR 3
.Os
.Sh NAME
@@ -45,8 +50,222 @@ has been optimized for use by applications expecting system scope thread
semantics, and can provide significant performance improvements
compared to
.Lb libkse .
+.Pp
+The library is tightly integrated with the run-time link editor
+.Xr ld-elf.so.1 1
+and
+.Lb libc ;
+all three components must be built from the same source tree.
+Mixing
+.Li libc
+and
+.Nm
+libraries from different versions of
+.Fx
+is not supported.
+The run-time linker
+.Xr ld-elf.so.1 1
+has some code to ensure backward-compatibility with older versions of
+.Nm .
+.Pp
+The man page documents the quirks and tunables of the
+.Nm .
+When linking with
+.Li -lpthread ,
+the run-time dependency
+.Li libthr.so.3
+is recorded in the produced object.
+.Sh MUTEX ACQUISITION
+A locked mutex (see
+.Xr pthread_mutex_lock 3 )
+is represented by a volatile variable of type
+.Dv lwpid_t ,
+which records the global system identifier of the thread
+owning the lock.
+.Nm
+performs a contested mutex acquisition in three stages, each of which
+is more resource-consuming than the previous.
+The first two stages are only applied for a mutex of
+.Dv PTHREAD_MUTEX_ADAPTIVE_NP
+type and
+.Dv PTHREAD_PRIO_NONE
+protocol (see
+.Xr pthread_mutexattr 3 ) .
+.Pp
+First, on SMP systems, a spin loop
+is performed, where the library attempts to acquire the lock by
+.Xr atomic 9
+operations.
+The loop count is controlled by the
+.Ev LIBPTHREAD_SPINLOOPS
+environment variable, with a default value of 2000.
+.Pp
+If the spin loop
+was unable to acquire the mutex, a yield loop
+is executed, performing the same
+.Xr atomic 9
+acquisition attempts as the spin loop,
+but each attempt is followed by a yield of the CPU time
+of the thread using the
+.Xr sched_yield 2
+syscall.
+By default, the yield loop
+is not executed.
+This is controlled by the
+.Ev LIBPTHREAD_YIELDLOOPS
+environment variable.
+.Pp
+If both the spin and yield loops
+failed to acquire the lock, the thread is taken off the CPU and
+put to sleep in the kernel with the
+.Xr umtx 2
+syscall.
+The kernel wakes up a thread and hands the ownership of the lock to
+the woken thread when the lock becomes available.
+.Sh THREAD STACKS
+Each thread is provided with a private user-mode stack area
+used by the C runtime.
+The size of the main (initial) thread stack is set by the kernel, and is
+controlled by the
+.Dv RLIMIT_STACK
+process resource limit (see
+.Xr getrlimit 2 ) .
+.Pp
+By default, the main thread's stack size is equal to the value of
+.Dv RLIMIT_STACK
+for the process.
+If the
+.Ev LIBPTHREAD_SPLITSTACK_MAIN
+environment variable is present in the process environment
+(its value does not matter),
+the main thread's stack is reduced to 4MB on 64bit architectures, and to
+2MB on 32bit architectures, when the threading library is initialized.
+The rest of the address space area which has been reserved by the
+kernel for the initial process stack is used for non-initial thread stacks
+in this case.
+The presence of the
+.Ev LIBPTHREAD_BIGSTACK_MAIN
+environment variable overrides
+.Ev LIBPTHREAD_SPLITSTACK_MAIN ;
+it is kept for backward-compatibility.
+.Pp
+The size of stacks for threads created by the process at run-time
+with the
+.Xr pthread_create 3
+call is controlled by thread attributes: see
+.Xr pthread_attr 3 ,
+in particular, the
+.Xr pthread_attr_setstacksize 3 ,
+.Xr pthread_attr_setguardsize 3
+and
+.Xr pthread_attr_setstackaddr 3
+functions.
+If no attributes for the thread stack size are specified, the default
+non-initial thread stack size is 2MB for 64bit architectures, and 1MB
+for 32bit architectures.
+.Sh RUN-TIME SETTINGS
+The following environment variables are recognized by
+.Nm
+and adjust the operation of the library at run-time:
+.Bl -tag -width LIBPTHREAD_SPLITSTACK_MAIN
+.It Ev LIBPTHREAD_BIGSTACK_MAIN
+Disables the reduction of the initial thread stack enabled by
+.Ev LIBPTHREAD_SPLITSTACK_MAIN .
+.It Ev LIBPTHREAD_SPLITSTACK_MAIN
+Causes a reduction of the initial thread stack, as described in the
+section
+.Sx THREAD STACKS .
+This was the default behaviour of
+.Nm
+before
+.Fx 11.0 .
+.It Ev LIBPTHREAD_SPINLOOPS
+The integer value of the variable overrides the default count of
+iterations in the
+.Li spin loop
+of the mutex acquisition.
+The default count is 2000, set by the
+.Dv MUTEX_ADAPTIVE_SPINS
+constant in the
+.Nm
+sources.
+.It Ev LIBPTHREAD_YIELDLOOPS
+A non-zero integer value enables the yield loop
+in the process of the mutex acquisition.
+The value is the count of loop operations.
+.It Ev LIBPTHREAD_QUEUE_FIFO
+The integer value of the variable specifies how often blocked
+threads are inserted at the head of the sleep queue, instead of its tail.
+Bigger values reduce the frequency of the FIFO discipline.
+The value must be between 0 and 255.
+.El
+.Sh INTERACTION WITH RUN-TIME LINKER
+The
+.Nm
+library must appear before
+.Li libc
+in the global order of depended objects.
+.Pp
+Loading
+.Nm
+with the
+.Xr dlopen 3
+call in the process after the program binary is activated
+is not supported, and causes miscellaneous and hard-to-diagnose misbehaviour.
+This is due to
+.Nm
+interposing several important
+.Li libc
+symbols to provide thread-safe services.
+In particular,
+.Dv errno
+and the locking stubs from
+.Li libc
+are affected.
+This requirement is currently not enforced.
+.Pp
+If the program loads any modules at run-time, and those modules may require
+threading services, the main program binary must be linked with
+.Li libpthread ,
+even if it does not require any services from the library.
+.Pp
+.Nm
+cannot be unloaded; the
+.Xr dlclose 3
+function does not perform any action when called with a handle for
+.Nm .
+One of the reasons is that the interposing of
+.Li libc
+functions cannot be undone.
+.Sh SIGNALS
+The implementation also interposes the user-installed
+.Xr signal 3
+handlers.
+This interposing is done to postpone signal delivery to threads which
+entered (libthr-internal) critical sections, where the calling
+of the user-provided signal handler is unsafe.
+An example of such a situation is owning the internal library lock.
+When a signal is delivered while the signal handler cannot be safely
+called, the call is postponed and performed until after the exit from
+the critical section.
+This should be taken into account when interpreting
+.Xr ktrace 1
+logs.
.Sh SEE ALSO
-.Xr pthread 3
+.Xr ktrace 1 ,
+.Xr ld-elf.so.1 1 ,
+.Xr getrlimit 2 ,
+.Xr umtx 2 ,
+.Xr dlclose 3 ,
+.Xr dlopen 3 ,
+.Xr errno 3 ,
+.Xr getenv 3 ,
+.Xr libc 3 ,
+.Xr pthread_attr 3 ,
+.Xr pthread_attr_setstacksize 3 ,
+.Xr pthread_create 3 ,
+.Xr signal 3 ,
+.Xr atomic 9
.Sh AUTHORS
.An -nosplit
The
diff --git a/lib/libthr/tests/Makefile b/lib/libthr/tests/Makefile
new file mode 100644
index 0000000..50f07f0
--- /dev/null
+++ b/lib/libthr/tests/Makefile
@@ -0,0 +1,58 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread
+
+TESTSDIR= ${TESTSBASE}/lib/libthr
+
+# TODO: t_name (missing pthread_getname_np support in FreeBSD)
+NETBSD_ATF_TESTS_C= barrier_test
+NETBSD_ATF_TESTS_C+= cond_test
+NETBSD_ATF_TESTS_C+= condwait_test
+NETBSD_ATF_TESTS_C+= detach_test
+NETBSD_ATF_TESTS_C+= equal_test
+NETBSD_ATF_TESTS_C+= fork_test
+NETBSD_ATF_TESTS_C+= fpu_test
+NETBSD_ATF_TESTS_C+= join_test
+NETBSD_ATF_TESTS_C+= kill_test
+NETBSD_ATF_TESTS_C+= mutex_test
+NETBSD_ATF_TESTS_C+= once_test
+NETBSD_ATF_TESTS_C+= preempt_test
+NETBSD_ATF_TESTS_C+= rwlock_test
+NETBSD_ATF_TESTS_C+= sem_test
+NETBSD_ATF_TESTS_C+= sigmask_test
+NETBSD_ATF_TESTS_C+= sigsuspend_test
+NETBSD_ATF_TESTS_C+= siglongjmp_test
+NETBSD_ATF_TESTS_C+= sleep_test
+NETBSD_ATF_TESTS_C+= swapcontext_test
+
+NETBSD_ATF_TESTS_SH= atexit_test
+NETBSD_ATF_TESTS_SH+= cancel_test
+NETBSD_ATF_TESTS_SH+= exit_test
+NETBSD_ATF_TESTS_SH+= resolv_test
+
+DPADD+= ${LIBPTHREAD}
+LDADD+= -lpthread
+DPADD.fpu_test+= ${LIBM}
+LDADD.fpu_test+= -lm
+DPADD.sem_test+= ${LIBRT}
+LDADD.sem_test+= -lrt
+
+BINDIR= ${TESTSDIR}
+
+PROGS= h_atexit
+PROGS+= h_cancel
+PROGS+= h_exit
+PROGS+= h_resolv
+
+FILESDIR= ${TESTSDIR}
+FILES= d_mach
+
+TESTS_SUBDIRS= dlopen
+
+.include <netbsd-tests.test.mk>
+
+CFLAGS.condwait_test+= -I${SRCTOP}/contrib/netbsd-tests/lib/libc/gen
+
+.include <bsd.test.mk>
diff --git a/lib/libthr/tests/dlopen/Makefile b/lib/libthr/tests/dlopen/Makefile
new file mode 100644
index 0000000..0764bfa
--- /dev/null
+++ b/lib/libthr/tests/dlopen/Makefile
@@ -0,0 +1,30 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread/dlopen
+
+.include <bsd.own.mk>
+
+TESTSDIR= ${TESTSBASE}/lib/libthr/dlopen
+
+CFLAGS+= -DTESTDIR=\"${TESTSDIR:Q}/\"
+LDFLAGS+= -L${.OBJDIR}/dso -Wl,-rpath=${TESTDIR}
+
+.if !defined(NO_PIC)
+SUBDIR+= dso
+
+NETBSD_ATF_TESTS_C= dlopen_test
+NETBSD_ATF_TESTS_C+= main_pthread_create_test
+# XXX: this blocks running the testcase
+#NETBSD_ATF_TESTS_C+= dso_pthread_create_test
+
+.for t in dlopen_test main_pthread_create_test
+DPADD.$t+= ${LIBPTHREAD}
+LDADD.$t+= -lpthread
+.endfor
+.endif
+
+.include <netbsd-tests.test.mk>
+
+.include <bsd.test.mk>
diff --git a/lib/libthr/tests/dlopen/dso/Makefile b/lib/libthr/tests/dlopen/dso/Makefile
new file mode 100644
index 0000000..080dec9
--- /dev/null
+++ b/lib/libthr/tests/dlopen/dso/Makefile
@@ -0,0 +1,19 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libpthread/dlopen/dso
+
+SHLIB= h_pthread_dlopen
+SHLIB_MAJOR= 1
+SHLIB_NAME= h_pthread_dlopen.so.${SHLIB_MAJOR}
+SRCS= h_pthread_dlopen.c
+
+DPADD+= ${LIBPTHREAD}
+LDADD+= -lpthread
+
+LIBDIR= ${TESTSBASE}/lib/libthr/dlopen
+
+.include <netbsd-tests.test.mk>
+
+.include <bsd.lib.mk>
diff --git a/lib/libthr/thread/thr_cond.c b/lib/libthr/thread/thr_cond.c
index 6af15db..71b4293 100644
--- a/lib/libthr/thread/thr_cond.c
+++ b/lib/libthr/thread/thr_cond.c
@@ -150,7 +150,7 @@ _pthread_cond_destroy(pthread_cond_t *cond)
}
/*
- * Cancellation behaivor:
+ * Cancellation behavior:
* Thread may be canceled at start, if thread is canceled, it means it
* did not get a wakeup from pthread_cond_signal(), otherwise, it is
* not canceled.
diff --git a/lib/libthr/thread/thr_init.c b/lib/libthr/thread/thr_init.c
index 937d83f..6d6a532 100644
--- a/lib/libthr/thread/thr_init.c
+++ b/lib/libthr/thread/thr_init.c
@@ -37,6 +37,7 @@
#include <sys/types.h>
#include <sys/signalvar.h>
#include <sys/ioctl.h>
+#include <sys/resource.h>
#include <sys/sysctl.h>
#include <sys/ttycom.h>
#include <sys/mman.h>
@@ -441,9 +442,10 @@ init_main_thread(struct pthread *thread)
static void
init_private(void)
{
+ struct rlimit rlim;
size_t len;
int mib[2];
- char *env;
+ char *env, *env_bigstack, *env_splitstack;
_thr_umutex_init(&_mutex_static_lock);
_thr_umutex_init(&_cond_static_lock);
@@ -471,6 +473,13 @@ init_private(void)
len = sizeof (_usrstack);
if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1)
PANIC("Cannot get kern.usrstack from sysctl");
+ env_bigstack = getenv("LIBPTHREAD_BIGSTACK_MAIN");
+ env_splitstack = getenv("LIBPTHREAD_SPLITSTACK_MAIN");
+ if (env_bigstack != NULL || env_splitstack == NULL) {
+ if (getrlimit(RLIMIT_STACK, &rlim) == -1)
+ PANIC("Cannot get stack rlimit");
+ _thr_stack_initial = rlim.rlim_cur;
+ }
len = sizeof(_thr_is_smp);
sysctlbyname("kern.smp.cpus", &_thr_is_smp, &len, NULL, 0);
_thr_is_smp = (_thr_is_smp > 1);
diff --git a/lib/libthr/thread/thr_stack.c b/lib/libthr/thread/thr_stack.c
index 15a9c82..e5d149e 100644
--- a/lib/libthr/thread/thr_stack.c
+++ b/lib/libthr/thread/thr_stack.c
@@ -246,7 +246,10 @@ _thr_stack_alloc(struct pthread_attr *attr)
THREAD_LIST_UNLOCK(curthread);
}
else {
- /* Allocate a stack from usrstack. */
+ /*
+ * Allocate a stack from or below usrstack, depending
+ * on the LIBPTHREAD_BIGSTACK_MAIN env variable.
+ */
if (last_stack == NULL)
last_stack = _usrstack - _thr_stack_initial -
_thr_guard_default;
@@ -268,7 +271,7 @@ _thr_stack_alloc(struct pthread_attr *attr)
/* Map the stack and guard page together, and split guard
page from allocated space: */
- if ((stackaddr = mmap(stackaddr, stacksize+guardsize,
+ if ((stackaddr = mmap(stackaddr, stacksize + guardsize,
_rtld_get_stack_prot(), MAP_STACK,
-1, 0)) != MAP_FAILED &&
(guardsize == 0 ||
diff --git a/lib/libunbound/Makefile b/lib/libunbound/Makefile
index c6bbede..aca3023 100644
--- a/lib/libunbound/Makefile
+++ b/lib/libunbound/Makefile
@@ -33,7 +33,7 @@ LDADD+= -lssl -lcrypto -lpthread
# Misnamed file in upstream source
configlexer.l: configlexer.lex
- cp -p ${.ALLSRC} ${.TARGET}
+ cp -fp ${.ALLSRC} ${.TARGET}
CLEANFILES+= configlexer.l
# Symbol prefix for lex and yacc
diff --git a/lib/libusb/Makefile b/lib/libusb/Makefile
index 92c0843..1ef85d4 100644
--- a/lib/libusb/Makefile
+++ b/lib/libusb/Makefile
@@ -38,6 +38,7 @@ SRCS+= libusb10_io.c
CFLAGS+= -DCOMPAT_32BIT
.endif
+.ifndef COMPAT_32BIT
beforeinstall:
${INSTALL} -C -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
${.CURDIR}/libusb-0.1.pc ${DESTDIR}${LIBDATADIR}/pkgconfig
@@ -45,6 +46,7 @@ beforeinstall:
${.CURDIR}/libusb-1.0.pc ${DESTDIR}${LIBDATADIR}/pkgconfig
${INSTALL} -C -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
${.CURDIR}/libusb-2.0.pc ${DESTDIR}${LIBDATADIR}/pkgconfig
+.endif
#
# Cross platform support
diff --git a/lib/libusb/libusb.h b/lib/libusb/libusb.h
index e490f24..7f8634f 100644
--- a/lib/libusb/libusb.h
+++ b/lib/libusb/libusb.h
@@ -51,10 +51,18 @@ enum libusb_class_code {
LIBUSB_CLASS_COMM = 2,
LIBUSB_CLASS_HID = 3,
LIBUSB_CLASS_PTP = 6,
+ LIBUSB_CLASS_IMAGE = 6,
LIBUSB_CLASS_PRINTER = 7,
LIBUSB_CLASS_MASS_STORAGE = 8,
LIBUSB_CLASS_HUB = 9,
LIBUSB_CLASS_DATA = 10,
+ LIBUSB_CLASS_SMART_CARD = 11,
+ LIBUSB_CLASS_CONTENT_SECURITY = 13,
+ LIBUSB_CLASS_VIDEO = 14,
+ LIBUSB_CLASS_PERSONAL_HEALTHCARE = 15,
+ LIBUSB_CLASS_DIAGNOSTIC_DEVICE = 0xdc,
+ LIBUSB_CLASS_WIRELESS = 0xe0,
+ LIBUSB_CLASS_APPLICATION = 0xfe,
LIBUSB_CLASS_VENDOR_SPEC = 0xff,
};
diff --git a/lib/libutil/Makefile b/lib/libutil/Makefile
index 5e5139f..7e5f1a3 100644
--- a/lib/libutil/Makefile
+++ b/lib/libutil/Makefile
@@ -81,4 +81,8 @@ MLINKS+=pw_util.3 pw_copy.3 \
pw_util.3 pw_tempname.3 \
pw_util.3 pw_tmp.3
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
.include <bsd.lib.mk>
diff --git a/lib/libutil/gr_util.c b/lib/libutil/gr_util.c
index 6f74507..465efd9 100644
--- a/lib/libutil/gr_util.c
+++ b/lib/libutil/gr_util.c
@@ -170,14 +170,21 @@ gr_copy(int ffd, int tfd, const struct group *gr, struct group *old_gr)
size_t len;
int eof, readlen;
- sgr = gr;
+ if (old_gr == NULL && gr == NULL)
+ return(-1);
+
+ sgr = old_gr;
+ /* deleting a group */
if (gr == NULL) {
line = NULL;
- if (old_gr == NULL)
+ } else {
+ if ((line = gr_make(gr)) == NULL)
return (-1);
- sgr = old_gr;
- } else if ((line = gr_make(gr)) == NULL)
- return (-1);
+ }
+
+ /* adding a group */
+ if (sgr == NULL)
+ sgr = gr;
eof = 0;
len = 0;
diff --git a/lib/libutil/login_class.c b/lib/libutil/login_class.c
index 39cce12..9ffca8e 100644
--- a/lib/libutil/login_class.c
+++ b/lib/libutil/login_class.c
@@ -424,7 +424,7 @@ setlogincontext(login_cap_t *lc, const struct passwd *pwd,
int
setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned int flags)
{
- quad_t p;
+ rlim_t p;
mode_t mymask;
login_cap_t *llc = NULL;
struct sigaction sa, prevsa;
@@ -449,16 +449,16 @@ setusercontext(login_cap_t *lc, const struct passwd *pwd, uid_t uid, unsigned in
if (p > PRIO_MAX) {
rtp.type = RTP_PRIO_IDLE;
- rtp.prio = p - PRIO_MAX - 1;
- p = (rtp.prio > RTP_PRIO_MAX) ? 31 : p;
+ p -= PRIO_MAX + 1;
+ rtp.prio = p > RTP_PRIO_MAX ? RTP_PRIO_MAX : p;
if (rtprio(RTP_SET, 0, &rtp))
syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
pwd ? pwd->pw_name : "-",
lc ? lc->lc_class : LOGIN_DEFCLASS);
} else if (p < PRIO_MIN) {
rtp.type = RTP_PRIO_REALTIME;
- rtp.prio = abs(p - PRIO_MIN + RTP_PRIO_MAX);
- p = (rtp.prio > RTP_PRIO_MAX) ? 1 : p;
+ p -= PRIO_MIN - RTP_PRIO_MAX;
+ rtp.prio = p < RTP_PRIO_MIN ? RTP_PRIO_MIN : p;
if (rtprio(RTP_SET, 0, &rtp))
syslog(LOG_WARNING, "rtprio '%s' (%s): %m",
pwd ? pwd->pw_name : "-",
diff --git a/lib/libutil/tests/Makefile b/lib/libutil/tests/Makefile
new file mode 100644
index 0000000..31b6c54
--- /dev/null
+++ b/lib/libutil/tests/Makefile
@@ -0,0 +1,15 @@
+# $FreeBSD$
+
+TESTSDIR= ${TESTSBASE}/lib/libutil
+
+TAP_TESTS_C+= flopen_test
+TAP_TESTS_C+= grp_test
+TAP_TESTS_C+= humanize_number_test
+TAP_TESTS_C+= pidfile_test
+TAP_TESTS_C+= trimdomain_test
+TAP_TESTS_C+= trimdomain-nodomain_test
+
+DPADD+= ${LIBUTIL}
+LDADD+= -lutil
+
+.include <bsd.test.mk>
diff --git a/lib/libutil/tests/flopen_test.c b/lib/libutil/tests/flopen_test.c
new file mode 100644
index 0000000..0471584
--- /dev/null
+++ b/lib/libutil/tests/flopen_test.c
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (c) 2007-2009 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/types.h>
+#include <sys/fcntl.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+/*
+ * Test that flopen() can create a file.
+ */
+const char *
+test_flopen_create(void)
+{
+ const char *fn = "test_flopen_create";
+ const char *result = NULL;
+ int fd;
+
+ unlink(fn);
+ fd = flopen(fn, O_RDWR|O_CREAT, 0640);
+ if (fd < 0) {
+ result = strerror(errno);
+ } else {
+ close(fd);
+ }
+ unlink(fn);
+ return (result);
+}
+
+/*
+ * Test that flopen() can open an existing file.
+ */
+const char *
+test_flopen_open(void)
+{
+ const char *fn = "test_flopen_open";
+ const char *result = NULL;
+ int fd;
+
+ fd = open(fn, O_RDWR|O_CREAT, 0640);
+ if (fd < 0) {
+ result = strerror(errno);
+ } else {
+ close(fd);
+ fd = flopen(fn, O_RDWR);
+ if (fd < 0) {
+ result = strerror(errno);
+ } else {
+ close(fd);
+ }
+ }
+ unlink(fn);
+ return (result);
+}
+
+/*
+ * Test that flopen() can lock against itself
+ */
+const char *
+test_flopen_lock_self(void)
+{
+ const char *fn = "test_flopen_lock_self";
+ const char *result = NULL;
+ int fd1, fd2;
+
+ unlink(fn);
+ fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
+ if (fd1 < 0) {
+ result = strerror(errno);
+ } else {
+ fd2 = flopen(fn, O_RDWR|O_NONBLOCK);
+ if (fd2 >= 0) {
+ result = "second open succeeded";
+ close(fd2);
+ }
+ close(fd1);
+ }
+ unlink(fn);
+ return (result);
+}
+
+/*
+ * Test that flopen() can lock against other processes
+ */
+const char *
+test_flopen_lock_other(void)
+{
+ const char *fn = "test_flopen_lock_other";
+ const char *result = NULL;
+ volatile int fd1, fd2;
+
+ unlink(fn);
+ fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
+ if (fd1 < 0) {
+ result = strerror(errno);
+ } else {
+ fd2 = -42;
+ if (vfork() == 0) {
+ fd2 = flopen(fn, O_RDWR|O_NONBLOCK);
+ close(fd2);
+ _exit(0);
+ }
+ if (fd2 == -42)
+ result = "vfork() doesn't work as expected";
+ if (fd2 >= 0)
+ result = "second open succeeded";
+ close(fd1);
+ }
+ unlink(fn);
+ return (result);
+}
+
+/*
+ * Test that child processes inherit the lock
+ */
+const char *
+test_flopen_lock_child(void)
+{
+ const char *fn = "test_flopen_lock_child";
+ const char *result = NULL;
+ pid_t pid;
+ volatile int fd1, fd2;
+
+ unlink(fn);
+ fd1 = flopen(fn, O_RDWR|O_CREAT, 0640);
+ if (fd1 < 0) {
+ result = strerror(errno);
+ } else {
+ pid = fork();
+ if (pid == -1) {
+ result = strerror(errno);
+ } else if (pid == 0) {
+ select(0, 0, 0, 0, 0);
+ _exit(0);
+ }
+ close(fd1);
+ if ((fd2 = flopen(fn, O_RDWR|O_NONBLOCK)) != -1) {
+ result = "second open succeeded";
+ close(fd2);
+ }
+ kill(pid, SIGINT);
+ }
+ unlink(fn);
+ return (result);
+}
+
+static struct test {
+ const char *name;
+ const char *(*func)(void);
+} t[] = {
+ { "flopen_create", test_flopen_create },
+ { "flopen_open", test_flopen_open },
+ { "flopen_lock_self", test_flopen_lock_self },
+ { "flopen_lock_other", test_flopen_lock_other },
+ { "flopen_lock_child", test_flopen_lock_child },
+};
+
+int
+main(void)
+{
+ const char *result;
+ int i, nt;
+
+ nt = sizeof(t) / sizeof(*t);
+ printf("1..%d\n", nt);
+ for (i = 0; i < nt; ++i) {
+ if ((result = t[i].func()) != NULL)
+ printf("not ok %d - %s # %s\n", i + 1,
+ t[i].name, result);
+ else
+ printf("ok %d - %s\n", i + 1,
+ t[i].name);
+ }
+ exit(0);
+}
diff --git a/lib/libutil/tests/grp_test.c b/lib/libutil/tests/grp_test.c
new file mode 100644
index 0000000..ae7ce73
--- /dev/null
+++ b/lib/libutil/tests/grp_test.c
@@ -0,0 +1,117 @@
+/*-
+ * Copyright (c) 2008 Sean C. Farley <scf@FreeBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <errno.h>
+#include <grp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <libutil.h>
+
+
+/*
+ * Static values for building and testing an artificial group.
+ */
+static char grpName[] = "groupName";
+static char grpPasswd[] = "groupPwd";
+static gid_t grpGID = 1234;
+static char *grpMems[] = { "mem1", "mem2", "mem3", NULL };
+static const char *origStrGrp = "groupName:groupPwd:1234:mem1,mem2,mem3";
+
+
+/*
+ * Build a group to test against without depending on a real group to be found
+ * within /etc/group.
+ */
+static void
+build_grp(struct group *grp)
+{
+ grp->gr_name = grpName;
+ grp->gr_passwd = grpPasswd;
+ grp->gr_gid = grpGID;
+ grp->gr_mem = grpMems;
+
+ return;
+}
+
+
+int
+main(void)
+{
+ char *strGrp;
+ int testNdx;
+ struct group *dupGrp;
+ struct group *scanGrp;
+ struct group origGrp;
+
+ /* Setup. */
+ printf("1..4\n");
+ testNdx = 0;
+
+ /* Manually build a group using static values. */
+ build_grp(&origGrp);
+
+ /* Copy the group. */
+ testNdx++;
+ if ((dupGrp = gr_dup(&origGrp)) == NULL)
+ printf("not ");
+ printf("ok %d - %s\n", testNdx, "gr_dup");
+
+ /* Compare the original and duplicate groups. */
+ testNdx++;
+ if (! gr_equal(&origGrp, dupGrp))
+ printf("not ");
+ printf("ok %d - %s\n", testNdx, "gr_equal");
+
+ /* Create group string from the duplicate group structure. */
+ testNdx++;
+ strGrp = gr_make(dupGrp);
+ if (strcmp(strGrp, origStrGrp) != 0)
+ printf("not ");
+ printf("ok %d - %s\n", testNdx, "gr_make");
+
+ /*
+ * Create group structure from string and compare it to the original
+ * group structure.
+ */
+ testNdx++;
+ if ((scanGrp = gr_scan(strGrp)) == NULL || ! gr_equal(&origGrp,
+ scanGrp))
+ printf("not ");
+ printf("ok %d - %s\n", testNdx, "gr_scan");
+
+ /* Clean up. */
+ free(scanGrp);
+ free(strGrp);
+ free(dupGrp);
+
+ exit(EXIT_SUCCESS);
+}
diff --git a/lib/libutil/tests/humanize_number_test.c b/lib/libutil/tests/humanize_number_test.c
new file mode 100644
index 0000000..2d66204
--- /dev/null
+++ b/lib/libutil/tests/humanize_number_test.c
@@ -0,0 +1,598 @@
+/*-
+ * Copyright 2012 Clifton Royston
+ * Copyright 2013 John-Mark Gurney
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (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$
+ *
+ */
+
+#include <sys/param.h>
+#include <inttypes.h>
+#include <libutil.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define MAX_STR_FLAGS_RESULT 80
+#define MAX_INT_STR_DIGITS 12
+
+static const int64_t halfExabyte = (int64_t)500*1000*1000*1000*1000*1000L;
+
+static struct {
+ int retval;
+ const char *res;
+ int64_t num;
+ int flags;
+ int scale;
+} test_args[] = {
+ /* tests 0-13 test 1000 suffixes */
+ { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+
+ /* tests 14-27 test 1024 suffixes */
+ { 2, "0 ", (int64_t)0L, 0, HN_AUTOSCALE },
+ { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE },
+ { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE },
+ { 3, "1 G", (int64_t)512*1024*1024L, 0, HN_AUTOSCALE },
+ { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 2, "1 ", (int64_t)1L, 0, HN_AUTOSCALE },
+ { 3, "2 K", (int64_t)1536L, 0, HN_AUTOSCALE },
+ { 3, "2 M", (int64_t)1536*1024L, 0, HN_AUTOSCALE },
+ { 3, "2 G", (int64_t)1536*1024*1024L, 0, HN_AUTOSCALE },
+ { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+
+ /* tests 28-37 test rounding */
+ { 3, "0 M", (int64_t)500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "1 M", (int64_t)1000*1000L + 500*1000L-1, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "2 M", (int64_t)1000*1000L + 500*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 3, "0 K", (int64_t)512L-1, 0, HN_AUTOSCALE },
+ { 3, "1 K", (int64_t)512L, 0, HN_AUTOSCALE },
+ { 3, "0 M", (int64_t)512*1024L-1, 0, HN_AUTOSCALE },
+ { 3, "1 M", (int64_t)512*1024L, 0, HN_AUTOSCALE },
+ { 3, "1 M", (int64_t)1024*1024L + 512*1024L-1, 0, HN_AUTOSCALE },
+ { 3, "2 M", (int64_t)1024*1024L + 512*1024L, 0, HN_AUTOSCALE },
+
+ /* tests 38-61 test specific scale factors with 1000 divisor */
+ { 3, "0 k", (int64_t)0L, HN_DIVISOR_1000, 1 },
+ { 3, "1 k", (int64_t)500L, HN_DIVISOR_1000, 1 },
+ { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, 2 },
+ { 3, "1 M", (int64_t)500*1000L, HN_DIVISOR_1000, 2 },
+ { 3, "0 G", (int64_t)500*1000L, HN_DIVISOR_1000, 3 },
+ { 3, "1 G", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 3 },
+ { 3, "0 T", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 4 },
+ { 3, "1 T", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 4 },
+ { 3, "0 P", (int64_t)500*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+ { 3, "1 P", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+ { 3, "0 E", (int64_t)500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+ { 3, "1 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+ { 3, "0 k", (int64_t)1L, HN_DIVISOR_1000, 1 },
+ { 3, "2 k", (int64_t)1500L, HN_DIVISOR_1000, 1 },
+ { 3, "0 M", (int64_t)1500L, HN_DIVISOR_1000, 2 },
+ { 3, "2 M", (int64_t)1500*1000L, HN_DIVISOR_1000, 2 },
+ { 3, "0 G", (int64_t)1500*1000L, HN_DIVISOR_1000, 3 },
+ { 3, "2 G", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 3 },
+ { 3, "0 T", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 4 },
+ { 3, "2 T", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 4 },
+ { 3, "0 P", (int64_t)1500*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+ { 3, "2 P", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+ { 3, "0 E", (int64_t)1500*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+ { 3, "2 E", (int64_t)1500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+
+ /* tests 62-85 test specific scale factors with 1024 divisor */
+ { 3, "0 K", (int64_t)0L, 0, 1 },
+ { 3, "1 K", (int64_t)512L, 0, 1 },
+ { 3, "0 M", (int64_t)512L, 0, 2 },
+ { 3, "1 M", (int64_t)512*1024L, 0, 2 },
+ { 3, "0 G", (int64_t)512*1024L, 0, 3 },
+ { 3, "1 G", (int64_t)512*1024*1024L, 0, 3 },
+ { 3, "0 T", (int64_t)512*1024*1024L, 0, 4 },
+ { 3, "1 T", (int64_t)512*1024*1024*1024L, 0, 4 },
+ { 3, "0 P", (int64_t)512*1024*1024*1024L, 0, 5 },
+ { 3, "1 P", (int64_t)512*1024*1024*1024*1024L, 0, 5 },
+ { 3, "0 E", (int64_t)512*1024*1024*1024*1024L, 0, 6 },
+ { 3, "1 E", (int64_t)512*1024*1024*1024*1024*1024L, 0, 6 },
+ { 3, "0 K", (int64_t)1L, 0, 1 },
+ { 3, "2 K", (int64_t)1536L, 0, 1 },
+ { 3, "0 M", (int64_t)1536L, 0, 2 },
+ { 3, "2 M", (int64_t)1536*1024L, 0, 2 },
+ { 3, "0 G", (int64_t)1536*1024L, 0, 3 },
+ { 3, "2 G", (int64_t)1536*1024*1024L, 0, 3 },
+ { 3, "0 T", (int64_t)1536*1024*1024L, 0, 4 },
+ { 3, "2 T", (int64_t)1536*1024*1024*1024L, 0, 4 },
+ { 3, "0 P", (int64_t)1536*1024*1024*1024L, 0, 5 },
+ { 3, "2 P", (int64_t)1536*1024*1024*1024*1024L, 0, 5 },
+ { 3, "0 E", (int64_t)1536*1024*1024*1024*1024L, 0, 6 },
+ { 3, "2 E", (int64_t)1536*1024*1024*1024*1024*1024L, 0, 6 },
+
+ /* tests 86-99 test invalid specific scale values of < 0 or >= 7 with
+ and without HN_DIVISOR_1000 set */
+ /* all should return errors with new code; with old, the latter 3
+ are instead processed as if having AUTOSCALE and/or GETSCALE set */
+ { -1, "", (int64_t)1L, 0, 7 },
+ { -1, "", (int64_t)1L, HN_DIVISOR_1000, 7 },
+ { -1, "", (int64_t)1L, 0, 1000 },
+ { -1, "", (int64_t)1L, HN_DIVISOR_1000, 1000 },
+ { -1, "", (int64_t)0L, 0, 1000*1000 },
+ { -1, "", (int64_t)0L, HN_DIVISOR_1000, 1000*1000 },
+ { -1, "", (int64_t)0L, 0, INT_MAX },
+ { -1, "", (int64_t)0L, HN_DIVISOR_1000, INT_MAX },
+
+ /* Negative scale values are not handled well
+ by the existing library routine - should report as error */
+ /* all should return errors with new code, fail assertion with old */
+
+ { -1, "", (int64_t)1L, 0, -1 },
+ { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1 },
+ { -1, "", (int64_t)1L, 0, -1000 },
+ { -1, "", (int64_t)1L, HN_DIVISOR_1000, -1000 },
+
+ /* __INT_MIN doesn't print properly, skipped. */
+
+ { -1, "", (int64_t)1L, 0, -__INT_MAX },
+ { -1, "", (int64_t)1L, HN_DIVISOR_1000, -__INT_MAX },
+
+
+ /* tests for scale == 0, without autoscale */
+ /* tests 100-114 test scale 0 with 1000 divisor - print first N digits */
+ { 2, "0 ", (int64_t)0L, HN_DIVISOR_1000, 0 },
+ { 2, "1 ", (int64_t)1L, HN_DIVISOR_1000, 0 },
+ { 3, "10 ", (int64_t)10L, HN_DIVISOR_1000, 0 },
+ { 3, "0 M", (int64_t)150L, HN_DIVISOR_1000, HN_NOSPACE },
+ { 3, "0 M", (int64_t)500L, HN_DIVISOR_1000, HN_NOSPACE },
+ { 3, "0 M", (int64_t)999L, HN_DIVISOR_1000, HN_NOSPACE },
+ { 4, "150", (int64_t)150L, HN_DIVISOR_1000, 0 },
+ { 4, "500", (int64_t)500L, HN_DIVISOR_1000, 0 },
+ { 4, "999", (int64_t)999L, HN_DIVISOR_1000, 0 },
+ { 5, "100", (int64_t)1000L, HN_DIVISOR_1000, 0 },
+ { 5, "150", (int64_t)1500L, HN_DIVISOR_1000, 0 },
+ { 7, "500", (int64_t)500*1000L, HN_DIVISOR_1000, 0 },
+ { 8, "150", (int64_t)1500*1000L, HN_DIVISOR_1000, 0 },
+ { 10, "500", (int64_t)500*1000*1000L, HN_DIVISOR_1000, 0 },
+ { 11, "150", (int64_t)1500*1000*1000L, HN_DIVISOR_1000, 0 },
+
+ /* tests 115-126 test scale 0 with 1024 divisor - print first N digits */
+ { 2, "0 ", (int64_t)0L, 0, 0 },
+ { 2, "1 ", (int64_t)1L, 0, 0 },
+ { 3, "10 ", (int64_t)10L, 0, 0 },
+ { 4, "150", (int64_t)150L, 0, 0 },
+ { 4, "500", (int64_t)500L, 0, 0 },
+ { 4, "999", (int64_t)999L, 0, 0 },
+ { 5, "100", (int64_t)1000L, 0, 0 },
+ { 5, "150", (int64_t)1500L, 0, 0 },
+ { 7, "500", (int64_t)500*1000L, 0, 0 },
+ { 8, "150", (int64_t)1500*1000L, 0, 0 },
+ { 10, "500", (int64_t)500*1000*1000L, 0, 0 },
+ { 11, "150", (int64_t)1500*1000*1000L, 0, 0 },
+
+ /* Test boundary cases for very large positive/negative number formatting */
+ /* Explicit scale, divisor 1024 */
+
+ /* XXX = requires length 5 (buflen 6) for some cases*/
+ /* KLUDGE - test loop below will bump length 5 up to 5 */
+ { 3, "8 E", INT64_MAX, 0, 6 },
+ { 4, "-8 E", -INT64_MAX, 0, 6 },
+ { 3, "0 E", (int64_t)92*1024*1024*1024*1024*1024L, 0, 6 },
+ { 3, "0 E", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 6 },
+ { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, 0, 6 },
+ { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 6 },
+ { 3, "0 E", (int64_t)81*1024*1024*1024*1024*1024L, 0, 6 },
+ { 3, "0 E", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 6 },
+ { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, 5 },
+ { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 5 },
+ { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, 5 },
+ { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 5 },
+ { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, 5 },
+ { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 5 },
+
+ /* Explicit scale, divisor 1000 */
+ { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, 6 },
+ { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, 6 },
+ { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 },
+ { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 },
+ { 3, "0 E", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 },
+ { 3, "0 E", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 6 },
+ { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 },
+ { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 },
+ { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 },
+ { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 5 },
+
+ /* Autoscale, divisor 1024 */
+ { 3, "8 E", INT64_MAX, 0, HN_AUTOSCALE },
+ { 4, "-8 E", -INT64_MAX, 0, HN_AUTOSCALE },
+ { 4, "92 P", (int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 5, "-92 P", -(int64_t)92*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 4, "82 P", (int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 5, "-82 P", -(int64_t)82*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 4, "81 P", (int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ { 5, "-81 P", -(int64_t)81*1024*1024*1024*1024*1024L, 0, HN_AUTOSCALE },
+ /* Autoscale, divisor 1000 */
+ { 3, "9 E", INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 4, "-9 E", -INT64_MAX, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 4, "92 P", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "-92 P", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 4, "91 P", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "-91 P", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, HN_AUTOSCALE },
+
+ /* 0 scale, divisor 1024 */
+ { 12, "skdj", INT64_MAX, 0, 0 },
+ { 21, "-9223", -INT64_MAX, 0, 0 },
+ { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, 0, 0 },
+ { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, 0, 0 },
+ { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, 0, 0 },
+ { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, 0, 0 },
+ { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, 0, 0 },
+ { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, 0, 0 },
+
+ /* 0 scale, divisor 1000 */
+ /* XXX - why does this fail? */
+ { -1, "", INT64_MAX, HN_DIVISOR_1000, 0 },
+ { 21, "-9223", -INT64_MAX, HN_DIVISOR_1000, 0 },
+ { 19, "10358", (int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 },
+ { 20, "-1035", -(int64_t)92*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 },
+ { 18, "92323", (int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 },
+ { 19, "-9232", -(int64_t)82*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 },
+ /* Expected to pass */
+ { 18, "91197", (int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 },
+ { 19, "-9119", -(int64_t)81*1024*1024*1024*1024*1024L, HN_DIVISOR_1000, 0 },
+
+
+
+ /* Need to implement tests for GETSCALE */
+/* { ?, "", (int64_t)0L, HN_DIVISOR_1000, HN_GETSCALE },
+ ...
+*/
+ /* Tests for HN_DECIMAL */
+ /* Positive, Autoscale */
+ { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "994 k", (int64_t)994*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "995 k", (int64_t)995*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "1.0 M", (int64_t)1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "994 M", (int64_t)994*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "995 M", (int64_t)995*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+
+ { 5, "500 K", (int64_t)500*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "994 K", (int64_t)994*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "995 K", (int64_t)995*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "999 K", (int64_t)999*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "1.0 M", (int64_t)1000*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "1.0 M", (int64_t)1018*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "1.0 M", (int64_t)1019*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "1.5 M", (int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "1.9 M", (int64_t)1996*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "2.0 M", (int64_t)1997*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "2.0 M", (int64_t)2047*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "2.0 M", (int64_t)2048*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "2.0 M", (int64_t)2099*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "2.1 M", (int64_t)2100*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "9.9 M", (int64_t)10188*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ /* XXX - shouldn't the following two be "10. M"? */
+ { 4, "10 M", (int64_t)10189*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 4, "10 M", (int64_t)10240*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "500 M", (int64_t)500*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "994 M", (int64_t)994*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "995 M", (int64_t)995*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "999 M", (int64_t)999*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "1.0 G", (int64_t)1000*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "1.0 G", (int64_t)1023*1024*1024L, HN_DECIMAL, HN_AUTOSCALE },
+
+ /* Negative, Autoscale - should pass */
+ { 6, "-1.5 ", -(int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 6, "-1.9 ", -(int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 6, "-9.9 ", -(int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+
+ { 6, "-1.5 ", -(int64_t)1536*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 6, "-1.9 ", -(int64_t)1949*1024L, HN_DECIMAL, HN_AUTOSCALE },
+ { 6, "-9.7 ", -(int64_t)9949*1024L, HN_DECIMAL, HN_AUTOSCALE },
+
+ /* Positive/negative, at maximum scale */
+ { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ /* Negatives work with latest rev only: */
+ { 6, "-9.2 ", -INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+ { 6, "-8.9 ", -(int64_t)8949*1000*1000*1000*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, HN_AUTOSCALE },
+
+ { 5, "8.0 E", INT64_MAX, HN_DECIMAL, HN_AUTOSCALE },
+ { 5, "7.9 E", INT64_MAX-(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE },
+ { 6, "-8.0 ", -INT64_MAX, HN_DECIMAL, HN_AUTOSCALE },
+ { 6, "-7.9 ", -INT64_MAX+(int64_t)100*1024*1024*1024*1024*1024LL, HN_DECIMAL, HN_AUTOSCALE },
+
+ /* Positive, Fixed scales */
+ { 5, "500 k", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+ { 5, "0.5 M", (int64_t)500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "949 k", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+ { 5, "0.9 M", (int64_t)949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "950 k", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+ { 5, "1.0 M", (int64_t)950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "999 k", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 1 },
+ { 5, "1.0 M", (int64_t)999*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "1.5 M", (int64_t)1500*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "1.9 M", (int64_t)1949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "2.0 M", (int64_t)1950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "9.9 M", (int64_t)9949*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 4, "10 M", (int64_t)9950*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "500 M", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "0.5 G", (int64_t)500*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 },
+ { 5, "999 M", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 2 },
+ { 5, "1.0 G", (int64_t)999*1000*1000L, HN_DECIMAL|HN_DIVISOR_1000, 3 },
+ /* Positive/negative, at maximum scale */
+ { 5, "500 P", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 5 },
+ { 5, "1.0 E", (int64_t)500*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+ { 5, "1.9 E", (int64_t)1949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+ { 5, "8.9 E", (int64_t)8949*1000*1000*1000*1000*1000L, HN_DIVISOR_1000, 6 },
+ { 5, "9.2 E", INT64_MAX, HN_DECIMAL|HN_DIVISOR_1000, 6 },
+
+ /* HN_DECIMAL + binary + fixed scale cases not completed */
+ { 5, "512 K", (int64_t)512*1024L, HN_DECIMAL, 1 },
+ { 5, "0.5 M", (int64_t)512*1024L, HN_DECIMAL, 2 },
+
+ /* Negative, Fixed scales */
+ /* Not yet added, but should work with latest rev */
+
+};
+
+
+/* Command line options usage */
+static void
+usage(char * progname) {
+ printf("%s: tests libutil humanize_number function\n", progname);
+ printf("Usage: %s [-nE] [-l num] [-v]\n\n", progname);
+ printf("Options:\n");
+ printf("\t-l num\tSet max length for result; buflen = num + 1\n");
+ printf("\t\t (NOTE: does not change expected result strings.)\n");
+ printf("\t-n\tInclude negative scale tests, which cause older libutil\n");
+ printf("\t\t version of function to coredump with assertion failure\n");
+ printf("\t-E\tInclude numbers > 1/2 Exa[byte] which currently fail\n");
+ printf("\t-v\tVerbose - always print summary results\n");
+ printf("\t-h, -?\tShow options\n");
+}
+
+/* Parse command line options */
+static void
+read_options(int argc, char * const argv[], size_t *bufLength,
+ int *includeNegativeScale, int *includeExabytes, int *verbose) {
+ int ch;
+ size_t temp;
+
+ while ((ch = getopt(argc, argv, "nEh?vl:")) != -1) {
+ switch (ch) {
+ default:
+ usage(argv[0]);
+ exit(1);
+ break; /* UNREACHABLE */
+ case 'h' :
+ case '?' :
+ usage(argv[0]);
+ exit(0);
+ break; /* UNREACHABLE */
+ case 'l' :
+ sscanf(optarg, "%zu", &temp);
+ *bufLength = temp + 1;
+ break;
+ case 'n' :
+ *includeNegativeScale = 1;
+ break;
+ case 'E' :
+ *includeExabytes = 1;
+ break;
+ case 'v' :
+ *verbose = 1;
+ break;
+ }
+ }
+}
+
+static struct {
+ int value;
+ const char *name;
+ } flags[] = {
+ { HN_AUTOSCALE, "HN_AUTOSCALE" },
+ { HN_GETSCALE, "HN_GETSCALE" },
+ { HN_DIVISOR_1000, "HN_DIVISOR_1000"},
+ { HN_B, "HN_B"},
+ { HN_DECIMAL, "HN_DECIMAL"},
+};
+
+static const char *separator = "|";
+
+/* Format flags parameter for meaningful display */
+static char *
+str_flags(int hn_flags, char *noFlags) {
+ size_t i;
+ char * result;
+
+ result = malloc(MAX_STR_FLAGS_RESULT);
+ result[0] = '\0';
+
+ for (i = 0; i < sizeof flags / sizeof *flags; i++) {
+ if (hn_flags & flags[i].value) {
+ if (*result != 0)
+ strlcat(result, separator,
+ MAX_STR_FLAGS_RESULT);
+ strlcat(result, flags[i].name, MAX_STR_FLAGS_RESULT);
+ }
+ }
+
+ if (strlen(result) == 0)
+ strlcat(result, noFlags, MAX_STR_FLAGS_RESULT);
+ return result;
+}
+
+
+/* Format scale parameter for meaningful display */
+static char *
+str_scale(int scale) {
+ char *result;
+
+ if (scale == HN_AUTOSCALE || scale == HN_GETSCALE)
+ return str_flags(scale, "");
+
+ result = malloc(MAX_INT_STR_DIGITS);
+ result[0] = '\0';
+ snprintf(result, MAX_INT_STR_DIGITS, "%d", scale);
+ return result;
+}
+
+static void
+testskipped(size_t i)
+{
+
+ printf("ok %zu # skip - not turned on\n", i);
+}
+
+int
+main(int argc, char * const argv[])
+{
+ char *buf;
+ char *flag_str, *scale_str;
+ size_t buflen, errcnt, i, skipped, tested;
+ int r;
+ int includeNegScale;
+ int includeExabyteTests;
+ int verbose;
+
+ buflen = 4;
+ includeNegScale = 0;
+ includeExabyteTests = 0;
+ verbose = 0;
+
+ read_options(argc, argv, &buflen, &includeNegScale,
+ &includeExabyteTests, &verbose);
+
+ buf = malloc(buflen);
+ errcnt = 0;
+ tested = 0;
+ skipped = 0;
+
+ if (buflen != 4)
+ printf("Warning: buffer size %zu != 4, expect some results to differ.\n", buflen);
+
+ printf("1..%zu\n", nitems(test_args));
+ for (i = 0; i < nitems(test_args); i++) {
+ /* KLUDGE */
+ if (test_args[i].num == INT64_MAX && buflen == 4) {
+ /* Start final tests which require buffer of 6 */
+ free(buf);
+ buflen = 6;
+ buf = malloc(buflen);
+ if (verbose)
+ printf("Buffer length increased to %zu\n",
+ buflen);
+ }
+
+ if (test_args[i].scale < 0 && ! includeNegScale) {
+ skipped++;
+ testskipped(i + 1);
+ continue;
+ }
+ if (test_args[i].num >= halfExabyte && ! includeExabyteTests) {
+ skipped++;
+ testskipped(i + 1);
+ continue;
+ }
+
+ r = humanize_number(buf, buflen, test_args[i].num, "",
+ test_args[i].scale, test_args[i].flags);
+ flag_str = str_flags(test_args[i].flags, "[no flags]");
+ scale_str = str_scale(test_args[i].scale);
+
+ if (r != test_args[i].retval) {
+ if (verbose)
+ printf("wrong return value on index %zu, "
+ "buflen: %zu, got: %d + \"%s\", "
+ "expected %d + \"%s\"; num = %jd, "
+ "scale = %s, flags= %s.\n",
+ i, buflen, r, buf, test_args[i].retval,
+ test_args[i].res,
+ (intmax_t)test_args[i].num,
+ scale_str, flag_str);
+ else
+ printf("not ok %zu # return %d != %d\n",
+ i + 1, r, test_args[i].retval);
+ errcnt++;
+ } else if (strcmp(buf, test_args[i].res) != 0) {
+ if (verbose)
+ printf("result mismatch on index %zu, got: "
+ "\"%s\", expected \"%s\"; num = %jd, "
+ "scale = %s, flags= %s.\n",
+ i, buf, test_args[i].res,
+ (intmax_t)test_args[i].num,
+ scale_str, flag_str);
+ else
+ printf("not ok %zu # buf \"%s\" != \"%s\"\n",
+ i + 1, buf, test_args[i].res);
+ errcnt++;
+ } else {
+ if (verbose)
+ printf("successful result on index %zu, "
+ "returned %d, got: \"%s\"; num = %jd, "
+ "scale = %s, flags= %s.\n",
+ i, r, buf,
+ (intmax_t)test_args[i].num,
+ scale_str, flag_str);
+ else
+ printf("ok %zu\n", i + 1);
+ }
+ tested++;
+ }
+
+ if (verbose)
+ printf("total errors: %zu/%zu tests, %zu skipped\n", errcnt,
+ tested, skipped);
+
+ if (errcnt)
+ return 1;
+
+ return 0;
+}
diff --git a/lib/libutil/tests/pidfile_test.c b/lib/libutil/tests/pidfile_test.c
new file mode 100644
index 0000000..0b70bc8
--- /dev/null
+++ b/lib/libutil/tests/pidfile_test.c
@@ -0,0 +1,280 @@
+/*-
+ * Copyright (c) 2007-2009 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/param.h>
+#include <sys/wait.h>
+
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libutil.h>
+
+/*
+ * We need a signal handler so kill(2) will interrupt our child's
+ * select(2) instead of killing it.
+ */
+static void
+signal_handler(int sig)
+{
+ (void)sig;
+}
+
+/*
+ * Test that pidfile_open() can create a pidfile and that pidfile_write()
+ * can write to it.
+ */
+static const char *
+test_pidfile_uncontested(void)
+{
+ const char *fn = "test_pidfile_uncontested";
+ struct pidfh *pf;
+ pid_t other = 0;
+
+ unlink(fn);
+ pf = pidfile_open(fn, 0600, &other);
+ if (pf == NULL && other != 0)
+ return ("pidfile exists and is locked");
+ if (pf == NULL)
+ return (strerror(errno));
+ if (pidfile_write(pf) != 0) {
+ pidfile_close(pf);
+ unlink(fn);
+ return ("failed to write PID");
+ }
+ pidfile_close(pf);
+ unlink(fn);
+ return (NULL);
+}
+
+/*
+ * Test that pidfile_open() locks against self.
+ */
+static const char *
+test_pidfile_self(void)
+{
+ const char *fn = "test_pidfile_self";
+ struct pidfh *pf1, *pf2;
+ pid_t other = 0;
+ int serrno;
+
+ unlink(fn);
+ pf1 = pidfile_open(fn, 0600, &other);
+ if (pf1 == NULL && other != 0)
+ return ("pidfile exists and is locked");
+ if (pf1 == NULL)
+ return (strerror(errno));
+ if (pidfile_write(pf1) != 0) {
+ serrno = errno;
+ pidfile_close(pf1);
+ unlink(fn);
+ return (strerror(serrno));
+ }
+ // second open should fail
+ pf2 = pidfile_open(fn, 0600, &other);
+ if (pf2 != NULL) {
+ pidfile_close(pf1);
+ pidfile_close(pf2);
+ unlink(fn);
+ return ("managed to opened pidfile twice");
+ }
+ if (other != getpid()) {
+ pidfile_close(pf1);
+ unlink(fn);
+ return ("pidfile contained wrong PID");
+ }
+ pidfile_close(pf1);
+ unlink(fn);
+ return (NULL);
+}
+
+/*
+ * Common code for test_pidfile_{contested,inherited}.
+ */
+static const char *
+common_test_pidfile_child(const char *fn, int parent_open)
+{
+ struct pidfh *pf = NULL;
+ pid_t other = 0, pid = 0;
+ int fd[2], serrno, status;
+ char ch;
+
+ unlink(fn);
+ if (pipe(fd) != 0)
+ return (strerror(errno));
+
+ if (parent_open) {
+ pf = pidfile_open(fn, 0600, &other);
+ if (pf == NULL && other != 0)
+ return ("pidfile exists and is locked");
+ if (pf == NULL)
+ return (strerror(errno));
+ }
+
+ pid = fork();
+ if (pid == -1)
+ return (strerror(errno));
+ if (pid == 0) {
+ // child
+ close(fd[0]);
+ signal(SIGINT, signal_handler);
+ if (!parent_open) {
+ pf = pidfile_open(fn, 0600, &other);
+ if (pf == NULL && other != 0)
+ return ("pidfile exists and is locked");
+ if (pf == NULL)
+ return (strerror(errno));
+ }
+ if (pidfile_write(pf) != 0) {
+ serrno = errno;
+ pidfile_close(pf);
+ unlink(fn);
+ return (strerror(serrno));
+ }
+ if (pf == NULL)
+ _exit(1);
+ if (pidfile_write(pf) != 0)
+ _exit(1);
+ if (write(fd[1], "*", 1) != 1)
+ _exit(1);
+ select(0, 0, 0, 0, 0);
+ _exit(0);
+ }
+ // parent
+ close(fd[1]);
+ if (pf)
+ pidfile_close(pf);
+
+ // wait for the child to signal us
+ if (read(fd[0], &ch, 1) != 1) {
+ serrno = errno;
+ unlink(fn);
+ kill(pid, SIGTERM);
+ errno = serrno;
+ return (strerror(errno));
+ }
+
+ // We shouldn't be able to lock the same pidfile as our child
+ pf = pidfile_open(fn, 0600, &other);
+ if (pf != NULL) {
+ pidfile_close(pf);
+ unlink(fn);
+ return ("managed to lock contested pidfile");
+ }
+
+ // Failed to lock, but not because it was contested
+ if (other == 0) {
+ unlink(fn);
+ return (strerror(errno));
+ }
+
+ // Locked by the wrong process
+ if (other != pid) {
+ unlink(fn);
+ return ("pidfile contained wrong PID");
+ }
+
+ // check our child's fate
+ if (pf)
+ pidfile_close(pf);
+ unlink(fn);
+ if (kill(pid, SIGINT) != 0)
+ return (strerror(errno));
+ if (waitpid(pid, &status, 0) == -1)
+ return (strerror(errno));
+ if (WIFSIGNALED(status))
+ return ("child caught signal");
+ if (WEXITSTATUS(status) != 0)
+ return ("child returned non-zero status");
+
+ // success
+ return (NULL);
+}
+
+/*
+ * Test that pidfile_open() fails when attempting to open a pidfile that
+ * is already locked, and that it returns the correct PID.
+ */
+static const char *
+test_pidfile_contested(void)
+{
+ const char *fn = "test_pidfile_contested";
+ const char *result;
+
+ result = common_test_pidfile_child(fn, 0);
+ return (result);
+}
+
+/*
+ * Test that the pidfile lock is inherited.
+ */
+static const char *
+test_pidfile_inherited(void)
+{
+ const char *fn = "test_pidfile_inherited";
+ const char *result;
+
+ result = common_test_pidfile_child(fn, 1);
+ return (result);
+}
+
+static struct test {
+ const char *name;
+ const char *(*func)(void);
+} t[] = {
+ { "pidfile_uncontested", test_pidfile_uncontested },
+ { "pidfile_self", test_pidfile_self },
+ { "pidfile_contested", test_pidfile_contested },
+ { "pidfile_inherited", test_pidfile_inherited },
+};
+
+int
+main(void)
+{
+ const char *result;
+ int i, nt;
+
+ nt = sizeof(t) / sizeof(*t);
+ printf("1..%d\n", nt);
+ for (i = 0; i < nt; ++i) {
+ if ((result = t[i].func()) != NULL)
+ printf("not ok %d - %s # %s\n", i + 1,
+ t[i].name, result);
+ else
+ printf("ok %d - %s\n", i + 1,
+ t[i].name);
+ }
+ exit(0);
+}
diff --git a/lib/libutil/tests/trimdomain-nodomain_test.c b/lib/libutil/tests/trimdomain-nodomain_test.c
new file mode 100644
index 0000000..c02ccdb
--- /dev/null
+++ b/lib/libutil/tests/trimdomain-nodomain_test.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005 Brooks Davis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define TESTDOMAIN ""
+#define TESTHOST "testhost"
+#define TESTFQDN "testhost" TESTDOMAIN
+
+int failures = 0;
+int tests = 0;
+
+/*
+ * Evily override gethostname(3) so trimdomain always gets the same result.
+ * This makes the tests much easier to write and less likely to fail on
+ * oddly configured systems.
+ */
+int
+gethostname(char *name, size_t namelen)
+{
+ if (strlcpy(name, TESTFQDN, namelen) > namelen) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ return (0);
+}
+
+void
+testit(const char *input, int hostsize, const char *output, const char *test)
+{
+ char *testhost;
+ const char *expected = (output == NULL) ? input : output;
+
+ testhost = strdup(input);
+ trimdomain(testhost, hostsize < 0 ? (int)strlen(testhost) : hostsize);
+ tests++;
+ if (strcmp(testhost, expected) != 0) {
+ printf("not ok %d - %s\n", tests, test);
+ printf("# %s -> %s (expected %s)\n", input, testhost, expected);
+ } else
+ printf("ok %d - %s\n", tests, test);
+ free(testhost);
+ return;
+}
+
+int
+main(void)
+{
+
+ printf("1..5\n");
+
+ testit(TESTFQDN, -1, TESTHOST, "self");
+ testit("XXX" TESTDOMAIN, -1, "XXX", "different host, same domain");
+ testit("XXX" TESTDOMAIN, 1, NULL, "short hostsize");
+ testit("bogus.example.net", -1, NULL, "arbitrary host");
+ testit("XXX." TESTFQDN, -1, NULL, "domain is local hostname");
+
+ return (0);
+}
diff --git a/lib/libutil/tests/trimdomain_test.c b/lib/libutil/tests/trimdomain_test.c
new file mode 100644
index 0000000..08fcfc0
--- /dev/null
+++ b/lib/libutil/tests/trimdomain_test.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2005 Brooks Davis. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <libutil.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define TESTDOMAIN ".domain.example.com"
+#define TESTHOST "testhost"
+#define TESTFQDN "testhost" TESTDOMAIN
+
+int failures = 0;
+int tests = 0;
+
+/*
+ * Evily override gethostname(3) so trimdomain always gets the same result.
+ * This makes the tests much easier to write and less likely to fail on
+ * oddly configured systems.
+ */
+int
+gethostname(char *name, size_t namelen)
+{
+ if (strlcpy(name, TESTFQDN, namelen) > namelen) {
+ errno = ENAMETOOLONG;
+ return (-1);
+ }
+ return (0);
+}
+
+void
+testit(const char *input, int hostsize, const char *output, const char *test)
+{
+ char *testhost;
+ const char *expected = (output == NULL) ? input : output;
+
+ testhost = strdup(input);
+ trimdomain(testhost, hostsize < 0 ? (int)strlen(testhost) : hostsize);
+ tests++;
+ if (strcmp(testhost, expected) != 0) {
+ printf("not ok %d - %s\n", tests, test);
+ printf("# %s -> %s (expected %s)\n", input, testhost, expected);
+ } else
+ printf("ok %d - %s\n", tests, test);
+ free(testhost);
+ return;
+}
+
+int
+main(void)
+{
+
+ printf("1..5\n");
+
+ testit(TESTFQDN, -1, TESTHOST, "self");
+ testit("XXX" TESTDOMAIN, -1, "XXX", "different host, same domain");
+ testit("XXX" TESTDOMAIN, 1, NULL, "short hostsize");
+ testit("bogus.example.net", -1, NULL, "arbitrary host");
+ testit("XXX." TESTFQDN, -1, NULL, "domain is local hostname");
+
+ return (0);
+}
diff --git a/lib/libxo/Makefile b/lib/libxo/Makefile
new file mode 100644
index 0000000..644b71f
--- /dev/null
+++ b/lib/libxo/Makefile
@@ -0,0 +1,36 @@
+# $FreeBSD$
+
+LIBXO= ${.CURDIR:H:H}/contrib/libxo
+
+.PATH: ${LIBXO}/libxo
+
+LIB= xo
+SHLIB_MAJOR=0
+
+SRCS= libxo.c
+
+CFLAGS+=-I${LIBXO}/libxo
+
+INCS= xo.h
+INCSDIR=${INCLUDEDIR}/libxo
+
+MAN+= libxo.3
+MAN+= xo_attr.3 \
+ xo_create.3 \
+ xo_emit.3 \
+ xo_err.3 \
+ xo_finish.3 \
+ xo_flush.3 \
+ xo_no_setlocale.3 \
+ xo_open_container.3 \
+ xo_open_list.3 \
+ xo_parse_args.3 \
+ xo_set_allocator.3 \
+ xo_set_flags.3 \
+ xo_set_info.3 \
+ xo_set_options.3 \
+ xo_set_style.3 \
+ xo_set_writer.3
+MAN+= xo_format.5
+
+.include <bsd.lib.mk>
diff --git a/lib/libz/Makefile b/lib/libz/Makefile
index 1b2fec5..1f9bb72 100644
--- a/lib/libz/Makefile
+++ b/lib/libz/Makefile
@@ -68,9 +68,11 @@ test: example minigzip
(export LD_LIBRARY_PATH=. ; \
echo hello world | ./minigzip | ./minigzip -d )
+.ifndef COMPAT_32BIT
beforeinstall:
${INSTALL} -C -o ${LIBOWN} -g ${LIBGRP} -m ${LIBMODE} \
${.CURDIR}/zlib.pc ${DESTDIR}${LIBDATADIR}/pkgconfig
+.endif
.include <bsd.lib.mk>
diff --git a/lib/msun/Makefile b/lib/msun/Makefile
index e8458d4..afb7067 100644
--- a/lib/msun/Makefile
+++ b/lib/msun/Makefile
@@ -100,6 +100,7 @@ COMMON_SRCS+= s_copysignl.c s_fabsl.c s_llrintl.c s_lrintl.c s_modfl.c
# If long double != double use these; otherwise, we alias the double versions.
COMMON_SRCS+= e_acoshl.c e_acosl.c e_asinl.c e_atan2l.c e_atanhl.c \
e_coshl.c e_fmodl.c e_hypotl.c \
+ e_lgammal.c e_lgammal_r.c \
e_remainderl.c e_sinhl.c e_sqrtl.c \
invtrig.c k_cosl.c k_sinl.c k_tanl.c \
s_asinhl.c s_atanl.c s_cbrtl.c s_ceill.c s_cosl.c s_cprojl.c \
@@ -190,7 +191,8 @@ MLINKS+=ilogb.3 ilogbf.3 ilogb.3 ilogbl.3 \
ilogb.3 logb.3 ilogb.3 logbf.3 ilogb.3 logbl.3
MLINKS+=j0.3 j1.3 j0.3 jn.3 j0.3 y0.3 j0.3 y1.3 j0.3 y1f.3 j0.3 yn.3
MLINKS+=j0.3 j0f.3 j0.3 j1f.3 j0.3 jnf.3 j0.3 y0f.3 j0.3 ynf.3
-MLINKS+=lgamma.3 gamma.3 lgamma.3 gammaf.3 lgamma.3 lgammaf.3 \
+MLINKS+=lgamma.3 gamma.3 lgamma.3 gammaf.3 \
+ lgamma.3 lgammaf.3 lgamma.3 lgammal.3 \
lgamma.3 tgamma.3 lgamma.3 tgammaf.3
MLINKS+=log.3 log10.3 log.3 log10f.3 log.3 log10l.3 \
log.3 log1p.3 log.3 log1pf.3 log.3 log1pl.3 \
@@ -219,4 +221,8 @@ MLINKS+=tan.3 tanf.3 tan.3 tanl.3
MLINKS+=tanh.3 tanhf.3 tanh.3 tanhl.3
MLINKS+=trunc.3 truncf.3 trunc.3 truncl.3
+.include <src.opts.mk>
+
+.include <bsd.arch.inc.mk>
+
.include <bsd.lib.mk>
diff --git a/lib/msun/Makefile.amd64 b/lib/msun/Makefile.amd64
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/msun/Makefile.amd64
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/msun/Makefile.i386 b/lib/msun/Makefile.i386
new file mode 100644
index 0000000..dd0f5b0
--- /dev/null
+++ b/lib/msun/Makefile.i386
@@ -0,0 +1,6 @@
+# $FreeBSD$
+
+.if ${MK_TESTS} != "no"
+SUBDIR+= tests
+.endif
+
diff --git a/lib/msun/Symbol.map b/lib/msun/Symbol.map
index e53ca07..d5b7f46 100644
--- a/lib/msun/Symbol.map
+++ b/lib/msun/Symbol.map
@@ -269,6 +269,7 @@ FBSD_1.3 {
erfl;
expl;
expm1l;
+ lgammal;
log10l;
log1pl;
log2l;
@@ -276,7 +277,11 @@ FBSD_1.3 {
sinhl;
tanhl;
/* Implemented as weak aliases for imprecise versions */
- lgammal;
powl;
tgammal;
};
+
+/* First added in 11.0-CURRENT */
+FBSD_1.4 {
+ lgammal_r;
+};
diff --git a/lib/msun/arm/fenv.c b/lib/msun/arm/fenv.c
index 2dd1933..16f1f48 100644
--- a/lib/msun/arm/fenv.c
+++ b/lib/msun/arm/fenv.c
@@ -30,7 +30,9 @@
#define __fenv_static
#include "fenv.h"
-#if defined(__FreeBSD_ARCH_armv6__) || (defined(__ARM_ARCH) && __ARM_ARCH >= 6)
+#include <machine/acle-compat.h>
+
+#if __ARM_ARCH >= 6
#define FENV_ARMv6
#endif
diff --git a/lib/msun/ld128/e_lgammal_r.c b/lib/msun/ld128/e_lgammal_r.c
new file mode 100644
index 0000000..53d3af1
--- /dev/null
+++ b/lib/msun/ld128/e_lgammal_r.c
@@ -0,0 +1,330 @@
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * See e_lgamma_r.c for complete comments.
+ *
+ * Converted to long double by Steven G. Kargl.
+ */
+
+#include "fpmath.h"
+#include "math.h"
+#include "math_private.h"
+
+static const volatile double vzero = 0;
+
+static const double
+zero= 0,
+half= 0.5,
+one = 1;
+
+static const long double
+pi = 3.14159265358979323846264338327950288e+00L;
+/*
+ * Domain y in [0x1p-119, 0.28], range ~[-1.4065e-36, 1.4065e-36]:
+ * |(lgamma(2 - y) + y / 2) / y - a(y)| < 2**-119.1
+ */
+static const long double
+a0 = 7.72156649015328606065120900824024296e-02L,
+a1 = 3.22467033424113218236207583323018498e-01L,
+a2 = 6.73523010531980951332460538330282217e-02L,
+a3 = 2.05808084277845478790009252803463129e-02L,
+a4 = 7.38555102867398526627292839296001626e-03L,
+a5 = 2.89051033074152328576829509522483468e-03L,
+a6 = 1.19275391170326097618357349881842913e-03L,
+a7 = 5.09669524743042462515256340206203019e-04L,
+a8 = 2.23154758453578096143609255559576017e-04L,
+a9 = 9.94575127818397632126978731542755129e-05L,
+a10 = 4.49262367375420471287545895027098145e-05L,
+a11 = 2.05072127845117995426519671481628849e-05L,
+a12 = 9.43948816959096748454087141447939513e-06L,
+a13 = 4.37486780697359330303852050718287419e-06L,
+a14 = 2.03920783892362558276037363847651809e-06L,
+a15 = 9.55191070057967287877923073200324649e-07L,
+a16 = 4.48993286185740853170657139487620560e-07L,
+a17 = 2.13107543597620911675316728179563522e-07L,
+a18 = 9.70745379855304499867546549551023473e-08L,
+a19 = 5.61889970390290257926487734695402075e-08L,
+a20 = 6.42739653024130071866684358960960951e-09L,
+a21 = 3.34491062143649291746195612991870119e-08L,
+a22 = -1.57068547394315223934653011440641472e-08L,
+a23 = 1.30812825422415841213733487745200632e-08L;
+/*
+ * Domain x in [tc-0.24, tc+0.28], range ~[-6.3201e-37, 6.3201e-37]:
+ * |(lgamma(x) - tf) - t(x - tc)| < 2**-120.3.
+ */
+static const long double
+tc = 1.46163214496836234126265954232572133e+00L,
+tf = -1.21486290535849608095514557177691584e-01L,
+tt = 1.57061739945077675484237837992951704e-36L,
+t0 = -1.99238329499314692728655623767019240e-36L,
+t1 = -6.08453430711711404116887457663281416e-35L,
+t2 = 4.83836122723810585213722380854828904e-01L,
+t3 = -1.47587722994530702030955093950668275e-01L,
+t4 = 6.46249402389127526561003464202671923e-02L,
+t5 = -3.27885410884813055008502586863748063e-02L,
+t6 = 1.79706751152103942928638276067164935e-02L,
+t7 = -1.03142230366363872751602029672767978e-02L,
+t8 = 6.10053602051788840313573150785080958e-03L,
+t9 = -3.68456960831637325470641021892968954e-03L,
+t10 = 2.25976482322181046611440855340968560e-03L,
+t11 = -1.40225144590445082933490395950664961e-03L,
+t12 = 8.78232634717681264035014878172485575e-04L,
+t13 = -5.54194952796682301220684760591403899e-04L,
+t14 = 3.51912956837848209220421213975000298e-04L,
+t15 = -2.24653443695947456542669289367055542e-04L,
+t16 = 1.44070395420840737695611929680511823e-04L,
+t17 = -9.27609865550394140067059487518862512e-05L,
+t18 = 5.99347334438437081412945428365433073e-05L,
+t19 = -3.88458388854572825603964274134801009e-05L,
+t20 = 2.52476631610328129217896436186551043e-05L,
+t21 = -1.64508584981658692556994212457518536e-05L,
+t22 = 1.07434583475987007495523340296173839e-05L,
+t23 = -7.03070407519397260929482550448878399e-06L,
+t24 = 4.60968590693753579648385629003100469e-06L,
+t25 = -3.02765473778832036018438676945512661e-06L,
+t26 = 1.99238771545503819972741288511303401e-06L,
+t27 = -1.31281299822614084861868817951788579e-06L,
+t28 = 8.60844432267399655055574642052370223e-07L,
+t29 = -5.64535486432397413273248363550536374e-07L,
+t30 = 3.99357783676275660934903139592727737e-07L,
+t31 = -2.95849029193433121795495215869311610e-07L,
+t32 = 1.37790144435073124976696250804940384e-07L;
+/*
+ * Domain y in [-0.1, 0.232], range ~[-1.4046e-37, 1.4181e-37]:
+ * |(lgamma(1 + y) + 0.5 * y) / y - u(y) / v(y)| < 2**-122.8
+ */
+static const long double
+u0 = -7.72156649015328606065120900824024311e-02L,
+u1 = 4.24082772271938167430983113242482656e-01L,
+u2 = 2.96194003481457101058321977413332171e+00L,
+u3 = 6.49503267711258043997790983071543710e+00L,
+u4 = 7.40090051288150177152835698948644483e+00L,
+u5 = 4.94698036296756044610805900340723464e+00L,
+u6 = 2.00194224610796294762469550684947768e+00L,
+u7 = 4.82073087750608895996915051568834949e-01L,
+u8 = 6.46694052280506568192333848437585427e-02L,
+u9 = 4.17685526755100259316625348933108810e-03L,
+u10 = 9.06361003550314327144119307810053410e-05L,
+v1 = 5.15937098592887275994320496999951947e+00L,
+v2 = 1.14068418766251486777604403304717558e+01L,
+v3 = 1.41164839437524744055723871839748489e+01L,
+v4 = 1.07170702656179582805791063277960532e+01L,
+v5 = 5.14448694179047879915042998453632434e+00L,
+v6 = 1.55210088094585540637493826431170289e+00L,
+v7 = 2.82975732849424562719893657416365673e-01L,
+v8 = 2.86424622754753198010525786005443539e-02L,
+v9 = 1.35364253570403771005922441442688978e-03L,
+v10 = 1.91514173702398375346658943749580666e-05L,
+v11 = -3.25364686890242327944584691466034268e-08L;
+/*
+ * Domain x in (2, 3], range ~[-1.3341e-36, 1.3536e-36]:
+ * |(lgamma(y+2) - 0.5 * y) / y - s(y)/r(y)| < 2**-120.1
+ * with y = x - 2.
+ */
+static const long double
+s0 = -7.72156649015328606065120900824024297e-02L,
+s1 = 1.23221687850916448903914170805852253e-01L,
+s2 = 5.43673188699937239808255378293820020e-01L,
+s3 = 6.31998137119005233383666791176301800e-01L,
+s4 = 3.75885340179479850993811501596213763e-01L,
+s5 = 1.31572908743275052623410195011261575e-01L,
+s6 = 2.82528453299138685507186287149699749e-02L,
+s7 = 3.70262021550340817867688714880797019e-03L,
+s8 = 2.83374000312371199625774129290973648e-04L,
+s9 = 1.15091830239148290758883505582343691e-05L,
+s10 = 2.04203474281493971326506384646692446e-07L,
+s11 = 9.79544198078992058548607407635645763e-10L,
+r1 = 2.58037466655605285937112832039537492e+00L,
+r2 = 2.86289413392776399262513849911531180e+00L,
+r3 = 1.78691044735267497452847829579514367e+00L,
+r4 = 6.89400381446725342846854215600008055e-01L,
+r5 = 1.70135865462567955867134197595365343e-01L,
+r6 = 2.68794816183964420375498986152766763e-02L,
+r7 = 2.64617234244861832870088893332006679e-03L,
+r8 = 1.52881761239180800640068128681725702e-04L,
+r9 = 4.63264813762296029824851351257638558e-06L,
+r10 = 5.89461519146957343083848967333671142e-08L,
+r11 = 1.79027678176582527798327441636552968e-10L;
+/*
+ * Domain z in [8, 0x1p70], range ~[-9.8214e-35, 9.8214e-35]:
+ * |lgamma(x) - (x - 0.5) * (log(x) - 1) - w(1/x)| < 2**-113.0
+ */
+static const long double
+w0 = 4.18938533204672741780329736405617738e-01L,
+w1 = 8.33333333333333333333333333332852026e-02L,
+w2 = -2.77777777777777777777777727810123528e-03L,
+w3 = 7.93650793650793650791708939493907380e-04L,
+w4 = -5.95238095238095234390450004444370959e-04L,
+w5 = 8.41750841750837633887817658848845695e-04L,
+w6 = -1.91752691752396849943172337347259743e-03L,
+w7 = 6.41025640880333069429106541459015557e-03L,
+w8 = -2.95506530801732133437990433080327074e-02L,
+w9 = 1.79644237328444101596766586979576927e-01L,
+w10 = -1.39240539108367641920172649259736394e+00L,
+w11 = 1.33987701479007233325288857758641761e+01L,
+w12 = -1.56363596431084279780966590116006255e+02L,
+w13 = 2.14830978044410267201172332952040777e+03L,
+w14 = -3.28636067474227378352761516589092334e+04L,
+w15 = 5.06201257747865138432663574251462485e+05L,
+w16 = -6.79720123352023636706247599728048344e+06L,
+w17 = 6.57556601705472106989497289465949255e+07L,
+w18 = -3.26229058141181783534257632389415580e+08L;
+
+static long double
+sin_pil(long double x)
+{
+ volatile long double vz;
+ long double y,z;
+ uint64_t lx, n;
+ uint16_t hx;
+
+ y = -x;
+
+ vz = y+0x1.p112;
+ z = vz-0x1.p112;
+ if (z == y)
+ return zero;
+
+ vz = y+0x1.p110;
+ EXTRACT_LDBL128_WORDS(hx,lx,n,vz);
+ z = vz-0x1.p110;
+ if (z > y) {
+ z -= 0.25;
+ n--;
+ }
+ n &= 7;
+ y = y - z + n * 0.25;
+
+ switch (n) {
+ case 0: y = __kernel_sinl(pi*y,zero,0); break;
+ case 1:
+ case 2: y = __kernel_cosl(pi*(0.5-y),zero); break;
+ case 3:
+ case 4: y = __kernel_sinl(pi*(one-y),zero,0); break;
+ case 5:
+ case 6: y = -__kernel_cosl(pi*(y-1.5),zero); break;
+ default: y = __kernel_sinl(pi*(y-2.0),zero,0); break;
+ }
+ return -y;
+}
+
+long double
+lgammal_r(long double x, int *signgamp)
+{
+ long double nadj,p,p1,p2,p3,q,r,t,w,y,z;
+ uint64_t llx,lx;
+ int i;
+ uint16_t hx,ix;
+
+ EXTRACT_LDBL128_WORDS(hx,lx,llx,x);
+
+ /* purge +-Inf and NaNs */
+ *signgamp = 1;
+ ix = hx&0x7fff;
+ if(ix==0x7fff) return x*x;
+
+ /* purge +-0 and tiny arguments */
+ *signgamp = 1-2*(hx>>15);
+ if(ix<0x3fff-116) { /* |x|<2**-(p+3), return -log(|x|) */
+ if((ix|lx|llx)==0)
+ return one/vzero;
+ return -logl(fabsl(x));
+ }
+
+ /* purge negative integers and start evaluation for other x < 0 */
+ if(hx&0x8000) {
+ *signgamp = 1;
+ if(ix>=0x3fff+112) /* |x|>=2**(p-1), must be -integer */
+ return one/vzero;
+ t = sin_pil(x);
+ if(t==zero) return one/vzero;
+ nadj = logl(pi/fabsl(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge 1 and 2 */
+ if((ix==0x3fff || ix==0x4000) && (lx|llx)==0) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x4000) {
+ if(x<=8.9999961853027344e-01) {
+ r = -logl(x);
+ if(x>=7.3159980773925781e-01) {y = 1-x; i= 0;}
+ else if(x>=2.3163998126983643e-01) {y= x-(tc-1); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = 0;
+ if(x>=1.7316312789916992e+00) {y=2-x;i=0;}
+ else if(x>=1.2316322326660156e+00) {y=x-tc;i=1;}
+ else {y=x-1;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*(a10+z*(a12+z*(a14+z*(a16+
+ z*(a18+z*(a20+z*a22))))))))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*(a11+z*(a13+z*(a15+
+ z*(a17+z*(a19+z*(a21+z*a23)))))))))));
+ p = y*p1+p2;
+ r += p-y/2; break;
+ case 1:
+ p = t0+y*t1+tt+y*y*(t2+y*(t3+y*(t4+y*(t5+y*(t6+y*(t7+y*(t8+
+ y*(t9+y*(t10+y*(t11+y*(t12+y*(t13+y*(t14+y*(t15+y*(t16+
+ y*(t17+y*(t18+y*(t19+y*(t20+y*(t21+y*(t22+y*(t23+
+ y*(t24+y*(t25+y*(t26+y*(t27+y*(t28+y*(t29+y*(t30+
+ y*(t31+y*t32))))))))))))))))))))))))))))));
+ r += tf + p; break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*(u5+y*(u6+y*(u7+
+ y*(u8+y*(u9+y*u10))))))))));
+ p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*(v5+y*(v6+y*(v7+
+ y*(v8+y*(v9+y*(v10+y*v11))))))))));
+ r += p1/p2-y/2;
+ }
+ }
+ /* x < 8.0 */
+ else if(ix<0x4002) {
+ i = x;
+ y = x-i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*(s6+y*(s7+y*(s8+
+ y*(s9+y*(s10+y*s11)))))))))));
+ q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*(r6+y*(r7+y*(r8+
+ y*(r9+y*(r10+y*r11))))))))));
+ r = y/2+p/q;
+ z = 1; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+6); /* FALLTHRU */
+ case 6: z *= (y+5); /* FALLTHRU */
+ case 5: z *= (y+4); /* FALLTHRU */
+ case 4: z *= (y+3); /* FALLTHRU */
+ case 3: z *= (y+2); /* FALLTHRU */
+ r += logl(z); break;
+ }
+ /* 8.0 <= x < 2**(p+3) */
+ } else if (ix<0x3fff+116) {
+ t = logl(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*(w6+y*(w7+y*(w8+
+ y*(w9+y*(w10+y*(w11+y*(w12+y*(w13+y*(w14+y*(w15+y*(w16+
+ y*(w17+y*w18)))))))))))))))));
+ r = (x-half)*(t-one)+w;
+ /* 2**(p+3) <= x <= inf */
+ } else
+ r = x*(logl(x)-1);
+ if(hx&0x8000) r = nadj - r;
+ return r;
+}
diff --git a/lib/msun/ld80/e_lgammal_r.c b/lib/msun/ld80/e_lgammal_r.c
new file mode 100644
index 0000000..1e65769
--- /dev/null
+++ b/lib/msun/ld80/e_lgammal_r.c
@@ -0,0 +1,358 @@
+/* @(#)e_lgamma_r.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+/*
+ * See e_lgamma_r.c for complete comments.
+ *
+ * Converted to long double by Steven G. Kargl.
+ */
+
+#ifdef __i386__
+#include <ieeefp.h>
+#endif
+
+#include "fpmath.h"
+#include "math.h"
+#include "math_private.h"
+
+static const volatile double vzero = 0;
+
+static const double
+zero= 0,
+half= 0.5,
+one = 1;
+
+static const union IEEEl2bits
+piu = LD80C(0xc90fdaa22168c235, 1, 3.14159265358979323851e+00L);
+#define pi (piu.e)
+/*
+ * Domain y in [0x1p-70, 0.27], range ~[-4.5264e-22, 4.5264e-22]:
+ * |(lgamma(2 - y) + y / 2) / y - a(y)| < 2**-70.9
+ */
+static const union IEEEl2bits
+a0u = LD80C(0x9e233f1bed863d26, -4, 7.72156649015328606028e-02L),
+a1u = LD80C(0xa51a6625307d3249, -2, 3.22467033424113218889e-01L),
+a2u = LD80C(0x89f000d2abafda8c, -4, 6.73523010531979398946e-02L),
+a3u = LD80C(0xa8991563eca75f26, -6, 2.05808084277991211934e-02L),
+a4u = LD80C(0xf2027e10634ce6b6, -8, 7.38555102796070454026e-03L),
+a5u = LD80C(0xbd6eb76dd22187f4, -9, 2.89051035162703932972e-03L),
+a6u = LD80C(0x9c562ab05e0458ed, -10, 1.19275351624639999297e-03L),
+a7u = LD80C(0x859baed93ee48e46, -11, 5.09674593842117925320e-04L),
+a8u = LD80C(0xe9f28a4432949af2, -13, 2.23109648015769155122e-04L),
+a9u = LD80C(0xd12ad0d9b93c6bb0, -14, 9.97387167479808509830e-05L),
+a10u= LD80C(0xb7522643c78a219b, -15, 4.37071076331030136818e-05L),
+a11u= LD80C(0xca024dcdece2cb79, -16, 2.40813493372040143061e-05L),
+a12u= LD80C(0xbb90fb6968ebdbf9, -19, 2.79495621083634031729e-06L),
+a13u= LD80C(0xba1c9ffeeae07b37, -17, 1.10931287015513924136e-05L);
+#define a0 (a0u.e)
+#define a1 (a1u.e)
+#define a2 (a2u.e)
+#define a3 (a3u.e)
+#define a4 (a4u.e)
+#define a5 (a5u.e)
+#define a6 (a6u.e)
+#define a7 (a7u.e)
+#define a8 (a8u.e)
+#define a9 (a9u.e)
+#define a10 (a10u.e)
+#define a11 (a11u.e)
+#define a12 (a12u.e)
+#define a13 (a13u.e)
+/*
+ * Domain x in [tc-0.24, tc+0.28], range ~[-6.1205e-22, 6.1205e-22]:
+ * |(lgamma(x) - tf) - t(x - tc)| < 2**-70.5
+ */
+static const union IEEEl2bits
+tcu = LD80C(0xbb16c31ab5f1fb71, 0, 1.46163214496836234128e+00L),
+tfu = LD80C(0xf8cdcde61c520e0f, -4, -1.21486290535849608093e-01L),
+ttu = LD80C(0xd46ee54b27d4de99, -69, -2.81152980996018785880e-21L),
+t0u = LD80C(0x80b9406556a62a6b, -68, 3.40728634996055147231e-21L),
+t1u = LD80C(0xc7e9c6f6df3f8c39, -67, -1.05833162742737073665e-20L),
+t2u = LD80C(0xf7b95e4771c55d51, -2, 4.83836122723810583532e-01L),
+t3u = LD80C(0x97213c6e35e119ff, -3, -1.47587722994530691476e-01L),
+t4u = LD80C(0x845a14a6a81dc94b, -4, 6.46249402389135358063e-02L),
+t5u = LD80C(0x864d46fa89997796, -5, -3.27885410884846056084e-02L),
+t6u = LD80C(0x93373cbd00297438, -6, 1.79706751150707171293e-02L),
+t7u = LD80C(0xa8fcfca7eddc8d1d, -7, -1.03142230361450732547e-02L),
+t8u = LD80C(0xc7e7015ff4bc45af, -8, 6.10053603296546099193e-03L),
+t9u = LD80C(0xf178d2247adc5093, -9, -3.68456964904901200152e-03L),
+t10u = LD80C(0x94188d58f12e5e9f, -9, 2.25976420273774583089e-03L),
+t11u = LD80C(0xb7cbaef14e1406f1, -10, -1.40224943666225639823e-03L),
+t12u = LD80C(0xe63a671e6704ea4d, -11, 8.78250640744776944887e-04L),
+t13u = LD80C(0x914b6c9cae61783e, -11, -5.54255012657716808811e-04L),
+t14u = LD80C(0xb858f5bdb79276fe, -12, 3.51614951536825927370e-04L),
+t15u = LD80C(0xea73e744c34b9591, -13, -2.23591563824520112236e-04L),
+t16u = LD80C(0x99aeabb0d67ba835, -13, 1.46562869351659194136e-04L),
+t17u = LD80C(0xd7c6938325db2024, -14, -1.02889866046435680588e-04L),
+t18u = LD80C(0xe24cb1e3b0474775, -15, 5.39540265505221957652e-05L);
+#define tc (tcu.e)
+#define tf (tfu.e)
+#define tt (ttu.e)
+#define t0 (t0u.e)
+#define t1 (t1u.e)
+#define t2 (t2u.e)
+#define t3 (t3u.e)
+#define t4 (t4u.e)
+#define t5 (t5u.e)
+#define t6 (t6u.e)
+#define t7 (t7u.e)
+#define t8 (t8u.e)
+#define t9 (t9u.e)
+#define t10 (t10u.e)
+#define t11 (t11u.e)
+#define t12 (t12u.e)
+#define t13 (t13u.e)
+#define t14 (t14u.e)
+#define t15 (t15u.e)
+#define t16 (t16u.e)
+#define t17 (t17u.e)
+#define t18 (t18u.e)
+/*
+ * Domain y in [-0.1, 0.232], range ~[-8.1938e-22, 8.3815e-22]:
+ * |(lgamma(1 + y) + 0.5 * y) / y - u(y) / v(y)| < 2**-71.2
+ */
+static const union IEEEl2bits
+u0u = LD80C(0x9e233f1bed863d27, -4, -7.72156649015328606095e-02L),
+u1u = LD80C(0x98280ee45e4ddd3d, -1, 5.94361239198682739769e-01L),
+u2u = LD80C(0xe330c8ead4130733, 0, 1.77492629495841234275e+00L),
+u3u = LD80C(0xd4a213f1a002ec52, 0, 1.66119622514818078064e+00L),
+u4u = LD80C(0xa5a9ca6f5bc62163, -1, 6.47122051417476492989e-01L),
+u5u = LD80C(0xc980e49cd5b019e6, -4, 9.83903751718671509455e-02L),
+u6u = LD80C(0xff636a8bdce7025b, -9, 3.89691687802305743450e-03L),
+v1u = LD80C(0xbd109c533a19fbf5, 1, 2.95413883330948556544e+00L),
+v2u = LD80C(0xd295cbf96f31f099, 1, 3.29039286955665403176e+00L),
+v3u = LD80C(0xdab8bcfee40496cb, 0, 1.70876276441416471410e+00L),
+v4u = LD80C(0xd2f2dc3638567e9f, -2, 4.12009126299534668571e-01L),
+v5u = LD80C(0xa07d9b0851070f41, -5, 3.91822868305682491442e-02L),
+v6u = LD80C(0xe3cd8318f7adb2c4, -11, 8.68998648222144351114e-04L);
+#define u0 (u0u.e)
+#define u1 (u1u.e)
+#define u2 (u2u.e)
+#define u3 (u3u.e)
+#define u4 (u4u.e)
+#define u5 (u5u.e)
+#define u6 (u6u.e)
+#define v1 (v1u.e)
+#define v2 (v2u.e)
+#define v3 (v3u.e)
+#define v4 (v4u.e)
+#define v5 (v5u.e)
+#define v6 (v6u.e)
+/*
+ * Domain x in (2, 3], range ~[-3.3648e-22, 3.4416e-22]:
+ * |(lgamma(y+2) - 0.5 * y) / y - s(y)/r(y)| < 2**-72.3
+ * with y = x - 2.
+ */
+static const union IEEEl2bits
+s0u = LD80C(0x9e233f1bed863d27, -4, -7.72156649015328606095e-02L),
+s1u = LD80C(0xd3ff0dcc7fa91f94, -3, 2.07027640921219389860e-01L),
+s2u = LD80C(0xb2bb62782478ef31, -2, 3.49085881391362090549e-01L),
+s3u = LD80C(0xb49f7438c4611a74, -3, 1.76389518704213357954e-01L),
+s4u = LD80C(0x9a957008fa27ecf9, -5, 3.77401710862930008071e-02L),
+s5u = LD80C(0xda9b389a6ca7a7ac, -9, 3.33566791452943399399e-03L),
+s6u = LD80C(0xbc7a2263faf59c14, -14, 8.98728786745638844395e-05L),
+r1u = LD80C(0xbf5cff5b11477d4d, 0, 1.49502555796294337722e+00L),
+r2u = LD80C(0xd9aec89de08e3da6, -1, 8.50323236984473285866e-01L),
+r3u = LD80C(0xeab7ae5057c443f9, -3, 2.29216312078225806131e-01L),
+r4u = LD80C(0xf29707d9bd2b1e37, -6, 2.96130326586640089145e-02L),
+r5u = LD80C(0xd376c2f09736c5a3, -10, 1.61334161411590662495e-03L),
+r6u = LD80C(0xc985983d0cd34e3d, -16, 2.40232770710953450636e-05L),
+r7u = LD80C(0xe5c7a4f7fc2ef13d, -25, -5.34997929289167573510e-08L);
+#define s0 (s0u.e)
+#define s1 (s1u.e)
+#define s2 (s2u.e)
+#define s3 (s3u.e)
+#define s4 (s4u.e)
+#define s5 (s5u.e)
+#define s6 (s6u.e)
+#define r1 (r1u.e)
+#define r2 (r2u.e)
+#define r3 (r3u.e)
+#define r4 (r4u.e)
+#define r5 (r5u.e)
+#define r6 (r6u.e)
+#define r7 (r7u.e)
+/*
+ * Domain z in [8, 0x1p70], range ~[-3.0235e-22, 3.0563e-22]:
+ * |lgamma(x) - (x - 0.5) * (log(x) - 1) - w(1/x)| < 2**-71.7
+ */
+static const union IEEEl2bits
+w0u = LD80C(0xd67f1c864beb4a69, -2, 4.18938533204672741776e-01L),
+w1u = LD80C(0xaaaaaaaaaaaaaaa1, -4, 8.33333333333333332678e-02L),
+w2u = LD80C(0xb60b60b60b5491c9, -9, -2.77777777777760927870e-03L),
+w3u = LD80C(0xd00d00cf58aede4c, -11, 7.93650793490637233668e-04L),
+w4u = LD80C(0x9c09bf626783d4a5, -11, -5.95238023926039051268e-04L),
+w5u = LD80C(0xdca7cadc5baa517b, -11, 8.41733700408000822962e-04L),
+w6u = LD80C(0xfb060e361e1ffd07, -10, -1.91515849570245136604e-03L),
+w7u = LD80C(0xcbd5101bb58d1f2b, -8, 6.22046743903262649294e-03L),
+w8u = LD80C(0xad27a668d32c821b, -6, -2.11370706734662081843e-02L);
+#define w0 (w0u.e)
+#define w1 (w1u.e)
+#define w2 (w2u.e)
+#define w3 (w3u.e)
+#define w4 (w4u.e)
+#define w5 (w5u.e)
+#define w6 (w6u.e)
+#define w7 (w7u.e)
+#define w8 (w8u.e)
+
+static long double
+sin_pil(long double x)
+{
+ volatile long double vz;
+ long double y,z;
+ uint64_t n;
+ uint16_t hx;
+
+ y = -x;
+
+ vz = y+0x1p63;
+ z = vz-0x1p63;
+ if (z == y)
+ return zero;
+
+ vz = y+0x1p61;
+ EXTRACT_LDBL80_WORDS(hx,n,vz);
+ z = vz-0x1p61;
+ if (z > y) {
+ z -= 0.25; /* adjust to round down */
+ n--;
+ }
+ n &= 7; /* octant of y mod 2 */
+ y = y - z + n * 0.25; /* y mod 2 */
+
+ switch (n) {
+ case 0: y = __kernel_sinl(pi*y,zero,0); break;
+ case 1:
+ case 2: y = __kernel_cosl(pi*(0.5-y),zero); break;
+ case 3:
+ case 4: y = __kernel_sinl(pi*(one-y),zero,0); break;
+ case 5:
+ case 6: y = -__kernel_cosl(pi*(y-1.5),zero); break;
+ default: y = __kernel_sinl(pi*(y-2.0),zero,0); break;
+ }
+ return -y;
+}
+
+long double
+lgammal_r(long double x, int *signgamp)
+{
+ long double nadj,p,p1,p2,p3,q,r,t,w,y,z;
+ uint64_t lx;
+ int i;
+ uint16_t hx,ix;
+
+ EXTRACT_LDBL80_WORDS(hx,lx,x);
+
+ /* purge +-Inf and NaNs */
+ *signgamp = 1;
+ ix = hx&0x7fff;
+ if(ix==0x7fff) return x*x;
+
+ ENTERI();
+
+ /* purge +-0 and tiny arguments */
+ *signgamp = 1-2*(hx>>15);
+ if(ix<0x3fff-67) { /* |x|<2**-(p+3), return -log(|x|) */
+ if((ix|lx)==0)
+ RETURNI(one/vzero);
+ RETURNI(-logl(fabsl(x)));
+ }
+
+ /* purge negative integers and start evaluation for other x < 0 */
+ if(hx&0x8000) {
+ *signgamp = 1;
+ if(ix>=0x3fff+63) /* |x|>=2**(p-1), must be -integer */
+ RETURNI(one/vzero);
+ t = sin_pil(x);
+ if(t==zero) RETURNI(one/vzero); /* -integer */
+ nadj = logl(pi/fabsl(t*x));
+ if(t<zero) *signgamp = -1;
+ x = -x;
+ }
+
+ /* purge 1 and 2 */
+ if((ix==0x3fff || ix==0x4000) && lx==0x8000000000000000ULL) r = 0;
+ /* for x < 2.0 */
+ else if(ix<0x4000) {
+ /*
+ * XXX Supposedly, one can use the following information to replace the
+ * XXX FP rational expressions. A similar approach is appropriate
+ * XXX for ld128, but one (may need?) needs to consider llx, too.
+ *
+ * 8.9999961853027344e-01 3ffe e666600000000000
+ * 7.3159980773925781e-01 3ffe bb4a200000000000
+ * 2.3163998126983643e-01 3ffc ed33080000000000
+ * 1.7316312789916992e+00 3fff dda6180000000000
+ * 1.2316322326660156e+00 3fff 9da6200000000000
+ */
+ if(x<8.9999961853027344e-01) {
+ r = -logl(x);
+ if(x>=7.3159980773925781e-01) {y = 1-x; i= 0;}
+ else if(x>=2.3163998126983643e-01) {y= x-(tc-1); i=1;}
+ else {y = x; i=2;}
+ } else {
+ r = 0;
+ if(x>=1.7316312789916992e+00) {y=2-x;i=0;}
+ else if(x>=1.2316322326660156e+00) {y=x-tc;i=1;}
+ else {y=x-1;i=2;}
+ }
+ switch(i) {
+ case 0:
+ z = y*y;
+ p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*(a10+z*a12)))));
+ p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*(a11+z*a13))))));
+ p = y*p1+p2;
+ r += p-y/2; break;
+ case 1:
+ p = t0+y*t1+tt+y*y*(t2+y*(t3+y*(t4+y*(t5+y*(t6+y*(t7+y*(t8+
+ y*(t9+y*(t10+y*(t11+y*(t12+y*(t13+y*(t14+y*(t15+y*(t16+
+ y*(t17+y*t18))))))))))))))));
+ r += tf + p; break;
+ case 2:
+ p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*(u5+y*u6))))));
+ p2 = 1+y*(v1+y*(v2+y*(v3+y*(v4+y*(v5+y*v6)))));
+ r += p1/p2-y/2;
+ }
+ }
+ /* x < 8.0 */
+ else if(ix<0x4002) {
+ i = x;
+ y = x-i;
+ p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
+ q = 1+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*(r6+y*r7))))));
+ r = y/2+p/q;
+ z = 1; /* lgamma(1+s) = log(s) + lgamma(s) */
+ switch(i) {
+ case 7: z *= (y+6); /* FALLTHRU */
+ case 6: z *= (y+5); /* FALLTHRU */
+ case 5: z *= (y+4); /* FALLTHRU */
+ case 4: z *= (y+3); /* FALLTHRU */
+ case 3: z *= (y+2); /* FALLTHRU */
+ r += logl(z); break;
+ }
+ /* 8.0 <= x < 2**(p+3) */
+ } else if (ix<0x3fff+67) {
+ t = logl(x);
+ z = one/x;
+ y = z*z;
+ w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*(w6+y*(w7+y*w8)))))));
+ r = (x-half)*(t-one)+w;
+ /* 2**(p+3) <= x <= inf */
+ } else
+ r = x*(logl(x)-1);
+ if(hx&0x8000) r = nadj - r;
+ RETURNI(r);
+}
diff --git a/lib/msun/man/lgamma.3 b/lib/msun/man/lgamma.3
index ea6eb6f..d244722 100644
--- a/lib/msun/man/lgamma.3
+++ b/lib/msun/man/lgamma.3
@@ -28,7 +28,7 @@
.\" from: @(#)lgamma.3 6.6 (Berkeley) 12/3/92
.\" $FreeBSD$
.\"
-.Dd January 14, 2005
+.Dd September 12, 2014
.Dt LGAMMA 3
.Os
.Sh NAME
@@ -36,6 +36,8 @@
.Nm lgamma_r ,
.Nm lgammaf ,
.Nm lgammaf_r ,
+.Nm lgammal ,
+.Nm lgammal_r ,
.Nm gamma ,
.Nm gamma_r ,
.Nm gammaf ,
@@ -58,6 +60,10 @@
.Fn lgammaf "float x"
.Ft float
.Fn lgammaf_r "float x" "int *signgamp"
+.Ft "long double"
+.Fn lgammal "long double x"
+.Ft "long double"
+.Fn lgammal_r "long double x" "int *signgamp"
.Ft double
.Fn gamma "double x"
.Ft double
@@ -66,14 +72,15 @@
.Fn gammaf "float x"
.Ft float
.Fn gammaf_r "float x" "int *signgamp"
-.Ft double
+.Ft "long double"
.Fn tgamma "double x"
.Ft float
.Fn tgammaf "float x"
.Sh DESCRIPTION
-.Fn lgamma x
+.Fn lgamma x ,
+.Fn lgammaf x ,
and
-.Fn lgammaf x
+.Fn lgammal x
.if t \{\
return ln\||\(*G(x)| where
.Bd -unfilled -offset indent
@@ -87,13 +94,15 @@ The external integer
.Fa signgam
returns the sign of \(*G(x).
.Pp
-.Fn lgamma_r x signgamp
+.Fn lgamma_r x signgamp ,
+.Fn lgammaf_r x signgamp ,
and
-.Fn lgammaf_r x signgamp
+.Fn lgammal_r x signgamp
provide the same functionality as
-.Fn lgamma x
+.Fn lgamma x ,
+.Fn lgammaf x ,
and
-.Fn lgammaf x
+.Fn lgammal x ,
but the caller must provide an integer to store the sign of \(*G(x).
.Pp
The
@@ -115,6 +124,7 @@ are deprecated aliases for
and
.Fn lgammaf_r ,
respectively.
+
.Sh IDIOSYNCRASIES
Do not use the expression
.Dq Li signgam\(**exp(lgamma(x))
@@ -139,14 +149,18 @@ Exponentiation of
will lose up to 10 significant bits.
.Sh RETURN VALUES
.Fn gamma ,
-.Fn gamma_r ,
.Fn gammaf ,
+.Fn gammal ,
+.Fn gamma_r ,
.Fn gammaf_r ,
+.Fn gammal_r ,
.Fn lgamma ,
-.Fn lgamma_r ,
.Fn lgammaf ,
+.Fn lgammal ,
+.Fn lgamma_r ,
+.Fn lgammaf_r ,
and
-.Fn lgammaf_r
+.Fn lgammal_r
return appropriate values unless an argument is out of range.
Overflow will occur for sufficiently large positive values, and
non-positive integers.
@@ -159,6 +173,7 @@ will underflow.
The
.Fn lgamma ,
.Fn lgammaf ,
+.Fn lgammal ,
.Fn tgamma ,
and
.Fn tgammaf
diff --git a/lib/msun/src/e_lgamma.c b/lib/msun/src/e_lgamma.c
index 4674d9b..43f5175 100644
--- a/lib/msun/src/e_lgamma.c
+++ b/lib/msun/src/e_lgamma.c
@@ -21,6 +21,8 @@ __FBSDID("$FreeBSD$");
* Method: call __ieee754_lgamma_r
*/
+#include <float.h>
+
#include "math.h"
#include "math_private.h"
@@ -31,3 +33,7 @@ __ieee754_lgamma(double x)
{
return __ieee754_lgamma_r(x,&signgam);
}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(lgamma, lgammal);
+#endif
diff --git a/lib/msun/src/e_lgamma_r.c b/lib/msun/src/e_lgamma_r.c
index 1cff592..be70767 100644
--- a/lib/msun/src/e_lgamma_r.c
+++ b/lib/msun/src/e_lgamma_r.c
@@ -1,4 +1,3 @@
-
/* @(#)e_lgamma_r.c 1.3 95/01/18 */
/*
* ====================================================
@@ -6,22 +5,21 @@
*
* Developed at SunSoft, a Sun Microsystems, Inc. business.
* Permission to use, copy, modify, and distribute this
- * software is freely granted, provided that this notice
+ * software is freely granted, provided that this notice
* is preserved.
* ====================================================
- *
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
/* __ieee754_lgamma_r(x, signgamp)
- * Reentrant version of the logarithm of the Gamma function
- * with user provide pointer for the sign of Gamma(x).
+ * Reentrant version of the logarithm of the Gamma function
+ * with user provide pointer for the sign of Gamma(x).
*
* Method:
* 1. Argument Reduction for 0 < x <= 8
- * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
+ * Since gamma(1+s)=s*gamma(s), for x in [0,8], we may
* reduce x to a number in [1.5,2.5] by
* lgamma(1+s) = log(s) + lgamma(s)
* for example,
@@ -59,20 +57,20 @@ __FBSDID("$FreeBSD$");
* by
* 3 5 11
* w = w0 + w1*z + w2*z + w3*z + ... + w6*z
- * where
+ * where
* |w - f(z)| < 2**-58.74
- *
+ *
* 4. For negative x, since (G is gamma function)
* -x*G(-x)*G(x) = pi/sin(pi*x),
* we have
* G(x) = pi/(sin(pi*x)*(-x)*G(-x))
* since G(-x) is positive, sign(G(x)) = sign(sin(pi*x)) for x<0
- * Hence, for x<0, signgam = sign(sin(pi*x)) and
+ * Hence, for x<0, signgam = sign(sin(pi*x)) and
* lgamma(x) = log(|Gamma(x)|)
* = log(pi/(|x*sin(pi*x)|)) - lgamma(-x);
- * Note: one should avoid compute pi*(-x) directly in the
+ * Note: one should avoid compute pi*(-x) directly in the
* computation of sin(pi*(-x)).
- *
+ *
* 5. Special Cases
* lgamma(2+s) ~ s*(1-Euler) for tiny s
* lgamma(1) = lgamma(2) = 0
@@ -80,14 +78,17 @@ __FBSDID("$FreeBSD$");
* lgamma(0) = lgamma(neg.integer) = inf and raise divide-by-zero
* lgamma(inf) = inf
* lgamma(-inf) = inf (bug for bug compatible with C99!?)
- *
*/
+#include <float.h>
+
#include "math.h"
#include "math_private.h"
+static const volatile double vzero = 0;
+
static const double
-two52= 4.50359962737049600000e+15, /* 0x43300000, 0x00000000 */
+zero= 0.00000000000000000000e+00,
half= 5.00000000000000000000e-01, /* 0x3FE00000, 0x00000000 */
one = 1.00000000000000000000e+00, /* 0x3FF00000, 0x00000000 */
pi = 3.14159265358979311600e+00, /* 0x400921FB, 0x54442D18 */
@@ -154,44 +155,40 @@ w4 = -5.95187557450339963135e-04, /* 0xBF4380CB, 0x8C0FE741 */
w5 = 8.36339918996282139126e-04, /* 0x3F4B67BA, 0x4CDAD5D1 */
w6 = -1.63092934096575273989e-03; /* 0xBF5AB89D, 0x0B9E43E4 */
-static const double zero= 0.00000000000000000000e+00;
-
- static double sin_pi(double x)
+/*
+ * Compute sin(pi*x) without actually doing the pi*x multiplication.
+ * sin_pi(x) is only called for x < 0 and |x| < 2**(p-1) where p is
+ * the precision of x.
+ */
+static double
+sin_pi(double x)
{
+ volatile double vz;
double y,z;
- int n,ix;
+ int n;
- GET_HIGH_WORD(ix,x);
- ix &= 0x7fffffff;
+ y = -x;
- if(ix<0x3fd00000) return __kernel_sin(pi*x,zero,0);
- y = -x; /* x is assume negative */
+ vz = y+0x1p52; /* depend on 0 <= y < 0x1p52 */
+ z = vz-0x1p52; /* rint(y) for the above range */
+ if (z == y)
+ return zero;
+
+ vz = y+0x1p50;
+ GET_LOW_WORD(n,vz); /* bits for rounded y (units 0.25) */
+ z = vz-0x1p50; /* y rounded to a multiple of 0.25 */
+ if (z > y) {
+ z -= 0.25; /* adjust to round down */
+ n--;
+ }
+ n &= 7; /* octant of y mod 2 */
+ y = y - z + n * 0.25; /* y mod 2 */
- /*
- * argument reduction, make sure inexact flag not raised if input
- * is an integer
- */
- z = floor(y);
- if(z!=y) { /* inexact anyway */
- y *= 0.5;
- y = 2.0*(y - floor(y)); /* y = |x| mod 2.0 */
- n = (int) (y*4.0);
- } else {
- if(ix>=0x43400000) {
- y = zero; n = 0; /* y must be even */
- } else {
- if(ix<0x43300000) z = y+two52; /* exact */
- GET_LOW_WORD(n,z);
- n &= 1;
- y = n;
- n<<= 2;
- }
- }
switch (n) {
case 0: y = __kernel_sin(pi*y,zero,0); break;
- case 1:
+ case 1:
case 2: y = __kernel_cos(pi*(0.5-y),zero); break;
- case 3:
+ case 3:
case 4: y = __kernel_sin(pi*(one-y),zero,0); break;
case 5:
case 6: y = -__kernel_cos(pi*(y-1.5),zero); break;
@@ -204,34 +201,38 @@ static const double zero= 0.00000000000000000000e+00;
double
__ieee754_lgamma_r(double x, int *signgamp)
{
- double t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ double nadj,p,p1,p2,p3,q,r,t,w,y,z;
int32_t hx;
- int i,lx,ix;
+ int i,ix,lx;
EXTRACT_WORDS(hx,lx,x);
- /* purge off +-inf, NaN, +-0, tiny and negative arguments */
+ /* purge +-Inf and NaNs */
*signgamp = 1;
ix = hx&0x7fffffff;
if(ix>=0x7ff00000) return x*x;
- if((ix|lx)==0) return one/zero;
- if(ix<0x3b900000) { /* |x|<2**-70, return -log(|x|) */
- if(hx<0) {
- *signgamp = -1;
- return -__ieee754_log(-x);
- } else return -__ieee754_log(x);
+
+ /* purge +-0 and tiny arguments */
+ *signgamp = 1-2*((uint32_t)hx>>31);
+ if(ix<0x3c700000) { /* |x|<2**-56, return -log(|x|) */
+ if((ix|lx)==0)
+ return one/vzero;
+ return -__ieee754_log(fabs(x));
}
+
+ /* purge negative integers and start evaluation for other x < 0 */
if(hx<0) {
+ *signgamp = 1;
if(ix>=0x43300000) /* |x|>=2**52, must be -integer */
- return one/zero;
+ return one/vzero;
t = sin_pi(x);
- if(t==zero) return one/zero; /* -integer */
+ if(t==zero) return one/vzero; /* -integer */
nadj = __ieee754_log(pi/fabs(t*x));
if(t<zero) *signgamp = -1;
x = -x;
}
- /* purge off 1 and 2 */
+ /* purge 1 and 2 */
if((((ix-0x3ff00000)|lx)==0)||(((ix-0x40000000)|lx)==0)) r = 0;
/* for x < 2.0 */
else if(ix<0x40000000) {
@@ -252,7 +253,7 @@ __ieee754_lgamma_r(double x, int *signgamp)
p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
p = y*p1+p2;
- r += (p-0.5*y); break;
+ r += p-y/2; break;
case 1:
z = y*y;
w = z*y;
@@ -260,38 +261,43 @@ __ieee754_lgamma_r(double x, int *signgamp)
p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
p = z*p1-(tt-w*(p2+y*p3));
- r += (tf + p); break;
- case 2:
+ r += tf + p; break;
+ case 2:
p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
- r += (-0.5*y + p1/p2);
+ r += p1/p2-y/2;
}
}
- else if(ix<0x40200000) { /* x < 8.0 */
- i = (int)x;
- y = x-(double)i;
+ /* x < 8.0 */
+ else if(ix<0x40200000) {
+ i = x;
+ y = x-i;
p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
- r = half*y+p/q;
+ r = y/2+p/q;
z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
switch(i) {
- case 7: z *= (y+6.0); /* FALLTHRU */
- case 6: z *= (y+5.0); /* FALLTHRU */
- case 5: z *= (y+4.0); /* FALLTHRU */
- case 4: z *= (y+3.0); /* FALLTHRU */
- case 3: z *= (y+2.0); /* FALLTHRU */
+ case 7: z *= (y+6); /* FALLTHRU */
+ case 6: z *= (y+5); /* FALLTHRU */
+ case 5: z *= (y+4); /* FALLTHRU */
+ case 4: z *= (y+3); /* FALLTHRU */
+ case 3: z *= (y+2); /* FALLTHRU */
r += __ieee754_log(z); break;
}
- /* 8.0 <= x < 2**58 */
- } else if (ix < 0x43900000) {
+ /* 8.0 <= x < 2**56 */
+ } else if (ix < 0x43700000) {
t = __ieee754_log(x);
z = one/x;
y = z*z;
w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
r = (x-half)*(t-one)+w;
- } else
- /* 2**58 <= x <= inf */
+ } else
+ /* 2**56 <= x <= inf */
r = x*(__ieee754_log(x)-one);
if(hx<0) r = nadj - r;
return r;
}
+
+#if (LDBL_MANT_DIG == 53)
+__weak_reference(lgamma_r, lgammal_r);
+#endif
diff --git a/lib/msun/src/e_lgammaf_r.c b/lib/msun/src/e_lgammaf_r.c
index e2d90ef..9084e18 100644
--- a/lib/msun/src/e_lgammaf_r.c
+++ b/lib/msun/src/e_lgammaf_r.c
@@ -1,5 +1,6 @@
/* e_lgammaf_r.c -- float version of e_lgamma_r.c.
* Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com.
+ * Conversion to float fixed By Steven G. Kargl.
*/
/*
@@ -19,107 +20,91 @@ __FBSDID("$FreeBSD$");
#include "math.h"
#include "math_private.h"
+static const volatile float vzero = 0;
+
static const float
-two23= 8.3886080000e+06, /* 0x4b000000 */
-half= 5.0000000000e-01, /* 0x3f000000 */
-one = 1.0000000000e+00, /* 0x3f800000 */
+zero= 0,
+half= 0.5,
+one = 1,
pi = 3.1415927410e+00, /* 0x40490fdb */
-a0 = 7.7215664089e-02, /* 0x3d9e233f */
-a1 = 3.2246702909e-01, /* 0x3ea51a66 */
-a2 = 6.7352302372e-02, /* 0x3d89f001 */
-a3 = 2.0580807701e-02, /* 0x3ca89915 */
-a4 = 7.3855509982e-03, /* 0x3bf2027e */
-a5 = 2.8905137442e-03, /* 0x3b3d6ec6 */
-a6 = 1.1927076848e-03, /* 0x3a9c54a1 */
-a7 = 5.1006977446e-04, /* 0x3a05b634 */
-a8 = 2.2086278477e-04, /* 0x39679767 */
-a9 = 1.0801156895e-04, /* 0x38e28445 */
-a10 = 2.5214456400e-05, /* 0x37d383a2 */
-a11 = 4.4864096708e-05, /* 0x383c2c75 */
-tc = 1.4616321325e+00, /* 0x3fbb16c3 */
-tf = -1.2148628384e-01, /* 0xbdf8cdcd */
-/* tt = -(tail of tf) */
-tt = 6.6971006518e-09, /* 0x31e61c52 */
-t0 = 4.8383611441e-01, /* 0x3ef7b95e */
-t1 = -1.4758771658e-01, /* 0xbe17213c */
-t2 = 6.4624942839e-02, /* 0x3d845a15 */
-t3 = -3.2788541168e-02, /* 0xbd064d47 */
-t4 = 1.7970675603e-02, /* 0x3c93373d */
-t5 = -1.0314224288e-02, /* 0xbc28fcfe */
-t6 = 6.1005386524e-03, /* 0x3bc7e707 */
-t7 = -3.6845202558e-03, /* 0xbb7177fe */
-t8 = 2.2596477065e-03, /* 0x3b141699 */
-t9 = -1.4034647029e-03, /* 0xbab7f476 */
-t10 = 8.8108185446e-04, /* 0x3a66f867 */
-t11 = -5.3859531181e-04, /* 0xba0d3085 */
-t12 = 3.1563205994e-04, /* 0x39a57b6b */
-t13 = -3.1275415677e-04, /* 0xb9a3f927 */
-t14 = 3.3552918467e-04, /* 0x39afe9f7 */
-u0 = -7.7215664089e-02, /* 0xbd9e233f */
-u1 = 6.3282704353e-01, /* 0x3f2200f4 */
-u2 = 1.4549225569e+00, /* 0x3fba3ae7 */
-u3 = 9.7771751881e-01, /* 0x3f7a4bb2 */
-u4 = 2.2896373272e-01, /* 0x3e6a7578 */
-u5 = 1.3381091878e-02, /* 0x3c5b3c5e */
-v1 = 2.4559779167e+00, /* 0x401d2ebe */
-v2 = 2.1284897327e+00, /* 0x4008392d */
-v3 = 7.6928514242e-01, /* 0x3f44efdf */
-v4 = 1.0422264785e-01, /* 0x3dd572af */
-v5 = 3.2170924824e-03, /* 0x3b52d5db */
-s0 = -7.7215664089e-02, /* 0xbd9e233f */
-s1 = 2.1498242021e-01, /* 0x3e5c245a */
-s2 = 3.2577878237e-01, /* 0x3ea6cc7a */
-s3 = 1.4635047317e-01, /* 0x3e15dce6 */
-s4 = 2.6642270386e-02, /* 0x3cda40e4 */
-s5 = 1.8402845599e-03, /* 0x3af135b4 */
-s6 = 3.1947532989e-05, /* 0x3805ff67 */
-r1 = 1.3920053244e+00, /* 0x3fb22d3b */
-r2 = 7.2193557024e-01, /* 0x3f38d0c5 */
-r3 = 1.7193385959e-01, /* 0x3e300f6e */
-r4 = 1.8645919859e-02, /* 0x3c98bf54 */
-r5 = 7.7794247773e-04, /* 0x3a4beed6 */
-r6 = 7.3266842264e-06, /* 0x36f5d7bd */
-w0 = 4.1893854737e-01, /* 0x3ed67f1d */
-w1 = 8.3333335817e-02, /* 0x3daaaaab */
-w2 = -2.7777778450e-03, /* 0xbb360b61 */
-w3 = 7.9365057172e-04, /* 0x3a500cfd */
-w4 = -5.9518753551e-04, /* 0xba1c065c */
-w5 = 8.3633989561e-04, /* 0x3a5b3dd2 */
-w6 = -1.6309292987e-03; /* 0xbad5c4e8 */
-
-static const float zero= 0.0000000000e+00;
-
- static float sin_pif(float x)
+/*
+ * Domain y in [0x1p-27, 0.27], range ~[-3.4599e-10, 3.4590e-10]:
+ * |(lgamma(2 - y) + 0.5 * y) / y - a(y)| < 2**-31.4
+ */
+a0 = 7.72156641e-02, /* 0x3d9e233f */
+a1 = 3.22467119e-01, /* 0x3ea51a69 */
+a2 = 6.73484802e-02, /* 0x3d89ee00 */
+a3 = 2.06395667e-02, /* 0x3ca9144f */
+a4 = 6.98275631e-03, /* 0x3be4cf9b */
+a5 = 4.11768444e-03, /* 0x3b86eda4 */
+/*
+ * Domain x in [tc-0.24, tc+0.28], range ~[-5.6577e-10, 5.5677e-10]:
+ * |(lgamma(x) - tf) - t(x - tc)| < 2**-30.8.
+ */
+tc = 1.46163213e+00, /* 0x3fbb16c3 */
+tf = -1.21486291e-01, /* 0xbdf8cdce */
+t0 = -2.94064460e-11, /* 0xae0154b7 */
+t1 = -2.35939837e-08, /* 0xb2caabb8 */
+t2 = 4.83836412e-01, /* 0x3ef7b968 */
+t3 = -1.47586212e-01, /* 0xbe1720d7 */
+t4 = 6.46013096e-02, /* 0x3d844db1 */
+t5 = -3.28450352e-02, /* 0xbd068884 */
+t6 = 1.86483748e-02, /* 0x3c98c47a */
+t7 = -9.89206228e-03, /* 0xbc221251 */
+/*
+ * Domain y in [-0.1, 0.232], range ~[-8.4931e-10, 8.7794e-10]:
+ * |(lgamma(1 + y) + 0.5 * y) / y - u(y) / v(y)| < 2**-31.2
+ */
+u0 = -7.72156641e-02, /* 0xbd9e233f */
+u1 = 7.36789703e-01, /* 0x3f3c9e40 */
+u2 = 4.95649040e-01, /* 0x3efdc5b6 */
+v1 = 1.10958421e+00, /* 0x3f8e06db */
+v2 = 2.10598111e-01, /* 0x3e57a708 */
+v3 = -1.02995494e-02, /* 0xbc28bf71 */
+/*
+ * Domain x in (2, 3], range ~[-5.5189e-11, 5.2317e-11]:
+ * |(lgamma(y+2) - 0.5 * y) / y - s(y)/r(y)| < 2**-35.0
+ * with y = x - 2.
+ */
+s0 = -7.72156641e-02, /* 0xbd9e233f */
+s1 = 2.69987404e-01, /* 0x3e8a3bca */
+s2 = 1.42851010e-01, /* 0x3e124789 */
+s3 = 1.19389519e-02, /* 0x3c439b98 */
+r1 = 6.79650068e-01, /* 0x3f2dfd8c */
+r2 = 1.16058730e-01, /* 0x3dedb033 */
+r3 = 3.75673687e-03, /* 0x3b763396 */
+/*
+ * Domain z in [8, 0x1p24], range ~[-1.2640e-09, 1.2640e-09]:
+ * |lgamma(x) - (x - 0.5) * (log(x) - 1) - w(1/x)| < 2**-29.6.
+ */
+w0 = 4.18938547e-01, /* 0x3ed67f1d */
+w1 = 8.33332464e-02, /* 0x3daaaa9f */
+w2 = -2.76129087e-03; /* 0xbb34f6c6 */
+
+static float
+sin_pif(float x)
{
+ volatile float vz;
float y,z;
- int n,ix;
-
- GET_FLOAT_WORD(ix,x);
- ix &= 0x7fffffff;
-
- if(ix<0x3e800000) return __kernel_sindf(pi*x);
- y = -x; /* x is assume negative */
-
- /*
- * argument reduction, make sure inexact flag not raised if input
- * is an integer
- */
- z = floorf(y);
- if(z!=y) { /* inexact anyway */
- y *= (float)0.5;
- y = (float)2.0*(y - floorf(y)); /* y = |x| mod 2.0 */
- n = (int) (y*(float)4.0);
- } else {
- if(ix>=0x4b800000) {
- y = zero; n = 0; /* y must be even */
- } else {
- if(ix<0x4b000000) z = y+two23; /* exact */
- GET_FLOAT_WORD(n,z);
- n &= 1;
- y = n;
- n<<= 2;
- }
- }
+ int n;
+
+ y = -x;
+
+ vz = y+0x1p23F; /* depend on 0 <= y < 0x1p23 */
+ z = vz-0x1p23F; /* rintf(y) for the above range */
+ if (z == y)
+ return zero;
+
+ vz = y+0x1p21F;
+ GET_FLOAT_WORD(n,vz); /* bits for rounded y (units 0.25) */
+ z = vz-0x1p21F; /* y rounded to a multiple of 0.25 */
+ if (z > y) {
+ z -= 0.25F; /* adjust to round down */
+ n--;
+ }
+ n &= 7; /* octant of y mod 2 */
+ y = y - z + n * 0.25F; /* y mod 2 */
+
switch (n) {
case 0: y = __kernel_sindf(pi*y); break;
case 1:
@@ -137,34 +122,38 @@ static const float zero= 0.0000000000e+00;
float
__ieee754_lgammaf_r(float x, int *signgamp)
{
- float t,y,z,nadj,p,p1,p2,p3,q,r,w;
+ float nadj,p,p1,p2,p3,q,r,t,w,y,z;
int32_t hx;
int i,ix;
GET_FLOAT_WORD(hx,x);
- /* purge off +-inf, NaN, +-0, tiny and negative arguments */
+ /* purge +-Inf and NaNs */
*signgamp = 1;
ix = hx&0x7fffffff;
if(ix>=0x7f800000) return x*x;
- if(ix==0) return one/zero;
- if(ix<0x35000000) { /* |x|<2**-21, return -log(|x|) */
- if(hx<0) {
- *signgamp = -1;
- return -__ieee754_logf(-x);
- } else return -__ieee754_logf(x);
+
+ /* purge +-0 and tiny arguments */
+ *signgamp = 1-2*((uint32_t)hx>>31);
+ if(ix<0x32000000) { /* |x|<2**-27, return -log(|x|) */
+ if(ix==0)
+ return one/vzero;
+ return -__ieee754_logf(fabsf(x));
}
+
+ /* purge negative integers and start evaluation for other x < 0 */
if(hx<0) {
- if(ix>=0x4b000000) /* |x|>=2**23, must be -integer */
- return one/zero;
+ *signgamp = 1;
+ if(ix>=0x4b000000) /* |x|>=2**23, must be -integer */
+ return one/vzero;
t = sin_pif(x);
- if(t==zero) return one/zero; /* -integer */
+ if(t==zero) return one/vzero; /* -integer */
nadj = __ieee754_logf(pi/fabsf(t*x));
if(t<zero) *signgamp = -1;
x = -x;
}
- /* purge off 1 and 2 */
+ /* purge 1 and 2 */
if (ix==0x3f800000||ix==0x40000000) r = 0;
/* for x < 2.0 */
else if(ix<0x40000000) {
@@ -175,55 +164,51 @@ __ieee754_lgammaf_r(float x, int *signgamp)
else {y = x; i=2;}
} else {
r = zero;
- if(ix>=0x3fdda618) {y=(float)2.0-x;i=0;} /* [1.7316,2] */
+ if(ix>=0x3fdda618) {y=2-x;i=0;} /* [1.7316,2] */
else if(ix>=0x3F9da620) {y=x-tc;i=1;} /* [1.23,1.73] */
else {y=x-one;i=2;}
}
switch(i) {
case 0:
z = y*y;
- p1 = a0+z*(a2+z*(a4+z*(a6+z*(a8+z*a10))));
- p2 = z*(a1+z*(a3+z*(a5+z*(a7+z*(a9+z*a11)))));
+ p1 = a0+z*(a2+z*a4);
+ p2 = z*(a1+z*(a3+z*a5));
p = y*p1+p2;
- r += (p-(float)0.5*y); break;
+ r += p-y/2; break;
case 1:
- z = y*y;
- w = z*y;
- p1 = t0+w*(t3+w*(t6+w*(t9 +w*t12))); /* parallel comp */
- p2 = t1+w*(t4+w*(t7+w*(t10+w*t13)));
- p3 = t2+w*(t5+w*(t8+w*(t11+w*t14)));
- p = z*p1-(tt-w*(p2+y*p3));
- r += (tf + p); break;
+ p = t0+y*t1+y*y*(t2+y*(t3+y*(t4+y*(t5+y*(t6+y*t7)))));
+ r += tf + p; break;
case 2:
- p1 = y*(u0+y*(u1+y*(u2+y*(u3+y*(u4+y*u5)))));
- p2 = one+y*(v1+y*(v2+y*(v3+y*(v4+y*v5))));
- r += (-(float)0.5*y + p1/p2);
+ p1 = y*(u0+y*(u1+y*u2));
+ p2 = one+y*(v1+y*(v2+y*v3));
+ r += p1/p2-y/2;
}
}
- else if(ix<0x41000000) { /* x < 8.0 */
- i = (int)x;
- y = x-(float)i;
- p = y*(s0+y*(s1+y*(s2+y*(s3+y*(s4+y*(s5+y*s6))))));
- q = one+y*(r1+y*(r2+y*(r3+y*(r4+y*(r5+y*r6)))));
- r = half*y+p/q;
+ /* x < 8.0 */
+ else if(ix<0x41000000) {
+ i = x;
+ y = x-i;
+ p = y*(s0+y*(s1+y*(s2+y*s3)));
+ q = one+y*(r1+y*(r2+y*r3));
+ r = y/2+p/q;
z = one; /* lgamma(1+s) = log(s) + lgamma(s) */
switch(i) {
- case 7: z *= (y+(float)6.0); /* FALLTHRU */
- case 6: z *= (y+(float)5.0); /* FALLTHRU */
- case 5: z *= (y+(float)4.0); /* FALLTHRU */
- case 4: z *= (y+(float)3.0); /* FALLTHRU */
- case 3: z *= (y+(float)2.0); /* FALLTHRU */
+ case 7: z *= (y+6); /* FALLTHRU */
+ case 6: z *= (y+5); /* FALLTHRU */
+ case 5: z *= (y+4); /* FALLTHRU */
+ case 4: z *= (y+3); /* FALLTHRU */
+ case 3: z *= (y+2); /* FALLTHRU */
r += __ieee754_logf(z); break;
}
- /* 8.0 <= x < 2**58 */
- } else if (ix < 0x5c800000) {
+ /* 8.0 <= x < 2**27 */
+ } else if (ix < 0x4d000000) {
t = __ieee754_logf(x);
z = one/x;
y = z*z;
- w = w0+z*(w1+y*(w2+y*(w3+y*(w4+y*(w5+y*w6)))));
+ w = w0+z*(w1+y*w2);
r = (x-half)*(t-one)+w;
} else
- /* 2**58 <= x <= inf */
+ /* 2**27 <= x <= inf */
r = x*(__ieee754_logf(x)-one);
if(hx<0) r = nadj - r;
return r;
diff --git a/lib/msun/src/e_lgammal.c b/lib/msun/src/e_lgammal.c
new file mode 100644
index 0000000..ebc2fc7
--- /dev/null
+++ b/lib/msun/src/e_lgammal.c
@@ -0,0 +1,25 @@
+/* @(#)e_lgamma.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice
+ * is preserved.
+ * ====================================================
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "math.h"
+#include "math_private.h"
+
+extern int signgam;
+
+long double
+lgammal(long double x)
+{
+ return lgammal_r(x,&signgam);
+}
diff --git a/lib/msun/src/imprecise.c b/lib/msun/src/imprecise.c
index 92fb2d0..08cd239 100644
--- a/lib/msun/src/imprecise.c
+++ b/lib/msun/src/imprecise.c
@@ -60,5 +60,4 @@ DECLARE_WEAK(powl);
long double imprecise_ ## f ## l(long double v) { return f(v); }\
DECLARE_WEAK(f ## l)
-DECLARE_IMPRECISE(lgamma);
DECLARE_IMPRECISE(tgamma);
diff --git a/lib/msun/src/math.h b/lib/msun/src/math.h
index 32d01da..2ff1731 100644
--- a/lib/msun/src/math.h
+++ b/lib/msun/src/math.h
@@ -465,6 +465,7 @@ long double frexpl(long double value, int *); /* fundamentally !__pure2 */
long double hypotl(long double, long double);
int ilogbl(long double) __pure2;
long double ldexpl(long double, int);
+long double lgammal(long double);
long long llrintl(long double);
long long llroundl(long double);
long double log10l(long double);
@@ -481,6 +482,7 @@ long double nextafterl(long double, long double);
double nexttoward(double, long double);
float nexttowardf(float, long double);
long double nexttowardl(long double, long double);
+long double powl(long double, long double);
long double remainderl(long double, long double);
long double remquol(long double, long double, int *);
long double rintl(long double);
@@ -492,31 +494,14 @@ long double sinl(long double);
long double sqrtl(long double);
long double tanhl(long double);
long double tanl(long double);
+long double tgammal(long double);
long double truncl(long double);
-
#endif /* __ISO_C_VISIBLE >= 1999 */
-__END_DECLS
-#endif /* !_MATH_H_ */
-
-/* separate header for cmath */
-#ifndef _MATH_EXTRA_H_
-#if __ISO_C_VISIBLE >= 1999
-#if _DECLARE_C99_LDBL_MATH
-
-#define _MATH_EXTRA_H_
-
-/*
- * extra long double versions of math functions for C99 and cmath
- */
-__BEGIN_DECLS
-
-long double lgammal(long double);
-long double powl(long double, long double);
-long double tgammal(long double);
+#if __BSD_VISIBLE
+long double lgammal_r(long double, int *);
+#endif
__END_DECLS
-#endif /* !_DECLARE_C99_LDBL_MATH */
-#endif /* __ISO_C_VISIBLE >= 1999 */
-#endif /* !_MATH_EXTRA_H_ */
+#endif /* !_MATH_H_ */
diff --git a/lib/msun/src/s_tanh.c b/lib/msun/src/s_tanh.c
index f7b71c5..6d26c69 100644
--- a/lib/msun/src/s_tanh.c
+++ b/lib/msun/src/s_tanh.c
@@ -42,7 +42,8 @@ __FBSDID("$FreeBSD$");
#include "math.h"
#include "math_private.h"
-static const double one = 1.0, two = 2.0, tiny = 1.0e-300, huge = 1.0e300;
+static const volatile double tiny = 1.0e-300;
+static const double one = 1.0, two = 2.0, huge = 1.0e300;
double
tanh(double x)
diff --git a/lib/msun/src/s_tanhf.c b/lib/msun/src/s_tanhf.c
index 04f09c6..f537be4 100644
--- a/lib/msun/src/s_tanhf.c
+++ b/lib/msun/src/s_tanhf.c
@@ -19,7 +19,9 @@ __FBSDID("$FreeBSD$");
#include "math.h"
#include "math_private.h"
-static const float one=1.0, two=2.0, tiny = 1.0e-30, huge = 1.0e30;
+static const volatile float tiny = 1.0e-30;
+static const float one=1.0, two=2.0, huge = 1.0e30;
+
float
tanhf(float x)
{
diff --git a/lib/msun/tests/Makefile b/lib/msun/tests/Makefile
new file mode 100644
index 0000000..4261e48
--- /dev/null
+++ b/lib/msun/tests/Makefile
@@ -0,0 +1,63 @@
+# $FreeBSD$
+
+OBJTOP= ${.OBJDIR:H:H:H}
+SRCTOP= ${.CURDIR:H:H:H}
+TESTSRC= ${SRCTOP}/contrib/netbsd-tests/lib/libm
+
+TESTSDIR= ${TESTSBASE}/lib/msun
+
+.if ${MACHINE} == "sparc" || ${MACHINE} == "i386" \
+ || ${MACHINE} == "amd64" || ${MACHINE_CPU} == "arm" \
+ || ${MACHINE} == "sparc64"
+CFLAGS+= -DHAVE_FENV_H
+.endif
+
+.if ${MACHINE} == "amd64" || ${MACHINE} == "i386"
+CFLAGS+= -D__HAVE_LONG_DOUBLE
+.endif
+
+NETBSD_ATF_TESTS_C= acos_test
+NETBSD_ATF_TESTS_C+= asin_test
+NETBSD_ATF_TESTS_C+= atan_test
+NETBSD_ATF_TESTS_C+= cbrt_test
+NETBSD_ATF_TESTS_C+= ceil_test
+NETBSD_ATF_TESTS_C+= cos_test
+NETBSD_ATF_TESTS_C+= cosh_test
+NETBSD_ATF_TESTS_C+= erf_test
+NETBSD_ATF_TESTS_C+= exp_test
+NETBSD_ATF_TESTS_C+= fmod_test
+NETBSD_ATF_TESTS_C+= infinity_test
+NETBSD_ATF_TESTS_C+= ldexp_test
+NETBSD_ATF_TESTS_C+= log_test
+NETBSD_ATF_TESTS_C+= pow_test
+NETBSD_ATF_TESTS_C+= precision_test
+NETBSD_ATF_TESTS_C+= round_test
+NETBSD_ATF_TESTS_C+= scalbn_test
+NETBSD_ATF_TESTS_C+= sin_test
+NETBSD_ATF_TESTS_C+= sinh_test
+NETBSD_ATF_TESTS_C+= sqrt_test
+NETBSD_ATF_TESTS_C+= tan_test
+NETBSD_ATF_TESTS_C+= tanh_test
+
+CSTD= c99
+
+LDADD+= -lm
+DPADD+= ${LIBM}
+#COPTS+= -Wfloat-equal
+
+# Copied from lib/msun/Makefile
+.if ${MACHINE_CPUARCH} == "i386"
+ARCH_SUBDIR= i387
+.else
+ARCH_SUBDIR= ${MACHINE_CPUARCH}
+.endif
+
+.include "../${ARCH_SUBDIR}/Makefile.inc"
+
+# XXX: for some odd reason float.h doesn't tell the full story about what the
+# precision is.
+CFLAGS+= -DLDBL_PREC=${LDBL_PREC}
+
+.include <netbsd-tests.test.mk>
+
+.include <bsd.test.mk>
OpenPOWER on IntegriCloud